net.sf.saxon.evpull.ComplexContentProcessor Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of saxon9 Show documentation
Show all versions of saxon9 Show documentation
Provides a basic XSLT 2.0 and XQuery 1.0 processor (W3C Recommendations,
January 2007). Command line interfaces and implementations of several
Java APIs (DOM, XPath, s9api) are also included.
The newest version!
package net.sf.saxon.evpull;
import net.sf.saxon.Configuration;
import net.sf.saxon.om.FastStringBuffer;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.om.Orphan;
import net.sf.saxon.trans.XPathException;
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;
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();
}
}
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(40);
sb.append(pendingTextNode.getStringValueCS());
sb.append(((NodeInfo)e).getStringValueCS());
o.setStringValue(sb);
pendingTextNode = o;
pendingTextNodeIsMutable = true;
}
continue;
default:
// TODO: handle attributes and namespaces
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(40);
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(40);
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;
int[] nsp = ((StartElementEvent)p).getLocalNamespaces();
for (int nspi = 0; nspi < nsp.length; nspi++) {
if (nsp[nspi] == -1) {
break;
}
retained++;
outer:
for (int i=depth-1; i>=0; i--) {
PullEvent q = startEventStack[i];
if (q instanceof StartElementEvent) {
int[] nsq = ((StartElementEvent)q).getLocalNamespaces();
for (int nsqi = 0; nsqi < nsq.length; nsqi++) {
if (nsp[nspi] == nsq[nsqi]) {
nsp[nspi] = -1;
retained--;
break outer;
} else if (nsp[nspi]>>16 == nsq[nsqi]>>16) {
break outer;
}
}
}
}
}
if (retained < nsp.length) {
int[] nsr = new int[retained];
int nsri = 0;
for (int nspi=0; nspi
© 2015 - 2025 Weber Informatics LLC | Privacy Policy