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

net.sf.saxon.evpull.ComplexContentProcessor 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.evpull;

import net.sf.saxon.Configuration;
import net.sf.saxon.om.NamespaceBinding;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.util.FastStringBuffer;
import net.sf.saxon.tree.util.Orphan;
import net.sf.saxon.type.Type;
import net.sf.saxon.value.AtomicValue;

/**
 * The ComplexContentProcessor is an EventIterator that deals with the events occurring between
 * a startElement and endElement (or startDocument and endDocument) according to the XSLT/XQuery
 * rules for constructing complex content. This includes:
 *
 * 
    *
  • Converting atomic values to text nodes (inserting space as a separator between adjacent nodes)
  • *
  • Replacing nested document nodes by their children
  • *
  • Merging adjacent text nodes and dropping zero-length text nodes
  • *
  • Detecting mispositioned or duplicated attribute and namespace nodes
  • * *
* *

Note that if the content includes nodes such as element nodes, these will not be decomposed into * a sequence of tree events, they will simply be returned as nodes.

*/ public class ComplexContentProcessor implements EventIterator { private Configuration config; private EventIterator base; private PullEvent[] startEventStack; // contains either startElement or startDocument events private int depth; private NodeInfo pendingTextNode; private boolean pendingTextNodeIsMutable; private boolean prevAtomic = false; private PullEvent pendingOutput = null; /** * Create the ComplexContentProcessor * @param config the Saxon Configuration * @param base the EventIterator that delivers the content of the element or document node */ public ComplexContentProcessor(Configuration config, EventIterator base) { this.config = config; this.base = EventStackIterator.flatten(base); startEventStack = new PullEvent[20]; depth = 0; } /** * Get the next event in the sequence. This will never be an EventIterator. * * @return the next event, or null when the sequence is exhausted * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { if (pendingOutput != null) { PullEvent next = pendingOutput; pendingOutput = null; return next; } else { return advance(); } } /*@Nullable*/ private PullEvent advance() throws XPathException { while (true) { if (depth == 0) { PullEvent e = base.next(); if (e instanceof StartElementEvent) { push(e); } else if (e instanceof StartDocumentEvent) { push(e); } return e; } else { PullEvent e = base.next(); if (e instanceof StartElementEvent) { prevAtomic = false; push(e); if (pendingTextNode != null) { pendingOutput = e; PullEvent next = pendingTextNode; pendingTextNode = null; return next; } else { return e; } } else if (e instanceof StartDocumentEvent) { prevAtomic = false; push(e); if (pendingTextNode != null) { pendingOutput = e; PullEvent next = pendingTextNode; pendingTextNode = null; return next; } else { //continue; } } else if (e instanceof EndElementEvent) { prevAtomic = false; pop(); if (pendingTextNode != null) { pendingOutput = e; PullEvent next = pendingTextNode; pendingTextNode = null; return next; } else { return e; } } else if (e instanceof EndDocumentEvent) { prevAtomic = false; pop(); if (pendingTextNode != null) { pendingOutput = e; PullEvent next = pendingTextNode; pendingTextNode = null; return next; } else { return e; } } else if (e instanceof NodeInfo) { prevAtomic = false; switch (((NodeInfo)e).getNodeKind()) { case Type.TEXT: if (pendingTextNode == null) { pendingTextNode = (NodeInfo)e; pendingTextNodeIsMutable = false; } else if (pendingTextNodeIsMutable) { FastStringBuffer sb = (FastStringBuffer)((Orphan)pendingTextNode).getStringValueCS(); sb.append(((NodeInfo)e).getStringValueCS()); } else { Orphan o = new Orphan(config); o.setNodeKind(Type.TEXT); FastStringBuffer sb = new FastStringBuffer(FastStringBuffer.SMALL); sb.append(pendingTextNode.getStringValueCS()); sb.append(((NodeInfo)e).getStringValueCS()); o.setStringValue(sb); pendingTextNode = o; pendingTextNodeIsMutable = true; } continue; default: if (pendingTextNode != null) { pendingOutput = e; PullEvent next = pendingTextNode; pendingTextNode = null; return next; } else { return e; } } } else if (e instanceof AtomicValue) { if (prevAtomic) { FastStringBuffer sb = (FastStringBuffer)((Orphan)pendingTextNode).getStringValueCS(); sb.append(' '); sb.append(((AtomicValue)e).getStringValueCS()); } else if (pendingTextNode != null) { prevAtomic = true; if (pendingTextNodeIsMutable) { FastStringBuffer sb = (FastStringBuffer)((Orphan)pendingTextNode).getStringValueCS(); sb.append(((AtomicValue)e).getStringValueCS()); } else { Orphan o = new Orphan(config); o.setNodeKind(Type.TEXT); FastStringBuffer sb = new FastStringBuffer(FastStringBuffer.SMALL); sb.append(pendingTextNode.getStringValueCS()); sb.append(((AtomicValue)e).getStringValueCS()); o.setStringValue(sb); pendingTextNode = o; pendingTextNodeIsMutable = true; } } else { prevAtomic = true; Orphan o = new Orphan(config); o.setNodeKind(Type.TEXT); FastStringBuffer sb = new FastStringBuffer(FastStringBuffer.SMALL); sb.append(((AtomicValue)e).getStringValueCS()); o.setStringValue(sb); pendingTextNode = o; pendingTextNodeIsMutable = true; } //continue; } else { throw new AssertionError("Unknown event"); } } } } /** * Push a startElement or startDocument event onto the stack. At the same time, if it is a startElement * event, remove any redundant namespace declarations * @param p the startElement or startDocument event */ private void push(PullEvent p) { if (depth >= startEventStack.length - 1) { PullEvent[] b2 = new PullEvent[depth*2]; System.arraycopy(startEventStack, 0, b2, 0, startEventStack.length); startEventStack = b2; } if (p instanceof StartElementEvent) { int retained = 0; NamespaceBinding[] nsp = ((StartElementEvent)p).getLocalNamespaces(); for (int nspi = 0; nspi < nsp.length; nspi++) { if (nsp[nspi] == null) { break; } retained++; outer: for (int i=depth-1; i>=0; i--) { PullEvent q = startEventStack[i]; if (q instanceof StartElementEvent) { NamespaceBinding[] nsq = ((StartElementEvent)q).getLocalNamespaces(); for (int nsqi = 0; nsqi < nsq.length; nsqi++) { if (nsp[nspi] == nsq[nsqi]) { nsp[nspi] = null; retained--; break outer; } else if (nsp[nspi].getPrefix().equals(nsq[nsqi].getPrefix())) { break outer; } } } } } if (retained < nsp.length) { NamespaceBinding[] nsr = new NamespaceBinding[retained]; int nsri = 0; for (int nspi=0; nspi




© 2015 - 2024 Weber Informatics LLC | Privacy Policy