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 nu.validator.htmlparser.common.XmlViolationPolicy;
026 import nu.validator.htmlparser.impl.AttributesImpl;
027 import nu.validator.htmlparser.impl.TreeBuilder;
028 import nu.validator.saxtree.Characters;
029 import nu.validator.saxtree.Comment;
030 import nu.validator.saxtree.DTD;
031 import nu.validator.saxtree.Document;
032 import nu.validator.saxtree.DocumentFragment;
033 import nu.validator.saxtree.Element;
034 import nu.validator.saxtree.NodeType;
035 import nu.validator.saxtree.ParentNode;
036 import nu.validator.saxtree.TreeParser;
037
038 import org.xml.sax.Attributes;
039 import org.xml.sax.ContentHandler;
040 import org.xml.sax.SAXException;
041 import org.xml.sax.ext.LexicalHandler;
042
043 class SAXTreeBuilder extends TreeBuilder<Element> {
044
045 private Document document;
046
047 SAXTreeBuilder() {
048 super(XmlViolationPolicy.ALLOW, false);
049 }
050
051 @Override
052 protected void appendComment(Element parent, char[] buf, int start, int length) {
053 parent.appendChild(new Comment(tokenizer, buf, start, length));
054 }
055
056 @Override
057 protected void appendCommentToDocument(char[] buf, int start, int length) {
058 document.appendChild(new Comment(tokenizer, buf, start, length));
059 }
060
061 @Override
062 protected void appendCharacters(Element parent, char[] buf, int start, int length) {
063 parent.appendChild(new Characters(tokenizer, buf, start, length));
064 }
065
066 @Override
067 protected void detachFromParent(Element element) {
068 element.detach();
069 }
070
071 @Override
072 protected boolean hasChildren(Element element) {
073 return element.getFirstChild() != null;
074 }
075
076 @Override
077 protected Element shallowClone(Element element) {
078 Element newElt = new Element(element, element.getUri(), element.getLocalName(), element.getQName(), element.getAttributes(), true, element.getPrefixMappings());
079 newElt.copyEndLocator(element);
080 return newElt;
081 }
082
083 @Override
084 protected void detachFromParentAndAppendToNewParent(Element child, Element newParent) {
085 newParent.appendChild(child);
086 }
087
088 @Override
089 protected Element createHtmlElementSetAsRoot(Attributes attributes) {
090 Element newElt = new Element(tokenizer, "http://www.w3.org/1999/xhtml", "html", "html", attributes, true, null);
091 document.appendChild(newElt);
092 return newElt;
093 }
094
095 @Override
096 protected void insertBefore(Element child, Element sibling, Element parent) {
097 parent.insertBefore(child, sibling);
098 }
099
100 @Override
101 protected Element parentElementFor(Element child) {
102 ParentNode parent = child.getParentNode();
103 if (parent == null) {
104 return null;
105 }
106 if (parent.getNodeType() == NodeType.ELEMENT) {
107 return (Element) parent;
108 }
109 return null;
110 }
111
112 @Override
113 protected void addAttributesToElement(Element element, Attributes attributes) {
114 AttributesImpl existingAttrs = (AttributesImpl) element.getAttributes();
115 for (int i = 0; i < attributes.getLength(); i++) {
116 String qName = attributes.getQName(i);
117 if (existingAttrs.getIndex(qName) < 0) {
118 existingAttrs.addAttribute(qName, attributes.getValue(i));
119 }
120 }
121 }
122
123 /**
124 * @see nu.validator.htmlparser.impl.TreeBuilder#appendDoctypeToDocument(java.lang.String, java.lang.String, java.lang.String)
125 */
126 @Override
127 protected void appendDoctypeToDocument(String name, String publicIdentifier, String systemIdentifier) {
128 DTD dtd = new DTD(tokenizer, name, publicIdentifier, systemIdentifier);
129 dtd.setEndLocator(tokenizer);
130 document.appendChild(dtd);
131 }
132
133 /**
134 * Returns the document.
135 *
136 * @return the document
137 */
138 Document getDocument() {
139 Document rv = document;
140 document = null;
141 return rv;
142 }
143
144 DocumentFragment getDocumentFragment() {
145 DocumentFragment rv = new DocumentFragment();
146 rv.appendChildren(document.getFirstChild());
147 document = null;
148 return rv;
149 }
150
151 /**
152 * @throws SAXException
153 * @see nu.validator.htmlparser.impl.TreeBuilder#end()
154 */
155 @Override
156 protected void end() throws SAXException {
157 document.setEndLocator(tokenizer);
158 }
159
160 /**
161 * @see nu.validator.htmlparser.impl.TreeBuilder#start()
162 */
163 @Override
164 protected void start(boolean fragment) {
165 document = new Document(tokenizer);
166 }
167
168 @Override
169 protected void appendChildrenToNewParent(Element oldParent, Element newParent) throws SAXException {
170 newParent.appendChildren(oldParent);
171 }
172
173 @Override
174 protected Element createElement(String name, Attributes attributes) throws SAXException {
175 return new Element(tokenizer, "http://www.w3.org/1999/xhtml", name, name, attributes, true, null);
176 }
177
178 @Override
179 protected void insertCharactersBefore(char[] buf, int start, int length, Element sibling, Element parent) throws SAXException {
180 parent.insertBefore(new Characters(tokenizer, buf, start, length), sibling);
181 }
182
183 }