Package client.net.sf.saxon.ce.event

Source Code of client.net.sf.saxon.ce.event.SequenceOutputter

package client.net.sf.saxon.ce.event;
import client.net.sf.saxon.ce.om.*;
import client.net.sf.saxon.ce.trans.XPathException;
import client.net.sf.saxon.ce.tree.iter.EmptyIterator;
import client.net.sf.saxon.ce.tree.iter.ListIterator;
import client.net.sf.saxon.ce.tree.util.Orphan;
import client.net.sf.saxon.ce.type.Type;
import client.net.sf.saxon.ce.value.AtomicValue;
import client.net.sf.saxon.ce.value.EmptySequence;
import client.net.sf.saxon.ce.value.SequenceExtent;
import client.net.sf.saxon.ce.Controller;

import java.util.ArrayList;


/**
* This outputter is used when writing a sequence of atomic values and nodes, that
* is, when xsl:variable is used with content and an "as" attribute. The outputter
* builds the sequence and provides access to it. (It isn't really an outputter at all,
* it doesn't pass the events to anyone, it merely constructs the sequence in memory
* and provides access to it). Note that the event sequence can include calls such as
* startElement and endElement that require trees to be built. If nodes such as attributes
* and text nodes are received while an element is being constructed, the nodes are added
* to the tree. Otherwise, "orphan" nodes (nodes with no parent) are created and added
* directly to the sequence.
*
* <p>This class is not used to build temporary trees. For that, the ComplexContentOutputter
* is used.</p>
*
*
* @author Michael H. Kay
*/

public final class SequenceOutputter extends SequenceReceiver {

    private ArrayList list;
    private Controller controller;  // enables the SequenceOutputter to be reused
    private Receiver outputter = null;
    private Builder builder = null;
    private int level = 0;
    private boolean inStartTag = false;


    public SequenceOutputter(Controller controller, int estimatedSize) {
      this.list = new ArrayList(estimatedSize);
        this.controller = controller;
  }

    /**
     * Clear the contents of the SequenceOutputter and make it available for reuse
     */

    public void reset() {
        list = new ArrayList(Math.max(list.size()+10, 50));
        if (controller != null && adviseReuse()) {
            controller.reuseSequenceOutputter(this);
        }
    }

    /**
     * Method to be supplied by subclasses: output one item in the sequence.
     */

    public void write(Item item) {
        list.add(item);
    }

    /**
    * Get the sequence that has been built
    */

    public ValueRepresentation getSequence() {
        switch (list.size()) {
            case 0:
                return EmptySequence.getInstance();
            case 1:
                return (Item)list.get(0);
            default:
                return new SequenceExtent(list);
        }
    }

    /**
     * Get an iterator over the sequence of items that has been constructed
     */

    public SequenceIterator iterate() {
        if (list.isEmpty()) {
            return EmptyIterator.getInstance();
        } else {
            return new ListIterator(list);
        }
    }

    /**
     * Get the list containing the sequence of items
     */

    public ArrayList getList() {
        return list;
    }

    /**
     * Get the first item in the sequence that has been built
     */

    public Item getFirstItem() {
        if (list.isEmpty()) {
            return null;
        } else {
            return (Item)list.get(0);
        }
    }

    /**
     * Get the last item in the sequence that has been built, and remove it
     */

    public Item popLastItem() {
        if (list.isEmpty()) {
            return null;
        } else {
            return (Item)list.remove(list.size()-1);
        }
    }


    /**
     * Start of a document node.
    */

    public void startDocument() throws XPathException {
        if (outputter==null) {
            createTree();
        }
        if (level++ == 0) {
            outputter.startDocument();
        }
    }

    /**
     * Create a tree to hold a document or element node.
     * @throws client.net.sf.saxon.ce.trans.XPathException
     */

    private void createTree() throws XPathException {
        PipelineConfiguration pipe = getPipelineConfiguration();

        builder = pipe.getController().makeBuilder();
        builder.setPipelineConfiguration(pipe);
        builder.setSystemId(getSystemId());

        NamespaceReducer reducer = new NamespaceReducer();
        reducer.setUnderlyingReceiver(builder);
        reducer.setPipelineConfiguration(getPipelineConfiguration());

        ComplexContentOutputter cco = new ComplexContentOutputter();
        cco.setPipelineConfiguration(getPipelineConfiguration());
        cco.setReceiver(reducer);
        outputter = cco;

        outputter.setSystemId(systemId);
        outputter.setPipelineConfiguration(getPipelineConfiguration());
        outputter.open();
    }

    /**
     * Decide whether reuse of the SequenceWriter is advisable
     * @return true if reuse is considered advisable
     */

    protected boolean adviseReuse() {
        return false;
        //return builder instanceof TinyBuilder && ((TinyBuilder)builder).getTree().getNumberOfNodes() < 20000;
    }

    /**
     * Notify the end of a document node
     */

    public void endDocument() throws XPathException {
        if (--level == 0) {
            outputter.endDocument();
            DocumentInfo doc = (DocumentInfo)builder.getCurrentRoot();
            // add the constructed document to the result sequence
            append(doc, NodeInfo.ALL_NAMESPACES);
        }
        previousAtomic = false;
    }

    /**
    * Output an element start tag.
    * @param nameCode The element name code - a code held in the Name Pool
     * @param properties bit-significant flags indicating any special information
     */

