All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.saxon.dom.DOMSender Maven / Gradle / Ivy

There is a newer version: 10.5
Show newest version
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2013 Saxonica Limited.
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.dom;

import net.sf.saxon.event.Receiver;
import net.sf.saxon.event.SaxonLocator;
import net.sf.saxon.event.SourceLocationProvider;
import net.sf.saxon.om.FingerprintedQName;
import net.sf.saxon.om.NameChecker;
import net.sf.saxon.om.NamespaceBinding;
import net.sf.saxon.om.NodeName;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.BuiltInAtomicType;
import net.sf.saxon.type.Untyped;
import org.w3c.dom.*;
import org.xml.sax.helpers.NamespaceSupport;

import java.util.HashMap;
import java.util.Map;

/**
* DOMSender.java: pseudo-SAX driver for a DOM source document.
* This class takes an existing
* DOM Document and walks around it in a depth-first traversal,
* calling a Receiver to process the nodes as it does so
*/

public class DOMSender implements SaxonLocator, SourceLocationProvider {
    /*@NotNull*/ private Receiver receiver;
    /*@NotNull*/ protected Node root;
    private NamespaceSupport nsSupport = new NamespaceSupport();
    private String[] parts = new String[3];
    private String[] elparts = new String[3];
    private HashMap nsDeclarations = new HashMap(10);
    protected String systemId;

    /**
     * Create a DOMSender that will send events representing the nodes in a tree
     * to a nominated receiver
     * @param startNode the root node of the tree to be send. Usually a document or element node.
     * @param receiver the object to be notified of the resulting events. The supplied Receiver must
     * be initialized with a PipelineConfiguration.The PipelineConfiguration
     * of the Receiver will be modified to set this DOMSender as its LocationProvider.
     */

    public DOMSender(Node startNode, Receiver receiver) {
        if (startNode == null) {
            throw new NullPointerException("startNode");
        }
        if (receiver == null) {
            throw new NullPointerException("receiver");
        }
        this.root = startNode;
        this.receiver = receiver;
    }

   /**
     * Set the systemId of the source document (which will also be
     * used for the destination)
     * @param systemId the systemId of the source document
    */

    public void setSystemId(String systemId) {
        this.systemId = systemId;
    }

    /**
     * Walk a tree (traversing the nodes depth first).
     * @throws IllegalStateException if the
     * start node is of a node kind other than document, document fragment, element, text,
     * comment, or processing instruction (for example, if it is an attribute node).
     * @throws net.sf.saxon.trans.XPathException On any error in the document
    */

    public void send() throws XPathException {
        receiver.setSystemId(systemId);
        receiver.getPipelineConfiguration().setLocationProvider(this);

        receiver.open();
        switch (root.getNodeType()) {
            case Node.DOCUMENT_NODE:
            case Node.DOCUMENT_FRAGMENT_NODE:
                receiver.startDocument(0);
                walkNode(root);
                receiver.endDocument();
                break;
            case Node.ELEMENT_NODE:
                sendElement((Element)root);
                break;
            case Node.TEXT_NODE:
            case Node.CDATA_SECTION_NODE:
                receiver.characters(((CharacterData)root).getData(), 0, 0);
                break;
            case Node.COMMENT_NODE:
                receiver.comment(((Comment)root).getData(), 0, 0);
                break;
            case Node.PROCESSING_INSTRUCTION_NODE:
                receiver.processingInstruction(
                        ((ProcessingInstruction)root).getTarget(),
                        ((ProcessingInstruction)root).getData(), 0, 0);
                break;
            default:
                throw new IllegalStateException("DOMSender: unsupported kind of start node (" + root.getNodeType() + ")");
        }
        receiver.close();
    }

    /**
     * Walk a tree starting from a particular element node. This has to make
     * sure that all the namespace declarations in scope for the element are
     * treated as if they were namespace declarations on the element itself.
     * @param startNode the start element node from which the walk will start
     * @throws net.sf.saxon.trans.XPathException if a dynamic error occurs
     */

    private void sendElement(Element startNode) throws XPathException {
        Element node = startNode;
        boolean hasNamespaceDeclarations = gatherNamespaces(node, false);
        while (true) {
            gatherNamespaces(node, true);
            Node parent = node.getParentNode();
            if (parent != null && parent.getNodeType() == Node.ELEMENT_NODE) {
                node = (Element)parent;
            } else {
                break;
            }
        }
        outputElement(startNode, hasNamespaceDeclarations);
    }

  /**
    * Walk an element of a document (traversing the children depth first)
    * @param node The DOM Element object to walk
    * @exception net.sf.saxon.trans.XPathException On any error in the document
    *
    */

    private void walkNode (Node node) throws XPathException {
        // See https://saxonica.plan.io/issues/1955
        if (node.hasChildNodes()) {
            for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
                switch (child.getNodeType()) {
                    case Node.DOCUMENT_NODE:
                    case Node.DOCUMENT_FRAGMENT_NODE:
                        break;                  // should not happen
                    case Node.ELEMENT_NODE:
                        Element element = (Element)child;
                        boolean hasNamespaces = gatherNamespaces(element, false);
                        outputElement(element, hasNamespaces);
                        nsSupport.popContext();
                        break;
                    case Node.ATTRIBUTE_NODE:        // have already dealt with attributes
                        break;
                    case Node.PROCESSING_INSTRUCTION_NODE:
                        receiver.processingInstruction(
                            ((ProcessingInstruction)child).getTarget(),
                            ((ProcessingInstruction)child).getData(),
                                0, 0);
                        break;
                    case Node.COMMENT_NODE: {
                        String text = ((Comment)child).getData();
                        if (text!=null) {
                            receiver.comment(text, 0, 0);
                        }
                        break;
                    }
                    case Node.TEXT_NODE:
                    case Node.CDATA_SECTION_NODE: {
                        String text = ((CharacterData)child).getData();
                        if (text!=null) {
                            receiver.characters(text, 0, 0);
                        }
                        break;
                    }
                    case Node.ENTITY_REFERENCE_NODE:
                        walkNode(child);
                        break;
                    default:
                        break;                  // should not happen
                }
            }
        }

    }

    private void outputElement(Element element, boolean hasNamespaceDeclarations) throws XPathException {
        String[] elparts2 = nsSupport.processName(element.getTagName(), elparts, false);
        if (elparts2==null) {
              throw new XPathException("Undeclared namespace in " + element.getTagName());
        }
        String uri = elparts2[0];
        String local = elparts2[1];
        String prefix = NameChecker.getPrefix(elparts2[2]);

        receiver.startElement(new FingerprintedQName(prefix, uri, local), Untyped.getInstance(), 0, 0);
        for (Map.Entry decl : nsDeclarations.entrySet()) {
            receiver.namespace(new NamespaceBinding(decl.getKey(), decl.getValue()), 0);
        }

        NamedNodeMap atts = element.getAttributes();
        if (atts != null) {
            final int len = atts.getLength();
            for (int a2=0; a2
            


© 2015 - 2024 Weber Informatics LLC | Privacy Policy