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 }