001 /*
002 * Copyright (c) 2007 Henri Sivonen
003 *
004 * Permission is hereby granted, free of charge, to any person obtaining a
005 * copy of this software and associated documentation files (the "Software"),
006 * to deal in the Software without restriction, including without limitation
007 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
008 * and/or sell copies of the Software, and to permit persons to whom the
009 * Software is furnished to do so, subject to the following conditions:
010 *
011 * The above copyright notice and this permission notice shall be included in
012 * all copies or substantial portions of the Software.
013 *
014 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
015 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
016 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
017 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
018 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
019 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
020 * DEALINGS IN THE SOFTWARE.
021 */
022
023 package nu.validator.htmlparser.sax;
024
025 import org.xml.sax.Attributes;
026 import org.xml.sax.ContentHandler;
027 import org.xml.sax.SAXException;
028 import org.xml.sax.ext.LexicalHandler;
029
030 import nu.validator.htmlparser.common.XmlViolationPolicy;
031 import nu.validator.htmlparser.impl.AttributesImpl;
032 import nu.validator.htmlparser.impl.TreeBuilder;
033
034 class SAXStreamer extends TreeBuilder<Attributes>{
035
036 private ContentHandler contentHandler;
037 private LexicalHandler lexicalHandler;
038 private int depth;
039
040 SAXStreamer() {
041 super(XmlViolationPolicy.FATAL, false);
042 }
043
044 @Override
045 protected void addAttributesToElement(Attributes element, Attributes attributes) throws SAXException {
046 Attributes existingAttrs = element;
047 for (int i = 0; i < attributes.getLength(); i++) {
048 String qName = attributes.getQName(i);
049 if (existingAttrs.getIndex(qName) < 0) {
050 fatal();
051 }
052 }
053 }
054
055 @Override
056 protected void appendCharacters(Attributes parent, char[] buf, int start, int length) throws SAXException {
057 contentHandler.characters(buf, start, length);
058 }
059
060 @Override
061 protected void appendChildrenToNewParent(Attributes oldParent, Attributes newParent) throws SAXException {
062 fatal();
063 }
064
065 @Override
066 protected void appendComment(Attributes parent, char[] buf, int start, int length) throws SAXException {
067 if (lexicalHandler != null) {
068 lexicalHandler.comment(buf, start, length);
069 }
070 }
071
072 @Override
073 protected void appendCommentToDocument(char[] buf, int start, int length)
074 throws SAXException {
075 if (lexicalHandler != null) {
076 if (depth == 0) {
077 lexicalHandler.comment(buf, start, length);
078 } else {
079 fatal();
080 }
081 }
082 }
083
084 @Override
085 protected Attributes createElement(String name, Attributes attributes) throws SAXException {
086 return attributes;
087 }
088
089 @Override
090 protected Attributes createHtmlElementSetAsRoot(Attributes attributes) throws SAXException {
091 return attributes;
092 }
093
094 @Override
095 protected void detachFromParent(Attributes element) throws SAXException {
096 fatal();
097 }
098
099 @Override
100 protected void detachFromParentAndAppendToNewParent(Attributes child, Attributes newParent) throws SAXException {
101 }
102
103 @Override
104 protected boolean hasChildren(Attributes element) throws SAXException {
105 return false;
106 }
107
108 @Override
109 protected void insertBefore(Attributes child, Attributes sibling, Attributes parent) throws SAXException {
110 fatal();
111 }
112
113 @Override
114 protected void insertCharactersBefore(char[] buf, int start, int length, Attributes sibling, Attributes parent) throws SAXException {
115 fatal();
116 }
117
118 @Override
119 protected Attributes parentElementFor(Attributes child) throws SAXException {
120 fatal();
121 throw new RuntimeException("Unreachable");
122 }
123
124 @Override
125 protected Attributes shallowClone(Attributes element) throws SAXException {
126 return element;
127 }
128
129 public void setContentHandler(ContentHandler handler) {
130 contentHandler = handler;
131 }
132
133 public void setLexicalHandler(LexicalHandler handler) {
134 lexicalHandler = handler;
135 }
136
137 /**
138 * @see nu.validator.htmlparser.impl.TreeBuilder#appendDoctypeToDocument(java.lang.String, java.lang.String, java.lang.String)
139 */
140 @Override
141 protected void appendDoctypeToDocument(String name, String publicIdentifier, String systemIdentifier) throws SAXException {
142 if (lexicalHandler != null) {
143 lexicalHandler.startDTD(name, publicIdentifier, systemIdentifier);
144 lexicalHandler.endDTD();
145 }
146 }
147
148 /**
149 * @see nu.validator.htmlparser.impl.TreeBuilder#bodyClosed(java.lang.Object)
150 */
151 @Override
152 protected void bodyClosed(Attributes body) throws SAXException {
153 contentHandler.endElement("http://www.w3.org/1999/xhtml", "body", "body");
154 depth--;
155 }
156
157 /**
158 * @see nu.validator.htmlparser.impl.TreeBuilder#elementPopped(java.lang.String, java.lang.Object)
159 */
160 @Override
161 protected void elementPopped(String name, Attributes node) throws SAXException {
162 contentHandler.endElement("http://www.w3.org/1999/xhtml", name, name);
163 depth--;
164 }
165
166 /**
167 * @see nu.validator.htmlparser.impl.TreeBuilder#elementPushed(java.lang.String, java.lang.Object)
168 */
169 @Override
170 protected void elementPushed(String name, Attributes node) throws SAXException {
171 if (depth == 0) {
172 contentHandler.startPrefixMapping("", "http://www.w3.org/1999/xhtml");
173 }
174 contentHandler.startElement("http://www.w3.org/1999/xhtml", name, name, node);
175 depth++;
176 }
177
178 /**
179 * @see nu.validator.htmlparser.impl.TreeBuilder#end()
180 */
181 @Override
182 protected void end() throws SAXException {
183 contentHandler.endDocument();
184 }
185
186 /**
187 * @see nu.validator.htmlparser.impl.TreeBuilder#htmlClosed(java.lang.Object)
188 */
189 @Override
190 protected void htmlClosed(Attributes html) throws SAXException {
191 contentHandler.endElement("http://www.w3.org/1999/xhtml", "html", "html");
192 contentHandler.endPrefixMapping("");
193 depth--;
194 }
195
196 /**
197 * @see nu.validator.htmlparser.impl.TreeBuilder#start()
198 */
199 @Override
200 protected void start(boolean fragment) throws SAXException {
201 contentHandler.setDocumentLocator(tokenizer);
202 if (fragment) {
203 depth = 1;
204 } else {
205 depth = 0;
206 contentHandler.startDocument();
207 }
208 }
209
210 }