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.saxtree;
024
025 import org.xml.sax.Attributes;
026 import org.xml.sax.ContentHandler;
027 import org.xml.sax.Locator;
028 import org.xml.sax.SAXException;
029 import org.xml.sax.ext.LexicalHandler;
030
031 public final class TreeParser implements Locator {
032 private final ContentHandler contentHandler;
033
034 private final LexicalHandler lexicalHandler;
035
036 private Locator locatorDelegate;
037
038 /**
039 * The constructor.
040 *
041 * @param contentHandler
042 * must not be <code>null</code>
043 * @param lexicalHandler
044 * may be <code>null</code>
045 */
046 public TreeParser(final ContentHandler contentHandler,
047 final LexicalHandler lexicalHandler) {
048 if (contentHandler == null) {
049 throw new IllegalArgumentException("contentHandler was null.");
050 }
051 this.contentHandler = contentHandler;
052 if (lexicalHandler == null) {
053 this.lexicalHandler = new NullLexicalHandler();
054 } else {
055 this.lexicalHandler = lexicalHandler;
056 }
057 }
058
059 /**
060 * Causes SAX events for the tree rooted at the argument to be emitted.
061 * <code>startDocument()</code> and <code>endDocument()</code> are only
062 * emitted for a <code>Document</code> node.
063 *
064 * @param node
065 * the root
066 * @throws SAXException
067 */
068 public void parse(Node node) throws SAXException {
069 contentHandler.setDocumentLocator(this);
070 Node current = node;
071 Node next;
072 for (;;) {
073 current.visit(this);
074 if ((next = current.getFirstChild()) != null) {
075 current = next;
076 continue;
077 }
078 for (;;) {
079 current.revisit(this);
080 if (current == node) {
081 return;
082 }
083 if ((next = current.getNextSibling()) != null) {
084 current = next;
085 break;
086 }
087 current = current.getParentNode();
088 }
089 }
090 }
091
092 /**
093 * @param ch
094 * @param start
095 * @param length
096 * @throws SAXException
097 * @see org.xml.sax.ContentHandler#characters(char[], int, int)
098 */
099 void characters(char[] ch, int start, int length, Locator locator)
100 throws SAXException {
101 this.locatorDelegate = locator;
102 contentHandler.characters(ch, start, length);
103 }
104
105 /**
106 * @throws SAXException
107 * @see org.xml.sax.ContentHandler#endDocument()
108 */
109 void endDocument(Locator locator) throws SAXException {
110 this.locatorDelegate = locator;
111 contentHandler.endDocument();
112 }
113
114 /**
115 * @param uri
116 * @param localName
117 * @param qName
118 * @throws SAXException
119 * @see org.xml.sax.ContentHandler#endElement(java.lang.String,
120 * java.lang.String, java.lang.String)
121 */
122 void endElement(String uri, String localName, String qName, Locator locator)
123 throws SAXException {
124 this.locatorDelegate = locator;
125 contentHandler.endElement(uri, localName, qName);
126 }
127
128 /**
129 * @param prefix
130 * @throws SAXException
131 * @see org.xml.sax.ContentHandler#endPrefixMapping(java.lang.String)
132 */
133 void endPrefixMapping(String prefix, Locator locator) throws SAXException {
134 this.locatorDelegate = locator;
135 contentHandler.endPrefixMapping(prefix);
136 }
137
138 /**
139 * @param ch
140 * @param start
141 * @param length
142 * @throws SAXException
143 * @see org.xml.sax.ContentHandler#ignorableWhitespace(char[], int, int)
144 */
145 void ignorableWhitespace(char[] ch, int start, int length, Locator locator)
146 throws SAXException {
147 this.locatorDelegate = locator;
148 contentHandler.ignorableWhitespace(ch, start, length);
149 }
150
151 /**
152 * @param target
153 * @param data
154 * @throws SAXException
155 * @see org.xml.sax.ContentHandler#processingInstruction(java.lang.String,
156 * java.lang.String)
157 */
158 void processingInstruction(String target, String data, Locator locator)
159 throws SAXException {
160 this.locatorDelegate = locator;
161 contentHandler.processingInstruction(target, data);
162 }
163
164 /**
165 * @param name
166 * @throws SAXException
167 * @see org.xml.sax.ContentHandler#skippedEntity(java.lang.String)
168 */
169 void skippedEntity(String name, Locator locator) throws SAXException {
170 this.locatorDelegate = locator;
171 contentHandler.skippedEntity(name);
172 }
173
174 /**
175 * @throws SAXException
176 * @see org.xml.sax.ContentHandler#startDocument()
177 */
178 void startDocument(Locator locator) throws SAXException {
179 this.locatorDelegate = locator;
180 contentHandler.startDocument();
181 }
182
183 /**
184 * @param uri
185 * @param localName
186 * @param qName
187 * @param atts
188 * @throws SAXException
189 * @see org.xml.sax.ContentHandler#startElement(java.lang.String,
190 * java.lang.String, java.lang.String, org.xml.sax.Attributes)
191 */
192 void startElement(String uri, String localName, String qName,
193 Attributes atts, Locator locator) throws SAXException {
194 this.locatorDelegate = locator;
195 contentHandler.startElement(uri, localName, qName, atts);
196 }
197
198 /**
199 * @param prefix
200 * @param uri
201 * @throws SAXException
202 * @see org.xml.sax.ContentHandler#startPrefixMapping(java.lang.String,
203 * java.lang.String)
204 */
205 void startPrefixMapping(String prefix, String uri, Locator locator)
206 throws SAXException {
207 this.locatorDelegate = locator;
208 contentHandler.startPrefixMapping(prefix, uri);
209 }
210
211 /**
212 * @param ch
213 * @param start
214 * @param length
215 * @throws SAXException
216 * @see org.xml.sax.ext.LexicalHandler#comment(char[], int, int)
217 */
218 void comment(char[] ch, int start, int length, Locator locator)
219 throws SAXException {
220 this.locatorDelegate = locator;
221 lexicalHandler.comment(ch, start, length);
222 }
223
224 /**
225 * @throws SAXException
226 * @see org.xml.sax.ext.LexicalHandler#endCDATA()
227 */
228 void endCDATA(Locator locator) throws SAXException {
229 this.locatorDelegate = locator;
230 lexicalHandler.endCDATA();
231 }
232
233 /**
234 * @throws SAXException
235 * @see org.xml.sax.ext.LexicalHandler#endDTD()
236 */
237 void endDTD(Locator locator) throws SAXException {
238 this.locatorDelegate = locator;
239 lexicalHandler.endDTD();
240 }
241
242 /**
243 * @param name
244 * @throws SAXException
245 * @see org.xml.sax.ext.LexicalHandler#endEntity(java.lang.String)
246 */
247 void endEntity(String name, Locator locator) throws SAXException {
248 this.locatorDelegate = locator;
249 lexicalHandler.endEntity(name);
250 }
251
252 /**
253 * @throws SAXException
254 * @see org.xml.sax.ext.LexicalHandler#startCDATA()
255 */
256 void startCDATA(Locator locator) throws SAXException {
257 this.locatorDelegate = locator;
258 lexicalHandler.startCDATA();
259 }
260
261 /**
262 * @param name
263 * @param publicId
264 * @param systemId
265 * @throws SAXException
266 * @see org.xml.sax.ext.LexicalHandler#startDTD(java.lang.String,
267 * java.lang.String, java.lang.String)
268 */
269 void startDTD(String name, String publicId, String systemId, Locator locator)
270 throws SAXException {
271 this.locatorDelegate = locator;
272 lexicalHandler.startDTD(name, publicId, systemId);
273 }
274
275 /**
276 * @param name
277 * @throws SAXException
278 * @see org.xml.sax.ext.LexicalHandler#startEntity(java.lang.String)
279 */
280 void startEntity(String name, Locator locator) throws SAXException {
281 this.locatorDelegate = locator;
282 lexicalHandler.startEntity(name);
283 }
284
285 /**
286 * @return
287 * @see org.xml.sax.Locator#getColumnNumber()
288 */
289 public int getColumnNumber() {
290 if (locatorDelegate == null) {
291 return -1;
292 } else {
293 return locatorDelegate.getColumnNumber();
294 }
295 }
296
297 /**
298 * @return
299 * @see org.xml.sax.Locator#getLineNumber()
300 */
301 public int getLineNumber() {
302 if (locatorDelegate == null) {
303 return -1;
304 } else {
305 return locatorDelegate.getLineNumber();
306 }
307 }
308
309 /**
310 * @return
311 * @see org.xml.sax.Locator#getPublicId()
312 */
313 public String getPublicId() {
314 if (locatorDelegate == null) {
315 return null;
316 } else {
317
318 return locatorDelegate.getPublicId();
319 }
320 }
321
322 /**
323 * @return
324 * @see org.xml.sax.Locator#getSystemId()
325 */
326 public String getSystemId() {
327 if (locatorDelegate == null) {
328 return null;
329 } else {
330 return locatorDelegate.getSystemId();
331 }
332 }
333 }