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 }