001: /*
002: * Copyright 2001-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: SAX2DOM.java,v 1.20 2005/05/20 15:30:23 mkwan Exp $
018: */
019:
020: package org.apache.xalan.xsltc.trax;
021:
022: import java.util.Stack;
023: import java.util.Vector;
024:
025: import javax.xml.parsers.DocumentBuilderFactory;
026: import javax.xml.parsers.ParserConfigurationException;
027:
028: import org.apache.xalan.xsltc.runtime.Constants;
029:
030: import org.w3c.dom.Comment;
031: import org.w3c.dom.Document;
032: import org.w3c.dom.Element;
033: import org.w3c.dom.Node;
034: import org.w3c.dom.Text;
035: import org.w3c.dom.ProcessingInstruction;
036: import org.xml.sax.Attributes;
037: import org.xml.sax.ContentHandler;
038: import org.xml.sax.Locator;
039: import org.xml.sax.SAXException;
040: import org.xml.sax.ext.LexicalHandler;
041:
042: /**
043: * @author G. Todd Miller
044: */
045: public class SAX2DOM implements ContentHandler, LexicalHandler,
046: Constants {
047:
048: private Node _root = null;
049: private Document _document = null;
050: private Node _nextSibling = null;
051: private Stack _nodeStk = new Stack();
052: private Vector _namespaceDecls = null;
053: private Node _lastSibling = null;
054:
055: public SAX2DOM() throws ParserConfigurationException {
056: final DocumentBuilderFactory factory = DocumentBuilderFactory
057: .newInstance();
058: _document = factory.newDocumentBuilder().newDocument();
059: _root = _document;
060: }
061:
062: public SAX2DOM(Node root, Node nextSibling)
063: throws ParserConfigurationException {
064: _root = root;
065: if (root instanceof Document) {
066: _document = (Document) root;
067: } else if (root != null) {
068: _document = root.getOwnerDocument();
069: } else {
070: final DocumentBuilderFactory factory = DocumentBuilderFactory
071: .newInstance();
072: _document = factory.newDocumentBuilder().newDocument();
073: _root = _document;
074: }
075:
076: _nextSibling = nextSibling;
077: }
078:
079: public SAX2DOM(Node root) throws ParserConfigurationException {
080: this (root, null);
081: }
082:
083: public Node getDOM() {
084: return _root;
085: }
086:
087: public void characters(char[] ch, int start, int length) {
088: final Node last = (Node) _nodeStk.peek();
089:
090: // No text nodes can be children of root (DOM006 exception)
091: if (last != _document) {
092: final String text = new String(ch, start, length);
093: if (_lastSibling != null
094: && _lastSibling.getNodeType() == Node.TEXT_NODE) {
095: ((Text) _lastSibling).appendData(text);
096: } else if (last == _root && _nextSibling != null) {
097: _lastSibling = last.insertBefore(_document
098: .createTextNode(text), _nextSibling);
099: } else {
100: _lastSibling = last.appendChild(_document
101: .createTextNode(text));
102: }
103:
104: }
105: }
106:
107: public void startDocument() {
108: _nodeStk.push(_root);
109: }
110:
111: public void endDocument() {
112: _nodeStk.pop();
113: }
114:
115: public void startElement(String namespace, String localName,
116: String qName, Attributes attrs) {
117: final Element tmp = (Element) _document.createElementNS(
118: namespace, qName);
119:
120: // Add namespace declarations first
121: if (_namespaceDecls != null) {
122: final int nDecls = _namespaceDecls.size();
123: for (int i = 0; i < nDecls; i++) {
124: final String prefix = (String) _namespaceDecls
125: .elementAt(i++);
126:
127: if (prefix == null || prefix.equals(EMPTYSTRING)) {
128: tmp.setAttributeNS(XMLNS_URI, XMLNS_PREFIX,
129: (String) _namespaceDecls.elementAt(i));
130: } else {
131: tmp.setAttributeNS(XMLNS_URI,
132: XMLNS_STRING + prefix,
133: (String) _namespaceDecls.elementAt(i));
134: }
135: }
136: _namespaceDecls.clear();
137: }
138:
139: // Add attributes to element
140: final int nattrs = attrs.getLength();
141: for (int i = 0; i < nattrs; i++) {
142: if (attrs.getLocalName(i) == null) {
143: tmp.setAttribute(attrs.getQName(i), attrs.getValue(i));
144: } else {
145: tmp.setAttributeNS(attrs.getURI(i), attrs.getQName(i),
146: attrs.getValue(i));
147: }
148: }
149:
150: // Append this new node onto current stack node
151: Node last = (Node) _nodeStk.peek();
152:
153: // If the SAX2DOM is created with a non-null next sibling node,
154: // insert the result nodes before the next sibling under the root.
155: if (last == _root && _nextSibling != null)
156: last.insertBefore(tmp, _nextSibling);
157: else
158: last.appendChild(tmp);
159:
160: // Push this node onto stack
161: _nodeStk.push(tmp);
162: _lastSibling = null;
163: }
164:
165: public void endElement(String namespace, String localName,
166: String qName) {
167: _nodeStk.pop();
168: _lastSibling = null;
169: }
170:
171: public void startPrefixMapping(String prefix, String uri) {
172: if (_namespaceDecls == null) {
173: _namespaceDecls = new Vector(2);
174: }
175: _namespaceDecls.addElement(prefix);
176: _namespaceDecls.addElement(uri);
177: }
178:
179: public void endPrefixMapping(String prefix) {
180: // do nothing
181: }
182:
183: /**
184: * This class is only used internally so this method should never
185: * be called.
186: */
187: public void ignorableWhitespace(char[] ch, int start, int length) {
188: }
189:
190: /**
191: * adds processing instruction node to DOM.
192: */
193: public void processingInstruction(String target, String data) {
194: final Node last = (Node) _nodeStk.peek();
195: ProcessingInstruction pi = _document
196: .createProcessingInstruction(target, data);
197: if (pi != null) {
198: if (last == _root && _nextSibling != null)
199: last.insertBefore(pi, _nextSibling);
200: else
201: last.appendChild(pi);
202:
203: _lastSibling = pi;
204: }
205: }
206:
207: /**
208: * This class is only used internally so this method should never
209: * be called.
210: */
211: public void setDocumentLocator(Locator locator) {
212: }
213:
214: /**
215: * This class is only used internally so this method should never
216: * be called.
217: */
218: public void skippedEntity(String name) {
219: }
220:
221: /**
222: * Lexical Handler method to create comment node in DOM tree.
223: */
224: public void comment(char[] ch, int start, int length) {
225: final Node last = (Node) _nodeStk.peek();
226: Comment comment = _document.createComment(new String(ch, start,
227: length));
228: if (comment != null) {
229: if (last == _root && _nextSibling != null)
230: last.insertBefore(comment, _nextSibling);
231: else
232: last.appendChild(comment);
233:
234: _lastSibling = comment;
235: }
236: }
237:
238: // Lexical Handler methods- not implemented
239: public void startCDATA() {
240: }
241:
242: public void endCDATA() {
243: }
244:
245: public void startEntity(java.lang.String name) {
246: }
247:
248: public void endDTD() {
249: }
250:
251: public void endEntity(String name) {
252: }
253:
254: public void startDTD(String name, String publicId, String systemId)
255: throws SAXException {
256: }
257:
258: }
|