| /* |
| * The Apache Software License, Version 1.1 |
| * |
| * |
| * Copyright (c) 1999 The Apache Software Foundation. All rights |
| * reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in |
| * the documentation and/or other materials provided with the |
| * distribution. |
| * |
| * 3. The end-user documentation included with the redistribution, |
| * if any, must include the following acknowledgment: |
| * "This product includes software developed by the |
| * Apache Software Foundation (http://www.apache.org/)." |
| * Alternately, this acknowledgment may appear in the software itself, |
| * if and wherever such third-party acknowledgments normally appear. |
| * |
| * 4. The names "Xalan" and "Apache Software Foundation" must |
| * not be used to endorse or promote products derived from this |
| * software without prior written permission. For written |
| * permission, please contact apache@apache.org. |
| * |
| * 5. Products derived from this software may not be called "Apache", |
| * nor may "Apache" appear in their name, without prior written |
| * permission of the Apache Software Foundation. |
| * |
| * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
| * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR |
| * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
| * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| * SUCH DAMAGE. |
| * ==================================================================== |
| * |
| * This software consists of voluntary contributions made by many |
| * individuals on behalf of the Apache Software Foundation and was |
| * originally based on software copyright (c) 1999, Lotus |
| * Development Corporation., http://www.lotus.com. For more |
| * information on the Apache Software Foundation, please see |
| * <http://www.apache.org/>. |
| */ |
| package org.apache.xml.dtm.ref; |
| |
| import org.apache.xml.dtm.*; |
| import org.w3c.dom.*; |
| |
| import org.xml.sax.*; |
| import org.xml.sax.ext.LexicalHandler; |
| |
| import org.apache.xml.utils.NodeConsumer; |
| import org.apache.xml.utils.XMLString; |
| |
| /** |
| * <meta name="usage" content="advanced"/> |
| * This class does a pre-order walk of the DTM tree, calling a ContentHandler |
| * interface as it goes. As such, it's more like the Visitor design pattern |
| * than like the DOM's TreeWalker. |
| * |
| * I think normally this class should not be needed, because |
| * of DTM#dispatchToEvents. |
| */ |
| public class DTMTreeWalker |
| { |
| |
| /** Local reference to a ContentHandler */ |
| private ContentHandler m_contentHandler = null; |
| |
| /** DomHelper for this TreeWalker */ |
| protected DTM m_dtm; |
| |
| /** |
| * Set the DTM to be traversed. |
| * |
| * @param dtm The Document Table Model to be used. |
| */ |
| public void setDTM(DTM dtm) |
| { |
| m_dtm = dtm; |
| } |
| |
| /** |
| * Get the ContentHandler used for the tree walk. |
| * |
| * @return the ContentHandler used for the tree walk |
| */ |
| public ContentHandler getcontentHandler() |
| { |
| return m_contentHandler; |
| } |
| |
| /** |
| * Set the ContentHandler used for the tree walk. |
| * |
| * @param ch the ContentHandler to be the result of the tree walk. |
| */ |
| public void setcontentHandler(ContentHandler ch) |
| { |
| m_contentHandler = ch; |
| } |
| |
| |
| /** |
| * Constructor. |
| * @param contentHandler The implemention of the |
| * contentHandler operation (toXMLString, digest, ...) |
| */ |
| public DTMTreeWalker() |
| { |
| } |
| |
| /** |
| * Constructor. |
| * @param contentHandler The implemention of the |
| * contentHandler operation (toXMLString, digest, ...) |
| */ |
| public DTMTreeWalker(ContentHandler contentHandler, DTM dtm) |
| { |
| this.m_contentHandler = contentHandler; |
| m_dtm = dtm; |
| } |
| |
| /** Perform a non-recursive pre-order/post-order traversal, |
| * operating as a Visitor. startNode (preorder) and endNode |
| * (postorder) are invoked for each node as we traverse over them, |
| * with the result that the node is written out to m_contentHandler. |
| * |
| * @param pos Node in the tree at which to start (and end) traversal -- |
| * in other words, the root of the subtree to traverse over. |
| * |
| * @throws TransformerException */ |
| public void traverse(int pos) throws org.xml.sax.SAXException |
| { |
| // %REVIEW% Why isn't this just traverse(pos,pos)? |
| |
| int top = pos; // Remember the root of this subtree |
| |
| while (DTM.NULL != pos) |
| { |
| startNode(pos); |
| int nextNode = m_dtm.getFirstChild(pos); |
| while (DTM.NULL == nextNode) |
| { |
| endNode(pos); |
| |
| if (top == pos) |
| break; |
| |
| nextNode = m_dtm.getNextSibling(pos); |
| |
| if (DTM.NULL == nextNode) |
| { |
| pos = m_dtm.getParent(pos); |
| |
| if ((DTM.NULL == pos) || (top == pos)) |
| { |
| // %REVIEW% This condition isn't tested in traverse(pos,top) |
| // -- bug? |
| if (DTM.NULL != pos) |
| endNode(pos); |
| |
| nextNode = DTM.NULL; |
| |
| break; |
| } |
| } |
| } |
| |
| pos = nextNode; |
| } |
| } |
| |
| /** Perform a non-recursive pre-order/post-order traversal, |
| * operating as a Visitor. startNode (preorder) and endNode |
| * (postorder) are invoked for each node as we traverse over them, |
| * with the result that the node is written out to m_contentHandler. |
| * |
| * @param pos Node in the tree where to start traversal |
| * @param top Node in the tree where to end traversal. |
| * If top==DTM.NULL, run through end of document. |
| * |
| * @throws TransformerException |
| */ |
| public void traverse(int pos, int top) throws org.xml.sax.SAXException |
| { |
| // %OPT% Can we simplify the loop conditionals by adding: |
| // if(top==DTM.NULL) top=0 |
| // -- or by simply ignoring this case and relying on the fact that |
| // pos will never equal DTM.NULL until we're ready to exit? |
| |
| while (DTM.NULL != pos) |
| { |
| startNode(pos); |
| int nextNode = m_dtm.getFirstChild(pos); |
| while (DTM.NULL == nextNode) |
| { |
| endNode(pos); |
| |
| if ((DTM.NULL != top) && top == pos) |
| break; |
| |
| nextNode = m_dtm.getNextSibling(pos); |
| |
| if (DTM.NULL == nextNode) |
| { |
| pos = m_dtm.getParent(pos); |
| |
| if ((DTM.NULL == pos) || ((DTM.NULL != top) && (top == pos))) |
| { |
| nextNode = DTM.NULL; |
| |
| break; |
| } |
| } |
| } |
| |
| pos = nextNode; |
| } |
| } |
| |
| /** Flag indicating whether following text to be processed is raw text */ |
| boolean nextIsRaw = false; |
| |
| /** |
| * Optimized dispatch of characters. |
| */ |
| private final void dispatachChars(int node) |
| throws org.xml.sax.SAXException |
| { |
| m_dtm.dispatchCharactersEvents(node, m_contentHandler, false); |
| } |
| |
| /** |
| * Start processing given node |
| * |
| * |
| * @param node Node to process |
| * |
| * @throws org.xml.sax.SAXException |
| */ |
| protected void startNode(int node) throws org.xml.sax.SAXException |
| { |
| |
| if (m_contentHandler instanceof NodeConsumer) |
| { |
| // %TBD% |
| // ((NodeConsumer) m_contentHandler).setOriginatingNode(node); |
| } |
| |
| switch (m_dtm.getNodeType(node)) |
| { |
| case DTM.COMMENT_NODE : |
| { |
| XMLString data = m_dtm.getStringValue(node); |
| |
| if (m_contentHandler instanceof LexicalHandler) |
| { |
| LexicalHandler lh = ((LexicalHandler) this.m_contentHandler); |
| data.dispatchAsComment(lh); |
| } |
| } |
| break; |
| case DTM.DOCUMENT_FRAGMENT_NODE : |
| |
| // ??; |
| break; |
| case DTM.DOCUMENT_NODE : |
| this.m_contentHandler.startDocument(); |
| break; |
| case DTM.ELEMENT_NODE : |
| DTM dtm = m_dtm; |
| |
| for (int nsn = dtm.getFirstNamespaceNode(node, true); DTM.NULL != nsn; |
| nsn = dtm.getNextNamespaceNode(node, nsn, true)) |
| { |
| // String prefix = dtm.getPrefix(nsn); |
| String prefix = dtm.getNodeNameX(nsn); |
| |
| this.m_contentHandler.startPrefixMapping(prefix, dtm.getNodeValue(nsn)); |
| |
| } |
| |
| // System.out.println("m_dh.getNamespaceOfNode(node): "+m_dh.getNamespaceOfNode(node)); |
| // System.out.println("m_dh.getLocalNameOfNode(node): "+m_dh.getLocalNameOfNode(node)); |
| String ns = dtm.getNamespaceURI(node); |
| if(null == ns) |
| ns = ""; |
| |
| // %OPT% !! |
| org.xml.sax.helpers.AttributesImpl attrs = |
| new org.xml.sax.helpers.AttributesImpl(); |
| |
| for (int i = dtm.getFirstAttribute(node); |
| i != DTM.NULL; |
| i = dtm.getNextAttribute(i)) |
| { |
| attrs.addAttribute(dtm.getNamespaceURI(i), |
| dtm.getLocalName(i), |
| dtm.getNodeName(i), |
| "CDATA", |
| dtm.getNodeValue(i)); |
| } |
| |
| |
| this.m_contentHandler.startElement(ns, |
| m_dtm.getLocalName(node), |
| m_dtm.getNodeName(node), |
| attrs); |
| break; |
| case DTM.PROCESSING_INSTRUCTION_NODE : |
| { |
| String name = m_dtm.getNodeName(node); |
| |
| // String data = pi.getData(); |
| if (name.equals("xslt-next-is-raw")) |
| { |
| nextIsRaw = true; |
| } |
| else |
| { |
| this.m_contentHandler.processingInstruction(name, |
| m_dtm.getNodeValue(node)); |
| } |
| } |
| break; |
| case DTM.CDATA_SECTION_NODE : |
| { |
| boolean isLexH = (m_contentHandler instanceof LexicalHandler); |
| LexicalHandler lh = isLexH |
| ? ((LexicalHandler) this.m_contentHandler) : null; |
| |
| if (isLexH) |
| { |
| lh.startCDATA(); |
| } |
| |
| dispatachChars(node); |
| |
| { |
| if (isLexH) |
| { |
| lh.endCDATA(); |
| } |
| } |
| } |
| break; |
| case DTM.TEXT_NODE : |
| { |
| if (nextIsRaw) |
| { |
| nextIsRaw = false; |
| |
| m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING, ""); |
| dispatachChars(node); |
| m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_ENABLE_OUTPUT_ESCAPING, ""); |
| } |
| else |
| { |
| dispatachChars(node); |
| } |
| } |
| break; |
| case DTM.ENTITY_REFERENCE_NODE : |
| { |
| if (m_contentHandler instanceof LexicalHandler) |
| { |
| ((LexicalHandler) this.m_contentHandler).startEntity( |
| m_dtm.getNodeName(node)); |
| } |
| else |
| { |
| |
| // warning("Can not output entity to a pure SAX ContentHandler"); |
| } |
| } |
| break; |
| default : |
| } |
| } |
| |
| /** |
| * End processing of given node |
| * |
| * |
| * @param node Node we just finished processing |
| * |
| * @throws org.xml.sax.SAXException |
| */ |
| protected void endNode(int node) throws org.xml.sax.SAXException |
| { |
| |
| switch (m_dtm.getNodeType(node)) |
| { |
| case DTM.DOCUMENT_NODE : |
| this.m_contentHandler.endDocument(); |
| break; |
| case DTM.ELEMENT_NODE : |
| String ns = m_dtm.getNamespaceURI(node); |
| if(null == ns) |
| ns = ""; |
| this.m_contentHandler.endElement(ns, |
| m_dtm.getLocalName(node), |
| m_dtm.getNodeName(node)); |
| |
| for (int nsn = m_dtm.getFirstNamespaceNode(node, true); DTM.NULL != nsn; |
| nsn = m_dtm.getNextNamespaceNode(node, nsn, true)) |
| { |
| // String prefix = m_dtm.getPrefix(nsn); |
| String prefix = m_dtm.getNodeNameX(nsn); |
| |
| this.m_contentHandler.endPrefixMapping(prefix); |
| } |
| break; |
| case DTM.CDATA_SECTION_NODE : |
| break; |
| case DTM.ENTITY_REFERENCE_NODE : |
| { |
| if (m_contentHandler instanceof LexicalHandler) |
| { |
| LexicalHandler lh = ((LexicalHandler) this.m_contentHandler); |
| |
| lh.endEntity(m_dtm.getNodeName(node)); |
| } |
| } |
| break; |
| default : |
| } |
| } |
| } //TreeWalker |
| |