    public void startElement(int nameCode, int properties) throws XPathException {

        if (inStartTag) {
            startContent();
        }

        if (outputter==null) {
            createTree();
        }

        outputter.startElement(nameCode, properties);
        level++;
        inStartTag = true;
        previousAtomic = false;
    }

    /**
    * Output an element end tag.
    */

    public void endElement() throws XPathException {
        if (inStartTag) {
            startContent();
        }
        outputter.endElement();
        if (--level == 0) {
            outputter.close();
            NodeInfo element = builder.getCurrentRoot();
            append(element, NodeInfo.ALL_NAMESPACES);
        }
        previousAtomic = false;
    }

    /**
    * Output a namespace declaration. <br>
    * This is added to a list of pending namespaces for the current start tag.
    * If there is already another declaration of the same prefix, this one is
    * ignored.
    * Note that unlike SAX2 startPrefixMapping(), this call is made AFTER writing the start tag.
    * @param nsBinding The namespace code
    * @param properties Allows special properties to be passed if required
    * @throws client.net.sf.saxon.ce.trans.XPathException if there is no start tag to write to (created using writeStartTag),
    * or if character content has been written since the start tag was written.
    */

    public void namespace(NamespaceBinding nsBinding, int properties)
    throws XPathException {
        if (level == 0) {
            NamePool namePool = getNamePool();
            Orphan o = new Orphan(getConfiguration());
            o.setNodeKind(Type.NAMESPACE);
            o.setNameCode(namePool.allocate("", "", nsBinding.getPrefix()));
            o.setStringValue(nsBinding.getURI());
            append(o, NodeInfo.ALL_NAMESPACES);
        } else {
            outputter.namespace(nsBinding, properties);
        }
        previousAtomic = false;
    }

    /**
    * Output an attribute value. <br>
    * @param nameCode An integer code representing the name of the attribute, as held in the Name Pool
    * @param value The value of the attribute
    * @throws client.net.sf.saxon.ce.trans.XPathException if there is no start tag to write to (created using writeStartTag),
    * or if character content has been written since the start tag was written.
    */

    public void attribute(int nameCode, CharSequence value)
    throws XPathException {
        if (level == 0) {
            Orphan o = new Orphan(getConfiguration());
            o.setNodeKind(Type.ATTRIBUTE);
            o.setNameCode(nameCode);
            o.setStringValue(value);
            append(o, NodeInfo.ALL_NAMESPACES);
        } else {
            outputter.attribute(nameCode, value);
        }
        previousAtomic = false;
    }

    /**
    * The startContent() event is notified after all namespaces and attributes of an element
    * have been notified, and before any child nodes are notified.
    * @throws client.net.sf.saxon.ce.trans.XPathException for any failure
    */

    public void startContent() throws XPathException {
        inStartTag = false;
        outputter.startContent();
        previousAtomic = false;
    }

    /**
    * Produce text content output. <BR>
    * @param s The String to be output
    * @throws client.net.sf.saxon.ce.trans.XPathException for any failure
    */

    public void characters(CharSequence s) throws XPathException {
        if (level == 0) {
            Orphan o = new Orphan(getConfiguration());
            o.setNodeKind(Type.TEXT);
            o.setStringValue(s.toString());
            append(o, NodeInfo.ALL_NAMESPACES);
        } else {
            if (s.length() > 0) {
                if (inStartTag) {
                    startContent();
                }
                outputter.characters(s);
            }
        }
        previousAtomic = false;
    }

    /**
    * Write a comment.
    */

    public void comment(CharSequence comment) throws XPathException {
        if (inStartTag) {
            startContent();
        }
        if (level == 0) {
            Orphan o = new Orphan(getConfiguration());
            o.setNodeKind(Type.COMMENT);
            o.setStringValue(comment);
            append(o, NodeInfo.ALL_NAMESPACES);
        } else {
            outputter.comment(comment);
        }
        previousAtomic = false;
    }

    /**
    * Write a processing instruction
    * No-op in this implementation
    */

    public void processingInstruction(String target, CharSequence data) throws XPathException {
        if (inStartTag) {
            startContent();
        }
        if (level == 0) {
            Orphan o = new Orphan(getConfiguration());
            o.setNameCode(getNamePool().allocate("", "", target));
            o.setNodeKind(Type.PROCESSING_INSTRUCTION);
            o.setStringValue(data);
            append(o, NodeInfo.ALL_NAMESPACES);
        } else {
            outputter.processingInstruction(target, data);
        }
        previousAtomic = false;
    }

    /**
    * Close the output
    */

    public void close() throws XPathException {
        previousAtomic = false;
        if (outputter != null) {
            outputter.close();
        }
    }

    /**
    * Append an item to the sequence, performing any necessary type-checking and conversion
    */

    public void append(Item item, int copyNamespaces) throws XPathException {

        if (item==null) {
            return;
        }

        if (level==0) {
            write(item);
            previousAtomic = false;
        } else {
            if (item instanceof AtomicValue) {
                // If an atomic value is written to a tree, and the previous item was also
                // an atomic value, then add a single space to separate them
                if (previousAtomic) {
                    outputter.characters(" ");
                }
                outputter.characters(item.getStringValueCS());
                previousAtomic = true;
            } else {
                ((NodeInfo)item).copy(outputter, (CopyOptions.ALL_NAMESPACES | CopyOptions.TYPE_ANNOTATIONS));
                previousAtomic = false;
            }
        }
    }
}

// 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.
TOP

Related Classes of client.net.sf.saxon.ce.event.SequenceOutputter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.