net.sf.saxon.tinytree.TinyTreeEventIterator Maven / Gradle / Ivy
Show all versions of saxon9 Show documentation
package net.sf.saxon.tinytree;
import net.sf.saxon.evpull.*;
import net.sf.saxon.om.NamespaceDeclarationsImpl;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.type.Type;
/**
* This implementation of the Saxon event-pull interface starts from a document, element,
* text, comment, or processing-instruction node in a TinyTree,
* and returns the events corresponding to that node and its descendants (including
* their attributes and namespaces). The class performs the same function as
* the general-purpose {@link net.sf.saxon.evpull.Decomposer} class, but is
* specialized to exploit the TinyTree data structure: in particular, it never
* materializes any Node objects.
*/
public class TinyTreeEventIterator implements EventIterator {
private int startNodeNr;
private int currentNodeNr;
//private int currentEvent;
private int pendingEndEvents = 0;
private boolean startAtDocument = false;
private TinyTree tree;
//private PipelineConfiguration pipe;
private NamespaceDeclarationsImpl nsDeclarations;
private int[] nsBuffer = new int[10];
/**
* Create a TinyTreeEventIterator to return events associated with a tree or subtree
* @param startNode the root of the tree or subtree. Must be a document or element node.
* @throws IllegalArgumentException if the start node is an attribute or namespace node.
*/
public TinyTreeEventIterator(TinyNodeImpl startNode) {
int kind = startNode.getNodeKind();
if (kind != Type.DOCUMENT && kind != Type.ELEMENT) {
throw new IllegalArgumentException("TinyTreeEventIterator must start at a document or element node");
}
startNodeNr = startNode.nodeNr;
currentNodeNr = startNodeNr;
tree = startNode.tree;
pendingEndEvents = 0;
startAtDocument = (kind == Type.DOCUMENT);
nsDeclarations = new NamespaceDeclarationsImpl();
nsDeclarations.setNamePool(startNode.getNamePool());
}
/**
* Set configuration information. This must only be called before any events
* have been read.
* @param pipe the pipeline configuration
*/
// public void setPipelineConfiguration(PipelineConfiguration pipe) {
// this.pipe = pipe;
// }
/**
* Get configuration information.
* @return the pipeline configuration
*/
// public PipelineConfiguration getPipelineConfiguration() {
// return pipe;
// }
/**
* Get the next event
* @return a PullEvent object representing the next event, or null when the sequence is exhausted
*/
public PullEvent next() throws XPathException {
if (startNodeNr < 0) {
// this is a signal that we've finished
return null;
}
int thisDepth = tree.depth[currentNodeNr];
boolean lastNode = currentNodeNr + 1 >= tree.numberOfNodes;
int nextDepth = (lastNode ? 0 : tree.depth[currentNodeNr+1]);
boolean atEnd = (thisDepth == tree.depth[startNodeNr] && currentNodeNr != startNodeNr);
if (atEnd && pendingEndEvents == 1) {
pendingEndEvents--;
startNodeNr = -1;
if (startAtDocument) {
return EndDocumentEvent.getInstance();
} else {
return EndElementEvent.getInstance();
}
}
if (pendingEndEvents > 0) {
pendingEndEvents--;
return EndElementEvent.getInstance();
}
byte kind = tree.nodeKind[currentNodeNr];
switch (kind) {
case Type.DOCUMENT:
pendingEndEvents = thisDepth - nextDepth + 1;
currentNodeNr++;
return StartDocumentEvent.getInstance();
case Type.ELEMENT:
pendingEndEvents = thisDepth - nextDepth + 1;
StartElementEvent see = new StartElementEvent(tree.getConfiguration());
see.setNameCode(tree.nameCode[currentNodeNr]);
see.setTypeCode(tree.getTypeAnnotation(currentNodeNr));
// add the attributes
int index = tree.alpha[currentNodeNr];
if (index >= 0) {
while (index < tree.numberOfAttributes || tree.attParent[index] == currentNodeNr) {
see.addAttribute(tree.getAttributeNode(index++));
}
}
if (currentNodeNr == startNodeNr) {
// get all inscope namespaces for a top-level element in the sequence.
see.setLocalNamespaces(TinyElementImpl.getInScopeNamespaces(tree, currentNodeNr, nsBuffer));
} else {
// only namespace declarations (and undeclarations) on this element are required
see.setLocalNamespaces(TinyElementImpl.getDeclaredNamespaces(tree, currentNodeNr, nsBuffer));
}
currentNodeNr++;
return see;
case Type.TEXT:
case Type.WHITESPACE_TEXT:
case Type.COMMENT:
case Type.PROCESSING_INSTRUCTION:
pendingEndEvents = thisDepth - nextDepth;
return tree.getNode(currentNodeNr++);
case Type.PARENT_POINTER:
throw new IllegalStateException("First child node must not be a parent-pointer pseudo-node");
default:
throw new IllegalStateException("Unknown node kind " + tree.nodeKind[currentNodeNr]);
}
}
/**
* Get the attributes associated with the current element. This method must
* be called only after a START_ELEMENT event has been notified. The contents
* of the returned AttributeCollection are guaranteed to remain unchanged
* until the next START_ELEMENT event, but may be modified thereafter. The object
* should not be modified by the client.
*
* Attributes may be read before or after reading the namespaces of an element,
* but must not be read after the first child node has been read, or after calling
* one of the methods skipToEnd(), getStringValue(), or getTypedValue().
*
* @return an AttributeCollection representing the attributes of the element
* that has just been notified.
*/
// public AttributeCollection getAttributes() throws XPathException {
// if (tree.nodeKind[currentNodeNr] == Type.ELEMENT) {
// if (tree.alpha[currentNodeNr] == -1) {
// return AttributeCollectionImpl.EMPTY_ATTRIBUTE_COLLECTION;
// }
// return new TinyAttributeCollection(tree, currentNodeNr);
// } else {
// throw new IllegalStateException("getAttributes() called when current event is not ELEMENT_START");
// }
// }
/**
* Get the namespace declarations associated with the current element. This method must
* be called only after a START_ELEMENT event has been notified. In the case of a top-level
* START_ELEMENT event (that is, an element that either has no parent node, or whose parent
* is not included in the sequence being read), the NamespaceDeclarations object returned
* will contain a namespace declaration for each namespace that is in-scope for this element
* node. In the case of a non-top-level element, the NamespaceDeclarations will contain
* a set of namespace declarations and undeclarations, representing the differences between
* this element and its parent.
*
* It is permissible for this method to return namespace declarations that are redundant.
*
* The NamespaceDeclarations object is guaranteed to remain unchanged until the next START_ELEMENT
* event, but may then be overwritten. The object should not be modified by the client.
*
* Namespaces may be read before or after reading the attributes of an element,
* but must not be read after the first child node has been read, or after calling
* one of the methods skipToEnd(), getStringValue(), or getTypedValue().
*
*/
// public NamespaceDeclarations getNamespaceDeclarations() throws XPathException {
// if (tree.nodeKind[currentNodeNr] == Type.ELEMENT) {
// int[] decl;
// if (currentNodeNr == startNodeNr) {
// // get all inscope namespaces for a top-level element in the sequence.
// decl = TinyElementImpl.getInScopeNamespaces(tree, currentNodeNr, nsBuffer);
// } else {
// // only namespace declarations (and undeclarations) on this element are required
// decl = TinyElementImpl.getDeclaredNamespaces(tree, currentNodeNr, nsBuffer);
// }
// nsDeclarations.setNamespaceCodes(decl);
// return nsDeclarations;
// }
// throw new IllegalStateException("getNamespaceDeclarations() called when current event is not START_ELEMENT");
// }
/**
* Determine whether the EventIterator returns a flat sequence of events, or whether it can return
* nested event iterators
*
* @return true if the next() method is guaranteed never to return an EventIterator
*/
public boolean isFlatSequence() {
return true;
}
}
//
// The contents of this file are subject to the Mozilla Public License Version 1.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.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
// See the License for the specific language governing rights and limitations under the License.
//
// The Original Code is: all this file
//
// The Initial Developer of the Original Code is Michael H. Kay.
//
// Contributor(s):
//