1 /* Copyright 2002-2006, 2009, 2014 Elliotte Rusty Harold
2 
3    This library is free software; you can redistribute it and/or modify
4    it under the terms of version 2.1 of the GNU Lesser General Public
5    License as published by the Free Software Foundation.
6 
7    This library is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU Lesser General Public License for more details.
11 
12    You should have received a copy of the GNU Lesser General Public
13    License along with this library; if not, write to the
14    Free Software Foundation, Inc., 59 Temple Place, Suite 330,
15    Boston, MA 02111-1307  USA
16 
17    You can contact Elliotte Rusty Harold by sending e-mail to
18    elharo@ibiblio.org. Please include the word "XOM" in the
19    subject line. The XOM home page is located at http://www.xom.nu/
20 */
21 
22 
23 package nu.xom;
24 
25 import org.xml.sax.SAXException;
26 
27 /**
28  * @author Elliotte Rusty Harold
29  * @version 1.2.11
30  *
31  */
32 class NonVerifyingHandler extends XOMHandler {
33 
NonVerifyingHandler(NodeFactory factory)34     NonVerifyingHandler(NodeFactory factory) {
35         super(factory);
36     }
37 
38 
startElement(String namespaceURI, String localName, String qualifiedName, org.xml.sax.Attributes attributes)39     public void startElement(String namespaceURI, String localName,
40       String qualifiedName, org.xml.sax.Attributes attributes) throws SAXException {
41 
42         flushText();
43         Element element = Element.build(qualifiedName, namespaceURI, localName);
44         if (parent == document) { // root
45             document.setRootElement(element);
46             inProlog = false;
47         }
48 
49         current = element;
50         // Need to push this, even if it's null
51         parents.add(element);
52 
53         if (parent != document) {
54             // a.k.a. parent not instanceof Document
55             parent.fastInsertChild(element, parent.getChildCount());
56         }
57         // This is optimized for the very common case where
58         // everything in the document has the same actual base URI.
59         // It may add redundant base URIs in cases like XInclude
60         // where different parts of the document have different
61         // base URIs.
62          String baseURI = locator.getSystemId();
63          if (baseURI != null && !baseURI.equals(documentBaseURI)) {
64              element.setActualBaseURI(baseURI);
65          }
66 
67         // Attach the attributes; this must be done before the
68         // namespaces are attached.
69         int length = attributes.getLength();
70 
71         // We've got a pretty good guess at how many attributes there
72         // will be here; we could ensureCapacity up to that length.
73         // However, that might waste memory because we wouldn't use
74         // the ones for namespace declarations. We could always
75         // trimToSize when we're done, but it's probably not worth
76         // the effort.
77         for (int i = 0; i < length; i++) {
78             String qName = attributes.getQName(i);
79             if (qName.startsWith("xmlns:") || qName.equals("xmlns")) {
80                 continue;
81             }
82             else {
83                 String namespace = attributes.getURI(i);
84                 String value = attributes.getValue(i);
85                 Attribute attribute = Attribute.build(
86                   qName,
87                   namespace,
88                   value,
89                   convertStringToType(attributes.getType(i)),
90                   attributes.getLocalName(i)
91                 );
92                 element.fastAddAttribute(attribute);
93             }
94         }
95 
96         // Attach the namespaces
97         for (int i = 0; i < length; i++) {
98             String qName = attributes.getQName(i);
99             if (qName.startsWith("xmlns:")) {
100                 String namespaceName = attributes.getValue(i);
101                 String namespacePrefix = qName.substring(6);
102                 String currentValue
103                    = element.getNamespaceURI(namespacePrefix);
104                 if (!namespaceName.equals(currentValue)) {
105                     element.addNamespaceDeclaration(
106                       namespacePrefix, namespaceName);
107                 }
108             }
109             else if (qName.equals("xmlns")) {
110                 String namespaceName = attributes.getValue(i);
111                 String namespacePrefix = "";
112                 String currentValue
113                   = element.getNamespaceURI(namespacePrefix);
114                 if (!namespaceName.equals(currentValue)) {
115                     element.addNamespaceDeclaration(namespacePrefix,
116                      namespaceName);
117                 }
118             }
119         }
120 
121         // this is the new parent
122         parent = element;
123     }
124 
125 
endElement( String namespaceURI, String localName, String qualifiedName)126     public void endElement(
127       String namespaceURI, String localName, String qualifiedName) {
128 
129         // If we're immediately inside a skipped element
130         // we need to reset current to null, not to the parent
131         current = (ParentNode) parents.remove(parents.size()-1);
132         flushText();
133 
134         parent = current.getParent();
135 
136         if (parent.isDocument()) { // root element
137             Document doc = (Document) parent;
138             doc.setRootElement((Element) current);
139         }
140 
141     }
142 
143 
144     // accumulate all text that's in the buffer into a text node
flushText()145     private void flushText() {
146 
147         if (buffer != null) {
148             textString = buffer.toString();
149             buffer = null;
150         }
151 
152         if (textString != null) {
153             Text result;
154             if (!inCDATA) {
155                 result = Text.build(textString);
156             }
157             else {
158                 result = CDATASection.build(textString);
159             }
160             parent.fastInsertChild(result, parent.getChildCount());
161             textString = null;
162         }
163         inCDATA = false;
164         finishedCDATA = false;
165 
166     }
167 
168 
processingInstruction(String target, String data)169     public void processingInstruction(String target, String data) throws SAXException {
170 
171         // simplify logic???? into two cases in and not in DTD
172         // ditto for comment() method and superclass
173         if (!inDTD) flushText();
174         else if (!inInternalSubset()) return;
175 
176         ProcessingInstruction result = ProcessingInstruction.build(target, data);
177 
178         if (!inDTD) {
179             if (inProlog) {
180                 parent.fastInsertChild(result, position);
181                 position++;
182             }
183             else {
184                 parent.fastInsertChild(result, parent.getChildCount());
185             }
186         }
187         else {
188             internalDTDSubset.append("  ");
189             internalDTDSubset.append(result.toXML());
190             internalDTDSubset.append("\n");
191         }
192 
193     }
194 
195 
196     // LexicalHandler events
startDTD(String rootName, String publicID, String systemID)197     public void startDTD(String rootName, String publicID,
198       String systemID) {
199 
200         inDTD = true;
201         DocType doctype = DocType.build(rootName, publicID, systemID);
202         document.fastInsertChild(doctype, position);
203         position++;
204         internalDTDSubset = new StringBuffer();
205         this.doctype = doctype;
206 
207     }
208 
209 
comment(char[] text, int start, int length)210     public void comment(char[] text, int start, int length) throws SAXException {
211 
212         if (!inDTD) flushText();
213         else if (!inInternalSubset()) return;
214 
215         Comment result = Comment.build(new String(text, start, length));
216 
217         if (!inDTD) {
218             if (inProlog) {
219                 parent.insertChild(result, position);
220                 position++;
221             }
222             else {
223                 parent.fastInsertChild(result, parent.getChildCount());
224             }
225         }
226         else {
227             internalDTDSubset.append("  ");
228             internalDTDSubset.append(result.toXML());
229             internalDTDSubset.append("\n");
230         }
231 
232     }
233 
234 
endDTD()235     public void endDTD() {
236 
237         inDTD = false;
238         if (doctype != null) {
239             doctype.fastSetInternalDTDSubset(internalDTDSubset.toString());
240         }
241 
242     }
243 
244 
245 }