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