- XML parser framework rewrite
[mir.git] / source / mir / util / xml / html / HTMLParser.java
1 package mir.util.xml.html;
2
3 import java.io.*;
4 import java.util.*;
5
6 /**
7  *
8  * TODO
9  *   [x] selfclosing <br/> tags
10  *   [ ] de-html-escaping of cdata, parameter values etc
11  *   [ ] Smarter corrections
12  *       [ ]
13  *   [ ] case sensitivity optional
14  */
15
16 public class HTMLParser {
17   private HTMLSchemaInformation schemaInformation;
18
19   public HTMLParser() {
20     schemaInformation = new HTMLSchemaInformation();
21   }
22
23   public void parse(Reader aReader, ParserReceiver aReceiver) throws HTMLParserExc, HTMLParserFailure, IOException {
24     HTMLScanner scanner;
25     CoreParser parser;
26     parser = new CoreParser(aReceiver);
27     scanner = new HTMLScanner(parser, aReader);
28     scanner.run();
29   }
30
31   private class CoreParser implements HTMLScanner.ScannerReceiver {
32     private ParserReceiver receiver;
33     private Stack tagStack;
34
35     public CoreParser(ParserReceiver aReceiver) {
36       receiver = aReceiver;
37       tagStack = new Stack();
38     }
39
40     public void handleDTD(String aDTD) throws HTMLParserExc  {
41       receiver.dtd(aDTD);
42     }
43
44     public void handleOpenTag(String aTag, Map anAttributes) throws HTMLParserExc  {
45       String lowercaseTag = aTag.toLowerCase();
46
47       HTMLSchemaInformation.HTMLTagInformation tagInformation =
48           schemaInformation.lookupTag(lowercaseTag);
49
50       if (tagInformation!=null) {
51         if (tagInformation.getIsBlock()) {
52           closeAllInlineTags();
53         }
54
55         closeAllAutoclosingTags(tagInformation);
56
57         Map attributes = new HashMap();
58
59         Iterator i = anAttributes.entrySet().iterator();
60         while (i.hasNext()) {
61           Map.Entry entry = (Map.Entry) i.next();
62
63           attributes.put(((String) entry.getKey()).toLowerCase(), entry.getValue());
64         }
65
66         receiver.openTag(lowercaseTag, attributes);
67         if (tagInformation.getHasBody()) {
68           tagStack.push(lowercaseTag);
69         }
70         else {
71           receiver.closeTag(lowercaseTag);
72         }
73       }
74       else {
75         tagStack.push(aTag);
76       }
77     }
78
79     public void handleClosingTag(String aTag) throws HTMLParserExc {
80       String lowercaseTag = aTag.toLowerCase();
81       String tag = aTag;
82
83       HTMLSchemaInformation.HTMLTagInformation tagInformation =
84           schemaInformation.lookupTag(lowercaseTag);
85
86       if (tagInformation!=null) {
87         tag = lowercaseTag;
88         if (tagInformation.getIsBlock()) {
89           closeAllInlineTags();
90         }
91       }
92
93       int index = tagStack.search(tag);
94
95       if (index>-1 && index<4) {
96         for (int i=0; i<index; i++) {
97           closeUpmostTag();
98         }
99       }
100     }
101
102     public void handleCData(String aData)  throws HTMLParserExc {
103       receiver.cdata(aData);
104     }
105
106     public void handleComment(String aTag) throws HTMLParserExc  {
107       receiver.comment(aTag);
108     }
109
110     public void handleEndOfStream() throws HTMLParserExc {
111       while (!tagStack.empty())
112         closeUpmostTag();
113     }
114
115     private void closeAllAutoclosingTags(HTMLSchemaInformation.HTMLTagInformation aTagInformation) throws HTMLParserExc {
116       while (!tagStack.empty()) {
117         String tag = (String) tagStack.peek();
118
119         if (aTagInformation.autoClose(tag)) {
120           closeUpmostTag();
121         }
122         else {
123           break;
124         }
125       }
126     }
127
128     private void closeAllInlineTags() throws HTMLParserExc {
129       while (!tagStack.empty()) {
130         HTMLSchemaInformation.HTMLTagInformation tagInformation =
131             schemaInformation.lookupTag((String) tagStack.peek());
132
133         if (tagInformation!=null && !tagInformation.getIsBlock()) {
134           closeUpmostTag();
135         }
136         else {
137           break;
138         }
139       }
140     }
141
142     private void closeUpmostTag() throws HTMLParserExc {
143       receiver.closeTag((String) tagStack.peek());
144       tagStack.pop();
145     }
146   }
147
148   public interface ParserReceiver {
149     public void dtd(String aDTD) throws HTMLParserExc;
150     public void openTag(String aTag, Map anAttributes) throws HTMLParserExc;
151     public void closeTag(String aTag) throws HTMLParserExc;
152     public void comment(String aData) throws HTMLParserExc;
153     public void cdata(String aData) throws HTMLParserExc;
154   }
155 }