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.dom; 024 025 import org.w3c.dom.DOMException; 026 import org.w3c.dom.DOMImplementation; 027 import org.w3c.dom.Document; 028 import org.w3c.dom.DocumentFragment; 029 import org.w3c.dom.Element; 030 import org.w3c.dom.Node; 031 import org.xml.sax.Attributes; 032 import org.xml.sax.SAXException; 033 import org.xml.sax.SAXParseException; 034 035 import nu.validator.htmlparser.common.DocumentMode; 036 import nu.validator.htmlparser.common.DocumentModeHandler; 037 import nu.validator.htmlparser.common.XmlViolationPolicy; 038 import nu.validator.htmlparser.impl.TreeBuilder; 039 040 class DOMTreeBuilder extends TreeBuilder<Element> { 041 042 private DOMImplementation implementation; 043 044 private Document document; 045 046 protected DOMTreeBuilder(DOMImplementation implementation) { 047 super(XmlViolationPolicy.ALLOW, true); 048 this.implementation = implementation; 049 } 050 051 @Override 052 protected void addAttributesToElement(Element element, Attributes attributes) 053 throws SAXException { 054 try { 055 for (int i = 0; i < attributes.getLength(); i++) { 056 String localName = attributes.getLocalName(i); 057 String uri = attributes.getURI(i); 058 if (!element.hasAttributeNS(uri, localName)) { 059 element.setAttributeNS(uri, localName, 060 attributes.getValue(i)); 061 } 062 } 063 } catch (DOMException e) { 064 fatal(e); 065 } 066 } 067 068 @Override 069 protected void appendCharacters(Element parent, char[] buf, int start, 070 int length) throws SAXException { 071 try { 072 parent.appendChild(document.createTextNode(new String(buf, start, 073 length))); 074 } catch (DOMException e) { 075 fatal(e); 076 } 077 } 078 079 @Override 080 protected void appendChildrenToNewParent(Element oldParent, 081 Element newParent) throws SAXException { 082 try { 083 while (oldParent.hasChildNodes()) { 084 newParent.appendChild(oldParent.getFirstChild()); 085 } 086 } catch (DOMException e) { 087 fatal(e); 088 } 089 } 090 091 @Override 092 protected void appendComment(Element parent, char[] buf, int start, 093 int length) throws SAXException { 094 try { 095 parent.appendChild(document.createComment(new String(buf, start, 096 length))); 097 } catch (DOMException e) { 098 fatal(e); 099 } 100 } 101 102 @Override 103 protected void appendCommentToDocument(char[] buf, int start, int length) 104 throws SAXException { 105 try { 106 document.appendChild(document.createComment(new String(buf, start, 107 length))); 108 } catch (DOMException e) { 109 fatal(e); 110 } 111 } 112 113 @Override 114 protected Element createElement(String name, Attributes attributes) 115 throws SAXException { 116 try { 117 Element rv = document.createElementNS( 118 "http://www.w3.org/1999/xhtml", name); 119 for (int i = 0; i < attributes.getLength(); i++) { 120 rv.setAttributeNS(attributes.getURI(i), 121 attributes.getLocalName(i), attributes.getValue(i)); 122 } 123 return rv; 124 } catch (DOMException e) { 125 fatal(e); 126 throw new RuntimeException("Unreachable"); 127 } 128 } 129 130 @Override 131 protected Element createHtmlElementSetAsRoot(Attributes attributes) 132 throws SAXException { 133 try { 134 Element rv = document.createElementNS( 135 "http://www.w3.org/1999/xhtml", "html"); 136 for (int i = 0; i < attributes.getLength(); i++) { 137 rv.setAttributeNS(attributes.getURI(i), 138 attributes.getLocalName(i), attributes.getValue(i)); 139 } 140 document.appendChild(rv); 141 return rv; 142 } catch (DOMException e) { 143 fatal(e); 144 throw new RuntimeException("Unreachable"); 145 } 146 } 147 148 @Override 149 protected void detachFromParent(Element element) throws SAXException { 150 try { 151 Node parent = element.getParentNode(); 152 if (parent != null) { 153 parent.removeChild(element); 154 } 155 } catch (DOMException e) { 156 fatal(e); 157 } 158 } 159 160 @Override 161 protected void detachFromParentAndAppendToNewParent(Element child, 162 Element newParent) throws SAXException { 163 try { 164 newParent.appendChild(child); 165 } catch (DOMException e) { 166 fatal(e); 167 } 168 } 169 170 @Override 171 protected boolean hasChildren(Element element) throws SAXException { 172 try { 173 return element.hasChildNodes(); 174 } catch (DOMException e) { 175 fatal(e); 176 throw new RuntimeException("Unreachable"); 177 } 178 } 179 180 @Override 181 protected void insertBefore(Element child, Element sibling, Element parent) 182 throws SAXException { 183 try { 184 parent.insertBefore(child, sibling); 185 } catch (DOMException e) { 186 fatal(e); 187 } 188 } 189 190 @Override 191 protected void insertCharactersBefore(char[] buf, int start, int length, 192 Element sibling, Element parent) throws SAXException { 193 try { 194 parent.insertBefore(document.createTextNode(new String(buf, start, length)), sibling); 195 } catch (DOMException e) { 196 fatal(e); 197 } 198 } 199 200 @Override 201 protected Element parentElementFor(Element child) throws SAXException { 202 try { 203 Node parent = child.getParentNode(); 204 if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) { 205 return (Element) parent; 206 } else { 207 return null; 208 } 209 } catch (DOMException e) { 210 fatal(e); 211 throw new RuntimeException("Unreachable"); 212 } 213 } 214 215 @Override 216 protected Element shallowClone(Element element) throws SAXException { 217 try { 218 return (Element) element.cloneNode(false); 219 } catch (DOMException e) { 220 fatal(e); 221 throw new RuntimeException("Unreachable"); 222 } 223 } 224 225 /** 226 * Returns the document. 227 * 228 * @return the document 229 */ 230 Document getDocument() { 231 Document rv = document; 232 document = null; 233 return rv; 234 } 235 236 DocumentFragment getDocumentFragment() { 237 DocumentFragment rv = document.createDocumentFragment(); 238 Node rootElt = document.getFirstChild(); 239 while (rootElt.hasChildNodes()) { 240 rv.appendChild(rootElt.getFirstChild()); 241 } 242 document = null; 243 return rv; 244 } 245 246 /** 247 * @see nu.validator.htmlparser.impl.TreeBuilder#createElement(java.lang.String, org.xml.sax.Attributes, java.lang.Object) 248 */ 249 @Override 250 protected Element createElement(String name, Attributes attributes, 251 Element form) throws SAXException { 252 try { 253 Element rv = createElement(name, attributes); 254 rv.setUserData("nu.validator.form-pointer", form, null); 255 return rv; 256 } catch (DOMException e) { 257 fatal(e); 258 return null; 259 } 260 } 261 262 /** 263 * @see nu.validator.htmlparser.impl.TreeBuilder#start() 264 */ 265 @Override 266 protected void start(boolean fragment) throws SAXException { 267 document = implementation.createDocument(null, null, null); 268 } 269 270 protected void documentMode(DocumentMode mode, String publicIdentifier, String systemIdentifier, boolean html4SpecificAdditionalErrorChecks) throws SAXException { 271 document.setUserData("nu.validator.document-mode", mode, null); 272 } 273 }