1 /*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5 /*
6 * Copyright 2001-2004 The Apache Software Foundation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 /*
21 * $Id: SAX2DOM.java,v 1.7 2006/01/26 07:01:40 jeffsuttor Exp $
22 */
23
24
25 package com.sun.org.apache.xalan.internal.xsltc.trax;
26
27 import java.util.Stack;
28 import java.util.Vector;
29
30 import javax.xml.parsers.DocumentBuilderFactory;
31 import javax.xml.parsers.ParserConfigurationException;
32
33 import com.sun.org.apache.xalan.internal.xsltc.runtime.Constants;
34
35 import org.w3c.dom.Comment;
36 import org.w3c.dom.Document;
37 import org.w3c.dom.Element;
38 import org.w3c.dom.Node;
39 import org.w3c.dom.Text;
40 import org.w3c.dom.ProcessingInstruction;
41 import org.xml.sax.Attributes;
42 import org.xml.sax.ContentHandler;
43 import org.xml.sax.Locator;
44 import org.xml.sax.SAXException;
45 import org.xml.sax.ext.LexicalHandler;
46 import org.xml.sax.ext.Locator2;
47
48 /**
49 * @author G. Todd Miller
50 * @author Sunitha Reddy
51 */
52 public class SAX2DOM implements ContentHandler, LexicalHandler, Constants {
53
54 private Node _root = null;
55 private Document _document = null;
56 private Node _nextSibling = null;
57 private Stack _nodeStk = new Stack();
58 private Vector _namespaceDecls = null;
59 private Node _lastSibling = null;
60 private Locator locator = null;
61 private boolean needToSetDocumentInfo = true;
62
63 /**
64 * JAXP document builder factory. Create a single instance and use
65 * synchronization because the Javadoc is not explicit about
66 * thread safety.
67 */
68 static final DocumentBuilderFactory _factory =
69 DocumentBuilderFactory.newInstance();
70
71 public SAX2DOM() throws ParserConfigurationException {
72 synchronized (SAX2DOM.class) {
73 _document = _factory.newDocumentBuilder().newDocument();
74 }
75 _root = _document;
76 }
77
78 public SAX2DOM(Node root, Node nextSibling) throws ParserConfigurationException {
79 _root = root;
80 if (root instanceof Document) {
81 _document = (Document)root;
82 }
83 else if (root != null) {
84 _document = root.getOwnerDocument();
85 }
86 else {
87 synchronized (SAX2DOM.class) {
88 _document = _factory.newDocumentBuilder().newDocument();
89 }
90 _root = _document;
91 }
92
93 _nextSibling = nextSibling;
94 }
95
96 public SAX2DOM(Node root) throws ParserConfigurationException {
97 this(root, null);
98 }
99
100 public Node getDOM() {
101 return _root;
102 }
103
104 public void characters(char[] ch, int start, int length) {
105 // Ignore text nodes of length 0
106 if (length == 0) {
107 return;
108 }
109
110 final Node last = (Node)_nodeStk.peek();
111
112 // No text nodes can be children of root (DOM006 exception)
113 if (last != _document) {
114 final String text = new String(ch, start, length);
115 if( _lastSibling != null && _lastSibling.getNodeType() == Node.TEXT_NODE ){
116 ((Text)_lastSibling).appendData(text);
117 }
118 else if (last == _root && _nextSibling != null) {
119 _lastSibling = last.insertBefore(_document.createTextNode(text), _nextSibling);
120 }
121 else {
122 _lastSibling = last.appendChild(_document.createTextNode(text));
123 }
124 }
125 }
126
127 public void startDocument() {
128 _nodeStk.push(_root);
129 }
130
131 public void endDocument() {
132 _nodeStk.pop();
133 }
134
135 private void setDocumentInfo() {
136 //try to set document version
137 if (locator == null) return;
138 try{
139 _document.setXmlVersion(((Locator2)locator).getXMLVersion());
140 }catch(ClassCastException e){}
141
142 }
143
144 public void startElement(String namespace, String localName, String qName,
145 Attributes attrs)
146 {
147
148 if (needToSetDocumentInfo) {
149 setDocumentInfo();
150 needToSetDocumentInfo = false;
151 }
152
153 final Element tmp = (Element)_document.createElementNS(namespace, qName);
154
155 // Add namespace declarations first
156 if (_namespaceDecls != null) {
157 final int nDecls = _namespaceDecls.size();
158 for (int i = 0; i < nDecls; i++) {
159 final String prefix = (String) _namespaceDecls.elementAt(i++);
160
161 if (prefix == null || prefix.equals(EMPTYSTRING)) {
162 tmp.setAttributeNS(XMLNS_URI, XMLNS_PREFIX,
163 (String) _namespaceDecls.elementAt(i));
164 }
165 else {
166 tmp.setAttributeNS(XMLNS_URI, XMLNS_STRING + prefix,
167 (String) _namespaceDecls.elementAt(i));
168 }
169 }
170 _namespaceDecls.clear();
171 }
172
173 // Add attributes to element
174 /* final int nattrs = attrs.getLength();
175 for (int i = 0; i < nattrs; i++) {
176 if (attrs.getLocalName(i) == null) {
177 tmp.setAttribute(attrs.getQName(i), attrs.getValue(i));
178 }
179 else {
180 tmp.setAttributeNS(attrs.getURI(i), attrs.getQName(i),
181 attrs.getValue(i));
182 }
183 } */
184
185
186 // Add attributes to element
187 final int nattrs = attrs.getLength();
188 for (int i = 0; i < nattrs; i++) {
189 // checking if Namespace processing is being done
190 String attQName = attrs.getQName(i);
191 String attURI = attrs.getURI(i);
192 if (attrs.getLocalName(i).equals("")) {
193 tmp.setAttribute(attQName, attrs.getValue(i));
194 if (attrs.getType(i).equals("ID")) {
195 tmp.setIdAttribute(attQName, true);
196 }
197 } else {
198 tmp.setAttributeNS(attURI, attQName, attrs.getValue(i));
199 if (attrs.getType(i).equals("ID")) {
200 tmp.setIdAttributeNS(attURI, attrs.getLocalName(i), true);
201 }
202 }
203 }
204
205
206 // Append this new node onto current stack node
207 Node last = (Node)_nodeStk.peek();
208
209 // If the SAX2DOM is created with a non-null next sibling node,
210 // insert the result nodes before the next sibling under the root.
211 if (last == _root && _nextSibling != null)
212 last.insertBefore(tmp, _nextSibling);
213 else
214 last.appendChild(tmp);
215
216 // Push this node onto stack
217 _nodeStk.push(tmp);
218 _lastSibling = null;
219 }
220
221 public void endElement(String namespace, String localName, String qName) {
222 _nodeStk.pop();
223 _lastSibling = null;
224 }
225
226 public void startPrefixMapping(String prefix, String uri) {
227 if (_namespaceDecls == null) {
228 _namespaceDecls = new Vector(2);
229 }
230 _namespaceDecls.addElement(prefix);
231 _namespaceDecls.addElement(uri);
232 }
233
234 public void endPrefixMapping(String prefix) {
235 // do nothing
236 }
237
238 /**
239 * This class is only used internally so this method should never
240 * be called.
241 */
242 public void ignorableWhitespace(char[] ch, int start, int length) {
243 }
244
245 /**
246 * adds processing instruction node to DOM.
247 */
248 public void processingInstruction(String target, String data) {
249 final Node last = (Node)_nodeStk.peek();
250 ProcessingInstruction pi = _document.createProcessingInstruction(
251 target, data);
252 if (pi != null){
253 if (last == _root && _nextSibling != null)
254 last.insertBefore(pi, _nextSibling);
255 else
256 last.appendChild(pi);
257
258 _lastSibling = pi;
259 }
260 }
261
262 /**
263 * This class is only used internally so this method should never
264 * be called.
265 */
266 public void setDocumentLocator(Locator locator) {
267 this.locator = locator;
268 }
269
270 /**
271 * This class is only used internally so this method should never
272 * be called.
273 */
274 public void skippedEntity(String name) {
275 }
276
277
278 /**
279 * Lexical Handler method to create comment node in DOM tree.
280 */
281 public void comment(char[] ch, int start, int length) {
282 final Node last = (Node)_nodeStk.peek();
283 Comment comment = _document.createComment(new String(ch,start,length));
284 if (comment != null){
285 if (last == _root && _nextSibling != null)
286 last.insertBefore(comment, _nextSibling);
287 else
288 last.appendChild(comment);
289
290 _lastSibling = comment;
291 }
292 }
293
294 // Lexical Handler methods- not implemented
295 public void startCDATA() { }
296 public void endCDATA() { }
297 public void startEntity(java.lang.String name) { }
298 public void endDTD() { }
299 public void endEntity(String name) { }
300 public void startDTD(String name, String publicId, String systemId)
301 throws SAXException {}
302 }