jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/DOM2SAX.java
changeset 12457 c348e06f0e82
parent 6 7f561c08de6b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/com/sun/org/apache/xalan/internal/xsltc/trax/DOM2SAX.java	Thu Apr 12 08:38:26 2012 -0700
@@ -0,0 +1,485 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Copyright 2001-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
+ * $Id: DOM2SAX.java,v 1.2.4.1 2005/09/06 11:52:46 pvedula Exp $
+ */
+
+
+package com.sun.org.apache.xalan.internal.xsltc.trax;
+
+import java.io.IOException;
+import java.util.Hashtable;
+import java.util.Stack;
+import java.util.Vector;
+
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+import org.xml.sax.ContentHandler;
+import org.xml.sax.DTDHandler;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXNotRecognizedException;
+import org.xml.sax.SAXNotSupportedException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.ext.LexicalHandler;
+import org.xml.sax.helpers.AttributesImpl;
+import com.sun.org.apache.xalan.internal.xsltc.dom.SAXImpl;
+import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary;
+
+/**
+ * @author G. Todd Miller
+ */
+public class DOM2SAX implements XMLReader, Locator {
+
+    private final static String EMPTYSTRING = "";
+    private static final String XMLNS_PREFIX = "xmlns";
+
+    private Node _dom = null;
+    private ContentHandler _sax = null;
+    private LexicalHandler _lex = null;
+    private SAXImpl _saxImpl = null;
+    private Hashtable _nsPrefixes = new Hashtable();
+
+    public DOM2SAX(Node root) {
+        _dom = root;
+    }
+
+    public ContentHandler getContentHandler() {
+        return _sax;
+    }
+
+    public void setContentHandler(ContentHandler handler) throws
+        NullPointerException
+    {
+        _sax = handler;
+        if (handler instanceof LexicalHandler) {
+            _lex = (LexicalHandler) handler;
+        }
+
+        if (handler instanceof SAXImpl) {
+            _saxImpl = (SAXImpl)handler;
+        }
+    }
+
+    /**
+     * Begin the scope of namespace prefix. Forward the event to the
+     * SAX handler only if the prefix is unknown or it is mapped to a
+     * different URI.
+     */
+    private boolean startPrefixMapping(String prefix, String uri)
+        throws SAXException
+    {
+        boolean pushed = true;
+        Stack uriStack = (Stack) _nsPrefixes.get(prefix);
+
+        if (uriStack != null) {
+            if (uriStack.isEmpty()) {
+                _sax.startPrefixMapping(prefix, uri);
+                uriStack.push(uri);
+            }
+            else {
+                final String lastUri = (String) uriStack.peek();
+                if (!lastUri.equals(uri)) {
+                    _sax.startPrefixMapping(prefix, uri);
+                    uriStack.push(uri);
+                }
+                else {
+                    pushed = false;
+                }
+            }
+        }
+        else {
+            _sax.startPrefixMapping(prefix, uri);
+            _nsPrefixes.put(prefix, uriStack = new Stack());
+            uriStack.push(uri);
+        }
+        return pushed;
+    }
+
+    /*
+     * End the scope of a name prefix by popping it from the stack and
+     * passing the event to the SAX Handler.
+     */
+    private void endPrefixMapping(String prefix)
+        throws SAXException
+    {
+        final Stack uriStack = (Stack) _nsPrefixes.get(prefix);
+
+        if (uriStack != null) {
+            _sax.endPrefixMapping(prefix);
+            uriStack.pop();
+        }
+    }
+
+    /**
+     * If the DOM was created using a DOM 1.0 API, the local name may be
+     * null. If so, get the local name from the qualified name before
+     * generating the SAX event.
+     */
+    private static String getLocalName(Node node) {
+        final String localName = node.getLocalName();
+
+        if (localName == null) {
+            final String qname = node.getNodeName();
+            final int col = qname.lastIndexOf(':');
+            return (col > 0) ? qname.substring(col + 1) : qname;
+        }
+        return localName;
+    }
+
+    public void parse(InputSource unused) throws IOException, SAXException {
+        parse(_dom);
+    }
+
+    public void parse() throws IOException, SAXException {
+        if (_dom != null) {
+            boolean isIncomplete =
+                (_dom.getNodeType() != org.w3c.dom.Node.DOCUMENT_NODE);
+
+            if (isIncomplete) {
+                _sax.startDocument();
+                parse(_dom);
+                _sax.endDocument();
+            }
+            else {
+                parse(_dom);
+            }
+        }
+    }
+
+    /**
+     * Traverse the DOM and generate SAX events for a handler. A
+     * startElement() event passes all attributes, including namespace
+     * declarations.
+     */
+    private void parse(Node node) throws IOException, SAXException {
+        Node first = null;
+        if (node == null) return;
+
+        switch (node.getNodeType()) {
+        case Node.ATTRIBUTE_NODE:         // handled by ELEMENT_NODE
+        case Node.DOCUMENT_FRAGMENT_NODE:
+        case Node.DOCUMENT_TYPE_NODE :
+        case Node.ENTITY_NODE :
+        case Node.ENTITY_REFERENCE_NODE:
+        case Node.NOTATION_NODE :
+            // These node types are ignored!!!
+            break;
+        case Node.CDATA_SECTION_NODE:
+            final String cdata = node.getNodeValue();
+            if (_lex != null) {
+                _lex.startCDATA();
+                _sax.characters(cdata.toCharArray(), 0, cdata.length());
+                _lex.endCDATA();
+            }
+            else {
+                // in the case where there is no lex handler, we still
+                // want the text of the cdate to make its way through.
+                _sax.characters(cdata.toCharArray(), 0, cdata.length());
+            }
+            break;
+
+        case Node.COMMENT_NODE:           // should be handled!!!
+            if (_lex != null) {
+                final String value = node.getNodeValue();
+                _lex.comment(value.toCharArray(), 0, value.length());
+            }
+            break;
+        case Node.DOCUMENT_NODE:
+            _sax.setDocumentLocator(this);
+
+            _sax.startDocument();
+            Node next = node.getFirstChild();
+            while (next != null) {
+                parse(next);
+                next = next.getNextSibling();
+            }
+            _sax.endDocument();
+            break;
+
+        case Node.ELEMENT_NODE:
+            String prefix;
+            Vector pushedPrefixes = new Vector();
+            final AttributesImpl attrs = new AttributesImpl();
+            final NamedNodeMap map = node.getAttributes();
+            final int length = map.getLength();
+
+            // Process all namespace declarations
+            for (int i = 0; i < length; i++) {
+                final Node attr = map.item(i);
+                final String qnameAttr = attr.getNodeName();
+
+                // Ignore everything but NS declarations here
+                if (qnameAttr.startsWith(XMLNS_PREFIX)) {
+                    final String uriAttr = attr.getNodeValue();
+                    final int colon = qnameAttr.lastIndexOf(':');
+                    prefix = (colon > 0) ? qnameAttr.substring(colon + 1) : EMPTYSTRING;
+                    if (startPrefixMapping(prefix, uriAttr)) {
+                        pushedPrefixes.addElement(prefix);
+                    }
+                }
+            }
+
+            // Process all other attributes
+            for (int i = 0; i < length; i++) {
+                final Node attr = map.item(i);
+                String qnameAttr = attr.getNodeName();
+
+                // Ignore NS declarations here
+                if (!qnameAttr.startsWith(XMLNS_PREFIX)) {
+                    final String uriAttr = attr.getNamespaceURI();
+                    final String localNameAttr = getLocalName(attr);
+
+                    // Uri may be implicitly declared
+                    if (uriAttr != null) {
+                        final int colon = qnameAttr.lastIndexOf(':');
+                        if (colon > 0) {
+                            prefix = qnameAttr.substring(0, colon);
+                        }
+                        else {
+                            // If no prefix for this attr, we need to create
+                            // one because we cannot use the default ns
+                            prefix = BasisLibrary.generatePrefix();
+                            qnameAttr = prefix + ':' + qnameAttr;
+                        }
+                        if (startPrefixMapping(prefix, uriAttr)) {
+                            pushedPrefixes.addElement(prefix);
+                        }
+                    }
+
+                    // Add attribute to list
+                    attrs.addAttribute(attr.getNamespaceURI(), getLocalName(attr),
+                        qnameAttr, "CDATA", attr.getNodeValue());
+                }
+            }
+
+            // Now process the element itself
+            final String qname = node.getNodeName();
+            final String uri = node.getNamespaceURI();
+            final String localName = getLocalName(node);
+
+            // Uri may be implicitly declared
+            if (uri != null) {
+                final int colon = qname.lastIndexOf(':');
+                prefix = (colon > 0) ? qname.substring(0, colon) : EMPTYSTRING;
+                if (startPrefixMapping(prefix, uri)) {
+                    pushedPrefixes.addElement(prefix);
+                }
+            }
+
+            // Generate SAX event to start element
+            if (_saxImpl != null) {
+                _saxImpl.startElement(uri, localName, qname, attrs, node);
+            }
+            else {
+                _sax.startElement(uri, localName, qname, attrs);
+            }
+
+            // Traverse all child nodes of the element (if any)
+            next = node.getFirstChild();
+            while (next != null) {
+                parse(next);
+                next = next.getNextSibling();
+            }
+
+            // Generate SAX event to close element
+            _sax.endElement(uri, localName, qname);
+
+            // Generate endPrefixMapping() for all pushed prefixes
+            final int nPushedPrefixes = pushedPrefixes.size();
+            for (int i = 0; i < nPushedPrefixes; i++) {
+                endPrefixMapping((String) pushedPrefixes.elementAt(i));
+            }
+            break;
+
+        case Node.PROCESSING_INSTRUCTION_NODE:
+            _sax.processingInstruction(node.getNodeName(),
+                                       node.getNodeValue());
+            break;
+
+        case Node.TEXT_NODE:
+            final String data = node.getNodeValue();
+            _sax.characters(data.toCharArray(), 0, data.length());
+            break;
+        }
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public DTDHandler getDTDHandler() {
+        return null;
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public ErrorHandler getErrorHandler() {
+        return null;
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public boolean getFeature(String name) throws SAXNotRecognizedException,
+        SAXNotSupportedException
+    {
+        return false;
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public void setFeature(String name, boolean value) throws
+        SAXNotRecognizedException, SAXNotSupportedException
+    {
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public void parse(String sysId) throws IOException, SAXException {
+        throw new IOException("This method is not yet implemented.");
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public void setDTDHandler(DTDHandler handler) throws NullPointerException {
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public void setEntityResolver(EntityResolver resolver) throws
+        NullPointerException
+    {
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public EntityResolver getEntityResolver() {
+        return null;
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public void setErrorHandler(ErrorHandler handler) throws
+        NullPointerException
+    {
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public void setProperty(String name, Object value) throws
+        SAXNotRecognizedException, SAXNotSupportedException {
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public Object getProperty(String name) throws SAXNotRecognizedException,
+        SAXNotSupportedException
+    {
+        return null;
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public int getColumnNumber() {
+        return 0;
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public int getLineNumber() {
+        return 0;
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public String getPublicId() {
+        return null;
+    }
+
+    /**
+     * This class is only used internally so this method should never
+     * be called.
+     */
+    public String getSystemId() {
+        return null;
+    }
+
+    // Debugging
+    private String getNodeTypeFromCode(short code) {
+        String retval = null;
+        switch (code) {
+        case Node.ATTRIBUTE_NODE :
+            retval = "ATTRIBUTE_NODE"; break;
+        case Node.CDATA_SECTION_NODE :
+            retval = "CDATA_SECTION_NODE"; break;
+        case Node.COMMENT_NODE :
+            retval = "COMMENT_NODE"; break;
+        case Node.DOCUMENT_FRAGMENT_NODE :
+            retval = "DOCUMENT_FRAGMENT_NODE"; break;
+        case Node.DOCUMENT_NODE :
+            retval = "DOCUMENT_NODE"; break;
+        case Node.DOCUMENT_TYPE_NODE :
+            retval = "DOCUMENT_TYPE_NODE"; break;
+        case Node.ELEMENT_NODE :
+            retval = "ELEMENT_NODE"; break;
+        case Node.ENTITY_NODE :
+            retval = "ENTITY_NODE"; break;
+        case Node.ENTITY_REFERENCE_NODE :
+            retval = "ENTITY_REFERENCE_NODE"; break;
+        case Node.NOTATION_NODE :
+            retval = "NOTATION_NODE"; break;
+        case Node.PROCESSING_INSTRUCTION_NODE :
+            retval = "PROCESSING_INSTRUCTION_NODE"; break;
+        case Node.TEXT_NODE:
+            retval = "TEXT_NODE"; break;
+        }
+        return retval;
+    }
+}