saxonhe-9.4.0.7/src/main/java/0000755000175000017500000000000012213124740015640 5ustar mathieumathieusaxonhe-9.4.0.7/src/main/java/net/0000755000175000017500000000000012213124633016427 5ustar mathieumathieusaxonhe-9.4.0.7/src/main/java/net/sf/0000755000175000017500000000000012213124633017037 5ustar mathieumathieusaxonhe-9.4.0.7/src/main/java/net/sf/saxon/0000755000175000017500000000000012213124737020174 5ustar mathieumathieusaxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/0000755000175000017500000000000012213124725021500 5ustar mathieumathieusaxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/EventMappingIterator.java0000644000175000017500000000450211671711573026465 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * MappingIterator merges a sequence of sequences into a single sequence. * It takes as inputs an iteration, and a mapping function to be * applied to each Item returned by that iteration. The mapping function itself * returns another iteration. The result is an iteration of iterators. To convert this * int a single flat iterator over a uniform sequence of events, the result must be wrapped * in an {@link EventStackIterator}

*/ public final class EventMappingIterator implements EventIterator { private SequenceIterator base; private EventMappingFunction action; /** * Construct a MappingIterator that will apply a specified MappingFunction to * each Item returned by the base iterator. * @param base the base iterator * @param action the mapping function to be applied */ public EventMappingIterator(SequenceIterator base, EventMappingFunction action) { this.base = base; this.action = action; } /*@Nullable*/ public PullEvent next() throws XPathException { Item nextSource = base.next(); return (nextSource == null ? null : action.map(nextSource)); } /** * 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 false; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/EndElementEvent.java0000644000175000017500000000206311671711573025400 0ustar mathieumathieupackage net.sf.saxon.evpull; /** * Pull event representing the end of an element node */ public class EndElementEvent implements PullEvent { private final static EndElementEvent THE_INSTANCE = new EndElementEvent(); public static EndElementEvent getInstance() { return THE_INSTANCE; } private EndElementEvent() { } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/PullEventTracer.java0000644000175000017500000001216011671711573025434 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.util.FastStringBuffer; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import javax.xml.transform.stream.StreamSource; import java.io.File; import java.io.PrintStream; /** * Diagnostic class to display the sequence of events reported by an EventIterator */ public class PullEventTracer implements EventIterator { private EventIterator base; private String label = ("PET" + hashCode()).substring(0, 8) + ": "; private PrintStream out; //@SuppressWarnings({"FieldCanBeLocal"}) private NamePool pool; /** * Create a tracer for pull events * @param base the event iterator whose events are to be traced * @param config the Saxon configuration */ public PullEventTracer(EventIterator base, Configuration config) { this.base = base; pool = config.getNamePool(); out = config.getStandardErrorOutput(); } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ /*@Nullable*/ public PullEvent next() throws XPathException { PullEvent pe = base.next(); if (pe == null) { return null; } if (pe instanceof StartDocumentEvent) { out.println(label + "StartDocument"); label = " " + label; } else if (pe instanceof StartElementEvent) { out.println(label + "StartElement " + ((StartElementEvent)pe).getElementName().getDisplayName()); label = " " + label; } else if (pe instanceof EndDocumentEvent) { label = label.substring(2); out.println(label + "EndDocument"); } else if (pe instanceof EndElementEvent) { label = label.substring(2); out.println(label + "EndElement"); } else if (pe instanceof NodeInfo) { FastStringBuffer fsb = new FastStringBuffer(FastStringBuffer.SMALL); fsb.append(label); int kind = ((NodeInfo)pe).getNodeKind(); fsb.append(NodeKindTest.toString(kind)); if (kind == Type.ELEMENT || kind == Type.ATTRIBUTE) { fsb.append(' '); fsb.append(((NodeInfo)pe).getDisplayName()); } fsb.append(" \""); fsb.append(((NodeInfo)pe).getStringValueCS()); fsb.append('"'); out.println(fsb.toString()); } else if (pe instanceof AtomicValue) { out.println(label + Type.displayTypeName((AtomicValue)pe) + ' ' + pe); } else if (pe instanceof EventIterator) { out.println(label + "** NESTED ITERATOR **"); } else { out.println(label + pe.getClass().getName()); } return pe; } /** * 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 base.isFlatSequence(); } /** * Main method for testing only * @param args not used * @throws Exception */ public static void main(String[] args) throws Exception { Configuration config = new Configuration(); DocumentInfo doc = config.buildDocument(new StreamSource(new File("c:/MyJava/samples/data/books.xml"))); PipelineConfiguration pipe = config.makePipelineConfiguration(); pipe.setHostLanguage(Configuration.XQUERY); EventIterator e = new Decomposer(new SingletonEventIterator(doc), pipe); e = EventStackIterator.flatten(e); e = new PullEventTracer(e, config); while (true) { PullEvent pe = e.next(); if (pe == null) { break; } } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/StaxToEventBridge.java0000644000175000017500000005275211671711573025731 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.Configuration; import net.sf.saxon.event.NamespaceReducer; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.SaxonLocator; import net.sf.saxon.event.SourceLocationProvider; import net.sf.saxon.expr.parser.ExpressionLocation; import net.sf.saxon.om.FingerprintedQName; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NoNamespaceName; import net.sf.saxon.pull.UnparsedEntity; import net.sf.saxon.serialize.XMLEmitter; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.tiny.CharSlice; import net.sf.saxon.tree.util.Orphan; import net.sf.saxon.type.Type; import net.sf.saxon.type.Untyped; import net.sf.saxon.value.Whitespace; import javax.xml.stream.*; import javax.xml.stream.events.EntityDeclaration; import javax.xml.transform.TransformerException; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.List; import java.util.Properties; /** * This class implements the Saxon EventIterator API on top of a standard StAX parser * (or any other StAX XMLStreamReader implementation) */ public class StaxToEventBridge implements EventIterator, SaxonLocator, SourceLocationProvider { private Configuration config; private XMLStreamReader reader; private PipelineConfiguration pipe; /*@Nullable*/ private List unparsedEntities = null; PullEvent currentEvent = null; int depth = 0; boolean ignoreIgnorable = false; /** * Create a new instance of the class */ public StaxToEventBridge() { } /** * Supply an input stream containing XML to be parsed. A StAX parser is created using * the JAXP XMLInputFactory. * @param systemId The Base URI of the input document * @param inputStream the stream containing the XML to be parsed * @throws net.sf.saxon.trans.XPathException if an error occurs creating the StAX parser */ public void setInputStream(String systemId, InputStream inputStream) throws XPathException { try { XMLInputFactory factory = XMLInputFactory.newInstance(); //XMLInputFactory factory = new WstxInputFactory(); factory.setXMLReporter(new StaxErrorReporter()); reader = factory.createXMLStreamReader(systemId, inputStream); } catch (XMLStreamException e) { throw new XPathException(e); } } /** * Supply an XMLStreamReader: the events reported by this XMLStreamReader will be translated * into EventIterator events * @param reader the supplier of XML events, typically an XML parser */ public void setXMLStreamReader(XMLStreamReader reader) { this.reader = reader; } /** * 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 = new PipelineConfiguration(pipe); this.pipe.setLocationProvider(this); config = pipe.getConfiguration(); ignoreIgnorable = config.getStripsWhiteSpace() != Whitespace.NONE; } /** * Get configuration information. * @return the pipeline configuration */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Get the XMLStreamReader used by this StaxBridge. This is available only after * setInputStream() or setXMLStreamReader() has been called * @return the instance of XMLStreamReader allocated when setInputStream() was called, * or the instance supplied directly to setXMLStreamReader() */ public XMLStreamReader getXMLStreamReader() { return reader; } /** * Get the name pool * @return the name pool */ public NamePool getNamePool() { return pipe.getConfiguration().getNamePool(); } /** * Get the next event * @return the next event; or null to indicate the end of the event stream */ public PullEvent next() throws XPathException { if (currentEvent == null) { // StAX isn't reporting START_DOCUMENT so we supply it ourselves currentEvent = StartDocumentEvent.getInstance(); return currentEvent; } if (currentEvent instanceof EndDocumentEvent) { try { reader.close(); } catch (XMLStreamException e) { // } return null; } try { if (reader.hasNext()) { int event = reader.next(); //System.err.println("Read event " + event); currentEvent = translate(event); } else { currentEvent = null; } } catch (XMLStreamException e) { String message = e.getMessage(); // Following code recognizes the messages produced by the Sun Zephyr parser if (message.startsWith("ParseError at")) { int c = message.indexOf("\nMessage: "); if (c > 0) { message = message.substring(c + 10); } } XPathException err = new XPathException("Error reported by XML parser: " + message); err.setErrorCode(SaxonErrorCode.SXXP0003); err.setLocator(translateLocation(e.getLocation())); throw err; } return currentEvent; } /** * Translate a StAX event into a Saxon PullEvent * @param event the StAX event * @return the Saxon PullEvent * @throws XPathException */ private PullEvent translate(int event) throws XPathException { //System.err.println("EVENT " + event); switch (event) { case XMLStreamConstants.ATTRIBUTE: return next(); // attributes are reported as part of StartElement case XMLStreamConstants.CDATA: case XMLStreamConstants.CHARACTERS: if (depth == 0 && reader.isWhiteSpace()) { return next(); } else { Orphan o = new Orphan(config); o.setNodeKind(Type.TEXT); CharSlice value = new CharSlice( reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()); o.setStringValue(value); return o; } case XMLStreamConstants.COMMENT: { Orphan o = new Orphan(config); o.setNodeKind(Type.COMMENT); CharSlice value = new CharSlice( reader.getTextCharacters(), reader.getTextStart(), reader.getTextLength()); o.setStringValue(value); return o; } case XMLStreamConstants.DTD: unparsedEntities = (List)reader.getProperty("javax.xml.stream.entities"); return next(); case XMLStreamConstants.END_DOCUMENT: return EndDocumentEvent.getInstance(); case XMLStreamConstants.END_ELEMENT: depth--; return EndElementEvent.getInstance(); case XMLStreamConstants.ENTITY_DECLARATION: return next(); case XMLStreamConstants.ENTITY_REFERENCE: return next(); case XMLStreamConstants.NAMESPACE: return next(); // namespaces are reported as part of StartElement case XMLStreamConstants.NOTATION_DECLARATION: return next(); case XMLStreamConstants.PROCESSING_INSTRUCTION:{ Orphan o = new Orphan(config); o.setNodeKind(Type.PROCESSING_INSTRUCTION); String local = reader.getPITarget(); o.setNodeName(new NoNamespaceName(local)); o.setStringValue(reader.getText()); return o; } case XMLStreamConstants.SPACE: if (depth == 0) { return next(); } else if (ignoreIgnorable) { // (Brave attempt, but Woodstox doesn't seem to report ignorable whitespace) return next(); } else { Orphan o = new Orphan(config); o.setNodeKind(Type.TEXT); o.setStringValue(reader.getText()); return o; } case XMLStreamConstants.START_DOCUMENT: return next(); // we supplied the START_DOCUMENT ourselves case XMLStreamConstants.START_ELEMENT: depth++; StartElementEvent see = new StartElementEvent(pipe); String elocal = reader.getLocalName(); String euri = reader.getNamespaceURI(); String eprefix = reader.getPrefix(); if (eprefix == null) { eprefix = ""; } if (euri == null) { euri = ""; } see.setElementName(new FingerprintedQName(eprefix, euri, elocal)); see.setTypeCode(Untyped.getInstance()); int attCount = reader.getAttributeCount(); for (int index=0; index *

The return value is the public identifier of the document * entity or of the external parsed entity in which the markup * triggering the event appears.

* * @return A string containing the public identifier, or * null if none is available. * @see #getSystemId */ public String getPublicId() { return reader.getLocation().getPublicId(); } /** * Return the system identifier for the current document event. *

*

The return value is the system identifier of the document * entity or of the external parsed entity in which the markup * triggering the event appears.

*

*

If the system identifier is a URL, the parser must resolve it * fully before passing it to the application. For example, a file * name must always be provided as a file:... URL, and other * kinds of relative URI are also resolved against their bases.

* * @return A string containing the system identifier, or null * if none is available. * @see #getPublicId */ public String getSystemId() { return reader.getLocation().getSystemId(); } /** * Return the line number where the current document event ends. * Lines are delimited by line ends, which are defined in * the XML specification. *

*

Warning: The return value from the method * is intended only as an approximation for the sake of diagnostics; * it is not intended to provide sufficient information * to edit the character content of the original XML document. * In some cases, these "line" numbers match what would be displayed * as columns, and in others they may not match the source text * due to internal entity expansion.

*

*

The return value is an approximation of the line number * in the document entity or external parsed entity where the * markup triggering the event appears.

*

*

If possible, the SAX driver should provide the line position * of the first character after the text associated with the document * event. The first line is line 1.

* * @return The line number, or -1 if none is available. * @see #getColumnNumber */ public int getLineNumber() { return reader.getLocation().getLineNumber(); } /** * Return the column number where the current document event ends. * This is one-based number of Java char values since * the last line end. *

*

Warning: The return value from the method * is intended only as an approximation for the sake of diagnostics; * it is not intended to provide sufficient information * to edit the character content of the original XML document. * For example, when lines contain combining character sequences, wide * characters, surrogate pairs, or bi-directional text, the value may * not correspond to the column in a text editor's display.

*

*

The return value is an approximation of the column number * in the document entity or external parsed entity where the * markup triggering the event appears.

*

*

If possible, the SAX driver should provide the line position * of the first character after the text associated with the document * event. The first column in each line is column 1.

* * @return The column number, or -1 if none is available. * @see #getLineNumber */ public int getColumnNumber() { return reader.getLocation().getColumnNumber(); } public String getSystemId(long locationId) { return getSystemId(); } public int getLineNumber(long locationId) { return getLineNumber(); } public int getColumnNumber(long locationId) { return getColumnNumber(); } /** * Get a list of unparsed entities. * * @return a list of unparsed entities, or null if the information is not available, or * an empty list if there are no unparsed entities. Each item in the list will * be an instance of {@link net.sf.saxon.pull.UnparsedEntity} */ public List getUnparsedEntities() { if (unparsedEntities == null) { return null; } List list = new ArrayList(unparsedEntities.size()); for (int i=0; i 1) { emitter.setOutputStream(new FileOutputStream(args[1])); } else { emitter.setOutputStream(System.out); } NamespaceReducer r = new NamespaceReducer(emitter); EventIteratorToReceiver.copy(puller, r); System.err.println("Elapsed time: " + (System.currentTimeMillis() - startTime) + "ms"); } } /** * 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 false; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/Decomposer.java0000644000175000017500000001264111671711573024461 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.om.Axis; import net.sf.saxon.om.NameOfNode; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.iter.AxisIterator; import net.sf.saxon.tree.tiny.TinyNodeImpl; import net.sf.saxon.tree.tiny.TinyTreeEventIterator; import net.sf.saxon.type.Type; /** * This class takes a sequence of pull events and turns it into fully-decomposed form, that is, it * takes and document and element nodes in the sequence and turns them into a subsequence consisting of a * start element|document event, a content sequence, and an end element|document event, recursively. * *

The resulting sequence is decomposed, but not flat (it will contain nested EventIterators). To flatten * it, use {@link EventStackIterator#flatten(EventIterator)}

*/ public class Decomposer implements EventIterator { private EventIterator base; private PipelineConfiguration pipe; /** * Create a Decomposer, which turns an event sequence into fully decomposed form * @param base the base sequence, which may be fully composed, fully decomposed, or * anything in between * @param pipe the Saxon pipeline configuration */ public Decomposer(EventIterator base, PipelineConfiguration pipe) { this.pipe = pipe; this.base = EventStackIterator.flatten(base); } /** * Create a Decomposer which returns the sequence of events corresponding to * a particular node * @param node the node to be decomposed * @param pipe the Saxon pipeline configuration */ public Decomposer(NodeInfo node, PipelineConfiguration pipe) { this.pipe = pipe; base = new SingletonEventIterator(node); } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { PullEvent pe = base.next(); if (pe instanceof NodeInfo) { NodeInfo node = (NodeInfo)pe; switch (node.getNodeKind()) { case Type.DOCUMENT: { if (node instanceof TinyNodeImpl) { return new TinyTreeEventIterator(((TinyNodeImpl)node), pipe); } else { SequenceIterator content = node.iterateAxis(Axis.CHILD); EventIterator contentEvents = new EventIteratorOverSequence(content); return new BracketedDocumentIterator( new Decomposer(contentEvents, pipe)); } } case Type.ELEMENT: { if (node instanceof TinyNodeImpl) { return new TinyTreeEventIterator(((TinyNodeImpl)node), pipe); } else { SequenceIterator content = node.iterateAxis(Axis.CHILD); EventIterator contentEvents = new EventIteratorOverSequence(content); StartElementEvent see = new StartElementEvent(pipe); see.setElementName(new NameOfNode(node)); see.setTypeCode(node.getSchemaType()); see.setLocalNamespaces(node.getDeclaredNamespaces(null)); AxisIterator atts = node.iterateAxis(Axis.ATTRIBUTE); while (true) { NodeInfo att = atts.next(); if (att == null) { break; } see.addAttribute(att); } return new BracketedElementIterator( see, new Decomposer(contentEvents, pipe), EndElementEvent.getInstance()); } } default: return node; } } else { return pe; } } /** * 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 false; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/BracketedDocumentIterator.java0000644000175000017500000000572011671711573027456 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.trans.XPathException; /** * The class is an EventIterator that handles the events arising from a document node constructor: * that is, the start/end event pair for the document node, bracketing a sequence of events for the * content of the document. * *

This class does not normalize the content (for example by merging adjacent text nodes). That is the job * of the {@link ComplexContentProcessor}.

* */ public class BracketedDocumentIterator implements EventIterator { private EventIterator content; private int state = INITIAL_STATE; private static final int INITIAL_STATE = 0; private static final int PROCESSING_CHILDREN = 1; private static final int EXHAUSTED = 2; /** * Constructor * @param content iterator that delivers the content of the document */ public BracketedDocumentIterator(EventIterator content) { this.content = EventStackIterator.flatten(content); state = 0; } /** * Get the next event in the sequence * @return the next event, or null when the sequence is exhausted * @throws net.sf.saxon.trans.XPathException if a dynamic evaluation error occurs */ /*@Nullable*/ public PullEvent next() throws XPathException { switch (state) { case INITIAL_STATE: state = PROCESSING_CHILDREN; return StartDocumentEvent.getInstance(); case PROCESSING_CHILDREN: PullEvent pe = content.next(); if (pe == null) { state = EXHAUSTED; return EndDocumentEvent.getInstance(); } else { return pe; } case EXHAUSTED: return null; default: throw new AssertionError("BracketedDocumentIterator state " + state); } } /** * 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/PullEvent.java0000644000175000017500000000203111671711573024267 0ustar mathieumathieupackage net.sf.saxon.evpull; /** * A PullEvent is one of the following: * * */ public interface PullEvent { } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/StartElementEvent.java0000644000175000017500000003020711671711573025770 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.expr.parser.ExpressionLocation; import net.sf.saxon.om.*; import net.sf.saxon.trans.Err; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.util.Orphan; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.Type; import net.sf.saxon.type.Untyped; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; import java.util.List; /** * This is a PullEvent representing the start of an element node. It contains (or potentially contains) all the * namespace declarations and attributes associated with the element. */ public class StartElementEvent implements PullEvent { PipelineConfiguration pipe; private NodeName elementName; private SchemaType typeCode; /*@Nullable*/ private NamespaceBinding[] localNamespaces; private List attributes; private int locationId = -1; /** * Create a Start Element Event * @param pipe the pipeline configuration */ public StartElementEvent(PipelineConfiguration pipe) { this.pipe = pipe; } /** * Set the nameCode of this element * @param elementName the namecode of the element (its name as identified in the NamePool) */ public void setElementName(NodeName elementName) { this.elementName = elementName; } /** * Get the nameCode of this element * @return the nameCode representing the element's name */ public NodeName getElementName() { return elementName; } /** * Set the typeCode of this element * @param typeCode the element's type annotation */ public void setTypeCode(SchemaType typeCode) { this.typeCode = typeCode; } /** * Get the typeCode of this element * @return the element's type annotation */ public SchemaType getTypeCode() { return typeCode; } /** * Set the namespaces that are locally declared (or undeclared) on this element * @param nscodes integer array of namespace codes */ public void setLocalNamespaces(NamespaceBinding[] nscodes) { localNamespaces = nscodes; } /** * Add a namespace code representing a locally declared namespace * @param nscode a namespace code * @throws XPathException */ public void addNamespace(NamespaceBinding nscode) throws XPathException { if (localNamespaces == null) { localNamespaces = new NamespaceBinding[]{nscode, null, null, null}; } for (int n=0; nNote that this class merely provides the service of keeping track of which namespaces are * currently in scope. It does not attempt to remove duplicate namespace declarations, and it does * not perform namespace fixup.

*/ public class NamespaceMaintainer implements EventIterator, NamespaceResolver { private EventIterator base; // We keep track of namespaces to avoid outputting duplicate declarations. The namespaces // vector holds a list of all namespaces currently declared (organised as integer namespace codes). // The countStack contains an entry for each element currently open; the // value on the countStack is an Integer giving the number of namespaces added to the main // namespace stack by that element. private NamespaceBinding[] allNamespaces = new NamespaceBinding[50]; // all namespace codes currently declared private int allNamespacesSize = 0; // all namespaces currently declared private int[] namespaceCountStack = new int[50]; // one entry per started element, holding the number private int depth = 0; // current depth of element nesting /** * Create a namespace context for a pull-events pipeline * @param base the previous stage in the pipeline, from which events are read */ public NamespaceMaintainer(EventIterator base) { this.base = EventStackIterator.flatten(base); } /** * 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; } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { PullEvent event = base.next(); if (event instanceof StartElementEvent) { startElement((StartElementEvent)event); } else if (event instanceof EndElementEvent) { endElement(); } return event; } private void startElement(StartElementEvent event) throws XPathException { // Record the current height of the namespace list so it can be reset at endElement time NamespaceBinding[] declaredNamespaces = event.getLocalNamespaces(); int numberOfDeclaredNamespaces = declaredNamespaces.length; for (int i=0; i= namespaceCountStack.length) { int[] newstack = new int[depth * 2]; System.arraycopy(namespaceCountStack, 0, newstack, 0, depth); namespaceCountStack = newstack; } namespaceCountStack[depth++] = numberOfDeclaredNamespaces; // expand the stack if necessary while (allNamespacesSize + numberOfDeclaredNamespaces >= allNamespaces.length) { NamespaceBinding[] newlist = new NamespaceBinding[allNamespacesSize * 2]; System.arraycopy(allNamespaces, 0, newlist, 0, allNamespacesSize); allNamespaces = newlist; } for (int i=0; i= 0; i--) { // if ((allNamespaces[i].getPrefix().equals(== (prefixCode)) { // return (short) (allNamespaces[i] & 0xffff); // } // } // if (prefixCode == 0) { // return 0; // by default, no prefix means no namespace URI // } else { // return -1; // } // } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope */ /*@Nullable*/ public String getURIForPrefix(String prefix, boolean useDefault) { if ((prefix.length()==0) && !useDefault) { return NamespaceConstant.NULL; } else if ("xml".equals(prefix)) { return NamespaceConstant.XML; } else { for (int i = allNamespacesSize - 1; i >= 0; i--) { if ((allNamespaces[i].getPrefix().equals(prefix))) { return allNamespaces[i].getURI(); } } return (prefix.length()==0 ? NamespaceConstant.NULL : null); } } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { List prefixes = new ArrayList(allNamespacesSize); for (int i = allNamespacesSize - 1; i >= 0; i--) { String prefix = allNamespaces[i].getPrefix(); if (!prefixes.contains(prefix)) { prefixes.add(prefix); } } prefixes.add("xml"); return prefixes.iterator(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/EventAnnotationStripper.java0000644000175000017500000000551411671711573027227 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.wrapper.VirtualUntypedCopy; import net.sf.saxon.type.Type; /** * This class is an EventIterator that filters a stream of pull events setting * the type annotation on element nodes to xs:untyped and on attribute nodes to * xs:untypedAtomic */ public class EventAnnotationStripper implements EventIterator { private EventIterator base; /** * Create an EventAnnotationStripper * @param base the stream of events whose type annotations are to be stripped (set to untyped) */ public EventAnnotationStripper(EventIterator base) { this.base = EventStackIterator.flatten(base); } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { PullEvent pe = base.next(); if (pe instanceof StartElementEvent) { StartElementEvent see = (StartElementEvent)pe; see.stripTypeAnnotations(); return see; } else if (pe instanceof NodeInfo) { // Make a virtual untyped copy of the node switch (((NodeInfo)pe).getNodeKind()) { case Type.ELEMENT: case Type.ATTRIBUTE: return VirtualUntypedCopy.makeVirtualUntypedCopy((NodeInfo)pe, (NodeInfo)pe); default: return pe; } } else { return pe; } } /** * 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/SequenceComposer.java0000644000175000017500000002241711671711573025643 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.TreeReceiver; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.query.QueryResult; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.tiny.TinyBuilder; import javax.xml.transform.stream.StreamSource; import java.io.File; /** * This class takes a sequence of pull events and composes them into a sequence of items. This involves building * any element or document nodes that are presented in decomposed form. * *

Note: this SequenceIterator does not implement the getAnother() method, which limits its use, * since getAnother() is needed to support the XPath last() function. */ public class SequenceComposer implements SequenceIterator { private EventIterator base; private int position = 0; /*@Nullable*/ private Item current = null; private PipelineConfiguration pipe; /** * Create a sequence composer * @param iter the underlying event iterator * @param pipe the pipeline configuration */ public SequenceComposer(EventIterator iter, PipelineConfiguration pipe) { base = EventStackIterator.flatten(iter); this.pipe = pipe; } /** * Get the next item in the sequence. This method changes the state of the * iterator, in particular it affects the result of subsequent calls of * position() and current(). * * @return the next item, or null if there are no more items. Once a call * on next() has returned null, no further calls should be made. The preferred * action for an iterator if subsequent calls on next() are made is to return * null again, and all implementations within Saxon follow this rule. * @throws net.sf.saxon.trans.XPathException * if an error occurs retrieving the next item * @since 8.4 */ public Item next() throws XPathException { PullEvent pe = base.next(); if (pe == null) { position = -1; current = null; return null; } if (pe instanceof Item) { current = (Item)pe; position++; return current; } else if (pe instanceof StartDocumentEvent || pe instanceof StartElementEvent) { SubtreeIterator sub = new SubtreeIterator(base, pe); TinyBuilder builder = new TinyBuilder(pipe); TreeReceiver receiver = new TreeReceiver(builder); EventIteratorToReceiver.copy(sub, receiver); current = builder.getCurrentRoot(); position++; return current; } else { throw new IllegalStateException(pe.getClass().getName()); } } /** * Get the current value in the sequence (the one returned by the * most recent call on next()). This will be null before the first * call of next(). This method does not change the state of the iterator. * * @return the current item, the one most recently returned by a call on * next(). Returns null if next() has not been called, or if the end * of the sequence has been reached. * @since 8.4 */ public Item current() { return current; } public void close() { } /** * Get another SequenceIterator that iterates over the same items as the original, * but which is repositioned at the start of the sequence. *

* This method allows access to all the items in the sequence without disturbing the * current position of the iterator. Internally, its main use is in evaluating the last() * function. *

* This method does not change the state of the iterator. * * @return a SequenceIterator that iterates over the same items, * positioned before the first item * @throws net.sf.saxon.trans.XPathException * if any error occurs * @since 8.4 */ /*@NotNull*/ public SequenceIterator getAnother() throws XPathException { throw new UnsupportedOperationException("getAnother"); } /** * Get properties of this iterator, as a bit-significant integer. * * @return the properties of this iterator. This will be some combination of * properties such as {@link #GROUNDED}, {@link #LAST_POSITION_FINDER}, * and {@link #LOOKAHEAD}. It is always * acceptable to return the value zero, indicating that there are no known special properties. * It is acceptable for the properties of the iterator to change depending on its state. * @since 8.6 */ public int getProperties() { return 0; } /** * Get the current position. This will usually be zero before the first call * on next(), otherwise it will be the number of times that next() has * been called. Once next() has returned null, the preferred action is * for subsequent calls on position() to return -1, but not all existing * implementations follow this practice. (In particular, the EmptyIterator * is stateless, and always returns 0 as the value of position(), whether * or not next() has been called.) *

* This method does not change the state of the iterator. * * @return the current position, the position of the item returned by the * most recent call of next(). This is 1 after next() has been successfully * called once, 2 after it has been called twice, and so on. If next() has * never been called, the method returns zero. If the end of the sequence * has been reached, the value returned will always be <= 0; the preferred * value is -1. * @since 8.4 */ public int position() { return position; } private static class SubtreeIterator implements EventIterator { private int level = 0; private EventIterator base; private PullEvent first; public SubtreeIterator(EventIterator base, PullEvent first) { this.base = base; this.first = first; } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { if (first != null) { PullEvent pe = first; first = null; return pe; } if (level < 0) { return null; } PullEvent pe = base.next(); if (pe instanceof StartElementEvent || pe instanceof StartDocumentEvent) { level++; } else if (pe instanceof EndElementEvent || pe instanceof EndDocumentEvent) { level--; } return pe; } /** * 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 base.isFlatSequence(); } } /** * Main method for testing only * @param args not used * @throws Exception */ public static void main(String[] args) throws Exception { Configuration config = new Configuration(); DocumentInfo doc = config.buildDocument(new StreamSource(new File("c:/MyJava/samples/data/books.xml"))); PipelineConfiguration pipe = config.makePipelineConfiguration(); pipe.setHostLanguage(Configuration.XQUERY); EventIterator e = new Decomposer(new SingletonEventIterator(doc), pipe); SequenceIterator iter = new SequenceComposer(e, pipe); while (true) { NodeInfo item = (NodeInfo)iter.next(); if (item == null) { break; } System.out.println(QueryResult.serialize(item)); } } } // // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/EventMappingFunction.java0000644000175000017500000000267011671711573026465 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.om.Item; import net.sf.saxon.trans.XPathException; /** * EventMappingFunction is an interface that must be satisfied by an object passed to an * EventMappingIterator. It represents an object which, given an Item, can return an * EventIterator that delivers a sequence of zero or more PullEvents. */ public interface EventMappingFunction { /** * Map one item to a sequence of pull events. * @param item The item to be mapped. * @return one of the following: (a) an EventIterator over the sequence of items that the supplied input * item maps to, or (b) null if it maps to an empty sequence. */ public EventIterator map(Item item) throws XPathException; } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/EventToStaxBridge.java0000644000175000017500000005745611671711573025737 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.*; import net.sf.saxon.pull.NamespaceContextImpl; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.util.FastStringBuffer; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Whitespace; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.stream.Location; import javax.xml.stream.XMLStreamConstants; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import java.util.Iterator; import java.util.NoSuchElementException; import java.util.Stack; /** * This class bridges EventIterator events to XMLStreamReader (Stax) events. That is, it acts * as an XMLStreamReader, fetching the underlying data from an EventIterator. *

* An EventIterator may provide access to any XDM sequence, whereas an XMLStreamReader always * reads a document. The conversion of a sequence to a document follows the rules for * "normalizing" a sequence in the Serialization specification: for example, atomic values are * converted into text nodes, with adjacent atomic values being space-separated. */ public class EventToStaxBridge implements XMLStreamReader { private EventIterator provider; private StartElementEvent startElementEvent; private Item currentItem; private Stack stack; // holds instances of StartElementEvent; needed because namespace information // (though not attributes) must be available at EndElement time private NamePool namePool; private boolean previousAtomic; private FastStringBuffer currentTextNode = new FastStringBuffer(FastStringBuffer.SMALL); private int currentStaxEvent = XMLStreamConstants.START_DOCUMENT; private XPathException pendingException = null; /** * Create a EventToStaxBridge instance, which wraps a Saxon EventIterator as a Stax XMLStreamReader * @param provider the Saxon EventIterator from which the events will be read. This must return * a fully decomposed event stream, that is, document and element nodes must be presented as separate * events for the start, content, and end. * @param pipe the PipelineConfiguration */ public EventToStaxBridge(EventIterator provider, PipelineConfiguration pipe) { this.namePool = pipe.getConfiguration().getNamePool(); EventIterator flatIterator = EventStackIterator.flatten(provider); if (flatIterator instanceof LocationProvider) { pipe.setLocationProvider((LocationProvider)flatIterator); } this.provider = new NamespaceMaintainer(flatIterator); this.stack = new Stack(); } /** * Get the NamePool used by this bridge to translate integer name codes to QNames * @return the name pool in use */ public NamePool getNamePool() { return namePool; } public int getAttributeCount() { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getAttributeCount(); } public boolean isAttributeSpecified(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return true; } public QName getAttributeName(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } NodeInfo att = startElementEvent.getAttribute(i); return new QName(att.getURI(), att.getLocalPart(), att.getPrefix()); } public String getAttributeLocalName(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getAttribute(i).getLocalPart(); } public String getAttributeNamespace(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getAttribute(i).getURI(); } public String getAttributePrefix(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getAttribute(i).getPrefix(); } public String getAttributeType(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } int type = startElementEvent.getAttribute(i).getTypeAnnotation(); if (type == StandardNames.XS_ID) { return "ID"; } else if (type == StandardNames.XS_IDREF) { return "IDREF"; } else if (type == StandardNames.XS_IDREFS) { return "IDREFS"; } else if (type == StandardNames.XS_NMTOKEN) { return "NMTOKEN"; } else if (type == StandardNames.XS_NMTOKENS) { return "NMTOKENS"; } else if (type == StandardNames.XS_ENTITY) { return "ENTITY"; } else if (type == StandardNames.XS_ENTITIES) { return "ENTITIES"; } return "CDATA"; } public String getAttributeValue(int i) { if (currentStaxEvent != START_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getAttribute(i).getStringValue(); } /*@Nullable*/ public String getAttributeValue(String uri, String local) { for (Iterator iter = startElementEvent.iterateAttributes(); iter.hasNext(); ) { NodeInfo att = (NodeInfo)iter.next(); if (att.getURI().equals(uri) && att.getLocalPart().equals(local)) { return att.getStringValue(); } } return null; } public int getEventType() { return currentStaxEvent; } public int getNamespaceCount() { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } NamespaceBinding[] nscodes = startElementEvent.getLocalNamespaces(); for (int i=0; i target.length) { throw new IndexOutOfBoundsException("targetStart"); } if (length < 0 || targetStart + length > target.length) { throw new IndexOutOfBoundsException("length"); } String value = getText(); if (sourceStart >= value.length()) { return 0; } int sourceEnd = sourceStart + length; if (sourceEnd > value.length()) { sourceEnd = value.length(); } value.getChars(sourceStart, sourceEnd, target, targetStart); return sourceEnd - sourceStart; } // Diagnostic version of next() method // public int next() throws XMLStreamException { // System.err.println("calling next: "); // try { // int x = nextx(); // System.err.println("next: " + x); // return x; // } catch (XMLStreamException e) { // System.err.println("end of stream "); // throw e; // } catch (IllegalStateException e) { // System.err.println("illegal end of stream "); // throw e; // } // } public int next() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } PullEvent p; try { p = provider.next(); } catch (XPathException e) { throw new XMLStreamException(e); } if (p == null) { // The spec is ambivalent here; it also says IllegalStateException is appropriate throw new NoSuchElementException("end of stream"); } startElementEvent = null; if (p instanceof StartDocumentEvent) { // STAX doesn't actually report START_DOCUMENT: it's the initial state before reading any events currentStaxEvent = XMLStreamConstants.START_DOCUMENT; return next(); } else if (p instanceof StartElementEvent) { startElementEvent = (StartElementEvent)p; currentStaxEvent = XMLStreamConstants.START_ELEMENT; stack.push(p); return currentStaxEvent; } else if (p instanceof EndElementEvent) { currentStaxEvent = XMLStreamConstants.END_ELEMENT; startElementEvent = (StartElementEvent)stack.pop(); return currentStaxEvent; } else if (p instanceof EndDocumentEvent) { currentStaxEvent = XMLStreamConstants.END_DOCUMENT; return currentStaxEvent; } else if (p instanceof NodeInfo) { currentItem = (NodeInfo)p; switch (((NodeInfo)p).getNodeKind()) { case Type.COMMENT: currentStaxEvent = XMLStreamConstants.COMMENT; return currentStaxEvent; case Type.PROCESSING_INSTRUCTION: currentStaxEvent = XMLStreamConstants.PROCESSING_INSTRUCTION; return currentStaxEvent; case Type.TEXT: currentStaxEvent = XMLStreamConstants.CHARACTERS; return currentStaxEvent; case Type.ATTRIBUTE: throw new XMLStreamException("Encountered top-level attribute in sequence"); default: throw new AssertionError("Unexpected node kind (sequence not decomposed?)"); } } else if (p instanceof AtomicValue) { currentItem = (AtomicValue)p; currentStaxEvent = XMLStreamConstants.CHARACTERS; previousAtomic = true; return currentStaxEvent; } else if (p instanceof EventIterator) { throw new AssertionError("EventToStaxBridge requires a flattened event sequence"); } else { throw new AssertionError("Unhandled pull event: " + p.getClass().getName()); } } public int nextTag() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } int eventType = next(); while ((eventType == XMLStreamConstants.CHARACTERS && isWhiteSpace()) // skip whitespace || (eventType == XMLStreamConstants.CDATA && isWhiteSpace()) // skip whitespace || eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT ) { eventType = next(); } if (eventType != XMLStreamConstants.START_ELEMENT && eventType != XMLStreamConstants.END_ELEMENT) { throw new XMLStreamException("expected start or end tag", getLocation()); } return eventType; } public void close() throws XMLStreamException { //System.err.println("close"); if (pendingException != null) { throw new XMLStreamException(pendingException); } } public boolean hasName() { return currentStaxEvent == XMLStreamConstants.START_ELEMENT || currentStaxEvent == XMLStreamConstants.END_ELEMENT; } public boolean hasNext() throws XMLStreamException { //System.err.println("hasNext()? " + (currentStaxEvent != XMLStreamConstants.END_DOCUMENT)); if (pendingException != null) { throw new XMLStreamException(pendingException); } return currentStaxEvent != XMLStreamConstants.END_DOCUMENT; } public boolean hasText() { return currentStaxEvent == XMLStreamConstants.CHARACTERS || currentStaxEvent == XMLStreamConstants.COMMENT; } public boolean isCharacters() { return currentStaxEvent == XMLStreamConstants.CHARACTERS; } public boolean isEndElement() { return currentStaxEvent == XMLStreamConstants.END_ELEMENT; } public boolean isStandalone() { return false; } public boolean isStartElement() { return currentStaxEvent == XMLStreamConstants.START_ELEMENT; } public boolean isWhiteSpace() { return currentStaxEvent == XMLStreamConstants.CHARACTERS && Whitespace.isWhite(getText()); } public boolean standaloneSet() { return false; } public String getCharacterEncodingScheme() { return null; } public String getElementText() throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } if (getEventType() != XMLStreamConstants.START_ELEMENT) { throw new XMLStreamException("parser must be on START_ELEMENT to read next text", getLocation()); } int eventType = next(); StringBuffer content = new StringBuffer(); while (eventType != XMLStreamConstants.END_ELEMENT) { if (eventType == XMLStreamConstants.CHARACTERS || eventType == XMLStreamConstants.CDATA || eventType == XMLStreamConstants.SPACE || eventType == XMLStreamConstants.ENTITY_REFERENCE) { content.append(getText()); } else if (eventType == XMLStreamConstants.PROCESSING_INSTRUCTION || eventType == XMLStreamConstants.COMMENT) { // skipping } else if (eventType == XMLStreamConstants.END_DOCUMENT) { throw new XMLStreamException("unexpected end of document when reading element text content", getLocation()); } else if (eventType == XMLStreamConstants.START_ELEMENT) { throw new XMLStreamException("element text content may not contain START_ELEMENT", getLocation()); } else { throw new XMLStreamException("Unexpected event type " + eventType, getLocation()); } eventType = next(); } return content.toString(); } public String getEncoding() { return null; } public String getLocalName() { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } return startElementEvent.getElementName().getLocalPart(); } public String getNamespaceURI() { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { return null; } return startElementEvent.getElementName().getURI(); } public String getPIData() { if (currentStaxEvent != XMLStreamConstants.PROCESSING_INSTRUCTION) { throw new IllegalStateException("Not positioned at a processing instruction"); } return getText(); } public String getPITarget() { if (currentStaxEvent != XMLStreamConstants.PROCESSING_INSTRUCTION) { throw new IllegalStateException("Not positioned at a processing instruction"); } return namePool.getLocalName(((NodeInfo)currentItem).getNameCode()); } public String getPrefix() { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { return null; } return startElementEvent.getElementName().getPrefix(); } public String getVersion() { return "1.0"; } public String getNamespacePrefix(int i) { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } NamespaceBinding nscode = startElementEvent.getLocalNamespaces()[i]; return nscode.getPrefix(); } public String getNamespaceURI(int i) { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } NamespaceBinding nscode = startElementEvent.getLocalNamespaces()[i]; return nscode.getURI(); } public NamespaceContext getNamespaceContext() { return new NamespaceContextImpl((NamespaceResolver)provider); } public QName getName() { if (currentStaxEvent != START_ELEMENT && currentStaxEvent != END_ELEMENT) { throw new IllegalStateException(""+currentStaxEvent); } NodeName name = startElementEvent.getElementName(); return new QName(name.getURI(), name.getLocalPart(), name.getPrefix()); } public Location getLocation() { if (startElementEvent != null) { PipelineConfiguration pipe = startElementEvent.getPipelineConfiguration(); final LocationProvider provider = pipe.getLocationProvider(); final int locationId = startElementEvent.getLocationId(); if (provider != null) { return new Location() { public int getCharacterOffset() { return -1; } public int getColumnNumber() { return provider.getColumnNumber(locationId); } public int getLineNumber() { return provider.getLineNumber(locationId); } public String getPublicId() { return null; } public String getSystemId() { return provider.getSystemId(locationId); } }; } } if (currentItem instanceof NodeInfo) { final NodeInfo node = (NodeInfo)currentItem; return new Location() { public int getCharacterOffset() { return -1; } public int getColumnNumber() { return node.getColumnNumber(); } public int getLineNumber() { return node.getLineNumber(); } public String getPublicId() { return null; } public String getSystemId() { return node.getSystemId(); } }; } else { return DummyLocation.THE_INSTANCE; } } public Object getProperty(String s) throws IllegalArgumentException { return null; } public void require(int event, String uri, String local) throws XMLStreamException { if (pendingException != null) { throw new XMLStreamException(pendingException); } if (currentStaxEvent != event) { throw new XMLStreamException("Required event type is " + event + ", actual event is " + currentStaxEvent); } if (uri != null && !uri.equals(getNamespaceURI())) { throw new XMLStreamException("Required namespace is " + uri + ", actual is " + getNamespaceURI()); } if (local != null && !local.equals(getLocalName())) { throw new XMLStreamException("Required local name is " + local + ", actual is " + getLocalName()); } } public String getNamespaceURI(String prefix) { if (prefix.equals("xmlns")) { return NamespaceConstant.XMLNS; } return ((NamespaceResolver)provider).getURIForPrefix(prefix, true); } /** * Get the underlying event stream */ public EventIterator getProvider() { return provider; } private static class DummyLocation implements Location{ public static final Location THE_INSTANCE = new DummyLocation(); private DummyLocation() {} public int getCharacterOffset() { return -1; } public int getColumnNumber() { return -1; } public int getLineNumber() { return -1; } public java.lang.String getPublicId() { return null; } public java.lang.String getSystemId() { return null; } } /** * Temporary test program * @param args command line arguments. First argument is a file containing an XML document * @throws Exception */ // public static void main(String[] args) throws Exception { // Configuration config = new Configuration(); // DocumentInfo doc = config.buildDocument(new StreamSource(new File(args[0]))); // PipelineConfiguration pipe = config.makePipelineConfiguration(); // pipe.setHostLanguage(Configuration.XQUERY); // EventIterator ei = new Decomposer(doc, pipe); // XMLStreamReader sr = new EventToStaxBridge(ei, config.getNamePool()); // StaxBridge bridge = new StaxBridge(); // bridge.setXMLStreamReader(sr); // // bridge.setPipelineConfiguration(pipe); // Receiver out = config.getSerializerFactory().getReceiver(new StreamResult(System.out), pipe, new Properties()); // PullPushCopier copier = new PullPushCopier(bridge, out); // copier.copy(); // } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/ComplexContentProcessor.java0000644000175000017500000002735511671711573027233 0ustar mathieumathieupackage 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 Package overview for net.sf.saxon.evpull

This package provides classes that implement a StAX-like pull pipeline in which a recieving component makes calls on a provider component to supply information from the XML stream one event at a time. The object that is supplied in response to these calls is a {@link net.sf.saxon.evpull.PullEvent}, and a component that can be invoked to deliver a sequence of these objects is a {@link net.sf.saxon.evpull.EventIterator}.

An {@link net.sf.saxon.evpull.EventIterator} is itself a {@link net.sf.saxon.evpull.PullEvent}, so an event provider may return a sequence of events in response to a single call by returning an iterator. A sequence of events containing no iterators is referred to as a flat sequence, and any sequence of events can be converted to a flat sequence by inserting an {@link net.sf.saxon.evpull.EventStackIterator} into the pipeline.

Pull processing is not used extensively in Saxon, and is generally not used at all unless explicitly requested. It can be requested, for example, by supplying a {@link net.sf.saxon.evpull.PullEventSource} object to an interface that expects an XML document to be supplied as a JAXP {@link javax.xml.transform.Source}. It is also used in XQJ when methods such as {@link javax.xml.xquery.XQDataFactory#createItemFromDocument} are used to construct an XML document from a supplied {@link javax.xml.stream.XMLStreamReader}. In such cases Saxon uses the class {@link net.sf.saxon.evpull.StaxToEventBridge} to convert StAX events to its own {@link net.sf.saxon.evpull.PullEvent} events. Conversion in the opposite direction uses the class {@link net.sf.saxon.evpull.EventToStaxBridge}.

It is possible to request pull-mode evaluation of XQuery code using the method {@link net.sf.saxon.query.XQueryExpression#iterateEvents}. This causes any document and element node constructors to be evaluated in pull mode, returning events representing start/end document/element rather than actually constructing the result tree in memory. The relevant expressions in the expression tree provide an iterateEvents() method to support this mode of execution.

A sequence of events is said to be composed if it consists entirely of items (that is, a node is passed as a single event, rather than by walking the tree); it is said to be decomposed if if consists entirely of StAX-like events. In general, the classes in this package handle sequences that mix both styles. A fully-composed sequence, however, is normally handled using the {@link net.sf.saxon.om.SequenceIterator} interface rather than by the classes in this package. The {@link net.sf.saxon.evpull.SequenceComposer} returns a full composed event stream from a decomposed or mixed stream, constructing tree fragments when necessary to achieve this; the {@link net.sf.saxon.evpull.Decomposer} does the inverse, walking any tree fragments to deliver the corresponding start-element and end-element events.

The class {@link net.sf.saxon.evpull.EventIteratorOverSequence} converts a stream of items obtained from a {@link net.sf.saxon.om.SequenceIterator} into a composed stream of {@link net.sf.saxon.evpull.PullEvent} events.

The class {@link net.sf.saxon.evpull.EventIteratorToReceiver} reads a sequence of events from a pull pipeline and outputs the same sequence of events to a push pipeline using the {@link net.sf.saxon.event.Receiver} interface.

The package {@link net.sf.saxon.pull} represents an earlier attempt at pull-mode processing in Saxon. It is retained because it provides some capabilities not yet present in this package.


Michael H. Kay
Saxonica Limited
30 July 2010

saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/BlockEventIterator.java0000644000175000017500000000501011671711573026117 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.trans.XPathException; /** * Iterate over the instructions in a Block, concatenating the result of each instruction * into a single combined sequence. */ public class BlockEventIterator implements EventIterator { private Expression[] children; private int i = 0; private EventIterator child; private XPathContext context; /** * Create an EventIterator over the results of evaluating a Block * @param children the sequence of instructions comprising the Block * @param context the XPath dynamic context */ public BlockEventIterator(Expression[] children, XPathContext context) { this.children = children; this.context = context; } /** * Get the next item in the sequence. * * @return the next item, or null if there are no more items. * @throws XPathException if an error occurs retrieving the next item */ /*@Nullable*/ public PullEvent next() throws XPathException { while (true) { if (child == null) { child = children[i++].iterateEvents(context); } PullEvent current = child.next(); if (current != null) { return current; } child = null; if (i >= children.length) { return null; } } } /** * 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 false; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/PullEventSource.java0000644000175000017500000000511311671711573025454 0ustar mathieumathieupackage net.sf.saxon.evpull; import javax.xml.transform.Source; /** * A PullSource is a JAXP Source that encapsulates a PullProvider - that is, an object * that supplies an XML document as a sequence of events that are read under the control * of the recipient. Note that although PullSource implements the JAXP Source interface, * it is not necessarily acceptable to every JAXP implementation that accepts a Source * as input: Source is essentially a marker interface and users of Source objects need * to understand the individual implementation. */ public class PullEventSource implements Source { private String systemId; private EventIterator provider; /** * Create a PullSource based on a supplied EventIterator * @param provider the underlying EventIterator */ public PullEventSource(EventIterator provider) { this.provider = provider; } /** * Get the EventIterator * @return the underlying EventIterator */ public EventIterator getEventIterator() { return provider; } /** * Set the system identifier for this Source. *

*

The system identifier is optional if the source does not * get its data from a URL, but it may still be useful to provide one. * The application can use a system identifier, for example, to resolve * relative URIs and to include in error messages and warnings.

* * @param systemId The system identifier as a URL string. */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the system identifier that was set with setSystemId. * * @return The system identifier that was set with setSystemId, or null * if setSystemId was not called. */ public String getSystemId() { return systemId; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/EventIteratorToReceiver.java0000644000175000017500000001072311671711573027143 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.event.SequenceReceiver; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.iter.AxisIterator; import net.sf.saxon.tree.util.Orphan; import net.sf.saxon.type.SimpleType; import net.sf.saxon.type.Type; import java.util.Iterator; /** * Class to read pull events from an EventIterator and write them to a Receiver */ public class EventIteratorToReceiver { /** * Private constructor: this class holds static methods only */ private EventIteratorToReceiver() {} /** * Read the data obtained from an EventIterator and write the same data to a SequenceReceiver * @param in the input EventIterator * @param out the output Receiver * @throws XPathException */ public static void copy(EventIterator in, SequenceReceiver out) throws XPathException { in = EventStackIterator.flatten(in); int level = 0; out.open(); while (true) { PullEvent event = in.next(); if (event == null) { break; } if (event instanceof Orphan && ((Orphan)event).getNodeKind() == Type.TEXT) { out.characters(((Orphan)event).getStringValueCS(), 0, 0); } else if (event instanceof DocumentInfo && level > 0) { AxisIterator kids = ((DocumentInfo)event).iterateAxis(Axis.CHILD); while (true) { NodeInfo node = (NodeInfo)kids.next(); if (node == null) { break; } out.append(node, 0, 0); } } else if (event instanceof Item) { out.append((Item)event, 0, NodeInfo.ALL_NAMESPACES); } else if (event instanceof StartElementEvent) { StartElementEvent see = (StartElementEvent)event; level++; out.startElement(see.getElementName(), see.getTypeCode(), 0, ReceiverOptions.NAMESPACE_OK); NamespaceBinding[] localNamespaces = see.getLocalNamespaces(); for (NamespaceBinding ns : localNamespaces) { if (ns == null) { break; } out.namespace(ns, 0); } if (see.hasAttributes()) { for (Iterator ai=see.iterateAttributes(); ai.hasNext();) { NodeInfo att = (NodeInfo)ai.next(); out.attribute(new NameOfNode(att), (SimpleType)att.getSchemaType(), att.getStringValueCS(), 0, 0); } } out.startContent(); } else if (event instanceof EndElementEvent) { level--; out.endElement(); } else if (event instanceof StartDocumentEvent) { if (level == 0) { out.startDocument(0); } else { // output a zero-length text node to prevent whitespace being added between atomic values out.characters("", 0, 0); } level++; } else if (event instanceof EndDocumentEvent) { level--; if (level == 0) { out.endDocument(); } else { // output a zero-length text node to prevent whitespace being added between atomic values out.characters("", 0, 0); } } else { throw new AssertionError("Unknown event class " + event.getClass()); } } out.close(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/TracingEventIterator.java0000644000175000017500000000445411671711573026467 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.trans.XPathException; /** * This class is a filter for a sequence of pull events; it returns the input sequence unchanged, * but traces execution to System.err */ public class TracingEventIterator implements EventIterator { private EventIterator base; /** * Create an event iterator that traces all events received from the base sequence, and returns * them unchanged * @param base the iterator over the base sequence */ public TracingEventIterator(EventIterator base) { this.base = base; } /** * 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 base.isFlatSequence(); } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws net.sf.saxon.trans.XPathException * if a dynamic evaluation error occurs */ /*@Nullable*/ public PullEvent next() throws XPathException { PullEvent next = base.next(); if (next == null) { System.err.println("EVPULL end-of-sequence"); } else { System.err.println("EVPULL " + next.getClass().getName()); } return next; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/StartDocumentEvent.java0000644000175000017500000000210311671711573026147 0ustar mathieumathieupackage net.sf.saxon.evpull; /** * A PullEvent representing the start of a document node */ public class StartDocumentEvent implements PullEvent { private final static StartDocumentEvent THE_INSTANCE = new StartDocumentEvent(); public static StartDocumentEvent getInstance() { return THE_INSTANCE; } private StartDocumentEvent() { } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/BracketedElementIterator.java0000644000175000017500000001225211671711573027267 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.om.NamespaceBinding; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * The class is an EventIterator that handles the events arising from an element constructor: * that is, the start/end event pair for the element node, bracketing a sequence of events for the * content of the element. * *

This class does not normalize the content (for example by merging adjacent text nodes). That is the job * of the {@link ComplexContentProcessor}.

* *

The event stream consumed by a BracketedElementIterator may contain freestanding attribute and namespace nodes. * The event stream delivered by a BracketedElementIterator, however, packages all attributes and namespaces as * part of the startElement event.

*/ public class BracketedElementIterator implements EventIterator { private StartElementEvent start; private EventIterator content; private PullEvent pendingContent; private EndElementEvent end; private int state = INITIAL_STATE; private static final int INITIAL_STATE = 0; private static final int PROCESSING_FIRST_CHILD = 1; private static final int PROCESSING_REMAINING_CHILDREN = 2; private static final int REACHED_END_TAG = 3; private static final int EXHAUSTED = 4; /** * Constructor * @param start the StartElementEvent object * @param content iterator that delivers the content of the element * @param end the EndElementEvent object */ public BracketedElementIterator(StartElementEvent start, EventIterator content, EndElementEvent end) { this.start = start; this.content = EventStackIterator.flatten(content); this.end = end; state = 0; } /** * Get the next event in the sequence * @return the next event, or null when the sequence is exhausted * @throws XPathException if a dynamic evaluation error occurs */ /*@Nullable*/ public PullEvent next() throws XPathException { switch (state) { case INITIAL_STATE: while (true) { PullEvent pe = content.next(); if (pe == null) { pendingContent = null; state = REACHED_END_TAG; break; } else if (pe instanceof NodeInfo) { int k = ((NodeInfo)pe).getNodeKind(); if (k == Type.NAMESPACE) { NamespaceBinding nscode = new NamespaceBinding( ((NodeInfo)pe).getLocalPart(), ((NodeInfo)pe).getStringValue()); start.addNamespace(nscode); continue; } else if (k == Type.ATTRIBUTE) { start.addAttribute((NodeInfo)pe); continue; } else if (k == Type.TEXT && ((NodeInfo)pe).getStringValueCS().length() == 0) { // ignore a zero-length text node continue; } } pendingContent = pe; state = PROCESSING_FIRST_CHILD; break; } start.namespaceFixup(); return start; case PROCESSING_FIRST_CHILD: state = PROCESSING_REMAINING_CHILDREN; return pendingContent; case PROCESSING_REMAINING_CHILDREN: PullEvent pe = content.next(); if (pe == null) { state = EXHAUSTED; return end; } else { return pe; } case REACHED_END_TAG: state = EXHAUSTED; return end; case EXHAUSTED: return null; default: throw new AssertionError("BracketedEventIterator state " + state); } } /** * 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/EventIterator.java0000644000175000017500000000301511671711573025147 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.trans.XPathException; /** * An iterator over a sequence of events */ public interface EventIterator extends PullEvent { /** * Get the next event in the sequence * @return the next event, or null when the sequence is exhausted. Note that since an EventIterator is * itself a PullEvent, this method may return a nested iterator. * @throws XPathException if a dynamic evaluation error occurs */ /*@Nullable*/ public PullEvent next() throws XPathException; /** * 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(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/EventStackIterator.java0000644000175000017500000000610111671711573026134 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.trans.XPathException; import java.util.Stack; /** * An EventStackIterator is an EventIterator that delivers a flat sequence of PullEvents * containing no nested EventIterators */ public class EventStackIterator implements EventIterator { private Stack eventStack = new Stack(); /** * Factory method to create an iterator that flattens the sequence of PullEvents received * from a base iterator, that is, it returns an EventIterator that will never return any * nested iterators. * @param base the base iterator. Any nested EventIterator returned by the base iterator * will be flattened, recursively. */ public static EventIterator flatten(EventIterator base) { if (base.isFlatSequence()) { return base; } return new EventStackIterator(base); } /** * Create a EventStackIterator that flattens the sequence of PullEvents received * from a base iterator * @param base the base iterator. Any nested EventIterator returned by the base iterator * will be flattened, recursively. */ private EventStackIterator(EventIterator base) { eventStack.push(base); } /** * 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 */ /*@Nullable*/ public PullEvent next() throws XPathException { if (eventStack.isEmpty()) { return null; } EventIterator iter = eventStack.peek(); PullEvent next = iter.next(); if (next == null) { eventStack.pop(); return next(); } else if (next instanceof EventIterator) { eventStack.push((EventIterator)next); return next(); } else { return next; } } /** * 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/evpull/SingletonEventIterator.java0000644000175000017500000000377411671711573027046 0ustar mathieumathieupackage net.sf.saxon.evpull; import net.sf.saxon.trans.XPathException; /** * This class represents an EventIterator over a sequence containing a single pull event. */ public class SingletonEventIterator implements EventIterator { /*@Nullable*/ private PullEvent event; /** * Create an iterator over a sequence containing a single pull event * @param event the single event. This must not be an EventIterator */ public SingletonEventIterator(PullEvent event) { this.event = event; if (event instanceof EventIterator) { throw new IllegalArgumentException("event"); } } /** * Get the next event in the sequence * * @return the next event, or null when the sequence is exhausted * @throws XPathException if a dynamic evaluation error occurs */ public PullEvent next() throws XPathException { PullEvent next = event; event = null; return next; } /** * 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/xpath/0000755000175000017500000000000012213124713021312 5ustar mathieumathieusaxonhe-9.4.0.7/src/main/java/net/sf/saxon/xpath/XPathExpressionImpl.java0000644000175000017500000005510411671711573026125 0ustar mathieumathieupackage net.sf.saxon.xpath; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.expr.instruct.Executable; import net.sf.saxon.expr.instruct.SlotManager; import net.sf.saxon.expr.sort.AtomicComparer; import net.sf.saxon.expr.sort.SortKeyDefinition; import net.sf.saxon.expr.sort.SortKeyEvaluator; import net.sf.saxon.expr.sort.SortedIterator; import net.sf.saxon.functions.NumberFn; import net.sf.saxon.om.*; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.wrapper.VirtualNode; import net.sf.saxon.value.*; import org.xml.sax.InputSource; import javax.xml.namespace.QName; import javax.xml.transform.sax.SAXSource; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import java.util.List; /** *

The JAXP XPathExpression interface represents a compiled XPath expression that can be repeatedly * evaluated. This class is Saxon's implementation of that interface.

* *

The class also includes some methods retained from Saxon's original XPath API. When these methods * are used, the object contains the context node and other state, so it is not thread-safe.

* * @author Michael H. Kay */ public class XPathExpressionImpl implements XPathExpression, SortKeyEvaluator { private Configuration config; private Executable executable; private Expression expression; private Expression atomizer; /*@Nullable*/ private NodeInfo contextNode; private SlotManager stackFrameMap; /*@Nullable*/ private XPathExpressionImpl sortKey = null; /** * The constructor is protected, to ensure that instances can only be * created using the createExpression() method of XPathEvaluator * @param exp the compiled expression * @param exec the executable */ protected XPathExpressionImpl(Expression exp, /*@NotNull*/ Executable exec) { expression = exp; executable = exec; config = exec.getConfiguration(); } /** * Define the number of slots needed for local variables within the expression. * This method is for internal use only. * @param map description of the stack frame */ protected void setStackFrameMap(SlotManager map) { stackFrameMap = map; } /** * Get the stack frame map. This holds information about the allocation of slots to variables. * This is needed by applications using low-level interfaces for evaluating the expression * @return a description of the stack frame */ public SlotManager getStackFrameMap() { return stackFrameMap; } /** * Get the Configuration under which this XPath expression was compiled * @return the Saxon configuration */ public Configuration getConfiguration() { return config; } /** * Define the sort order for the results of the expression. If this method is called, then * the list returned by a subsequent call on the evaluate() method will first be sorted. * @param sortKey an XPathExpression, which will be applied to each item in the sequence; * the result of this expression determines the ordering of the list returned by the evaluate() * method. The sortKey can be null, to clear a previous sort key. Note that the expression is * not automatically atomized; if it selects nodes, these should be explicitly converted to * atomic values by calling the string() or data() functions. * @deprecated since 9.0. This method is not present in the JAXP interface. The recommended * way to get a sorted result is to use XQuery instead of XPath. */ public void setSortKey(XPathExpressionImpl sortKey) { this.sortKey = sortKey; } /** * Set the context node for evaluating the expression. If this method is not called, * the context node will be the root of the document to which the prepared expression is * bound. * @param node the context node * @deprecated since 9.0. Using this method is not thread-safe. Use a method instead * such as {@link #evaluate(Object, QName)} that allows the context node to be specified * as a parameter to the call. */ public void setContextNode(/*@Nullable*/ NodeInfo node) { if (node==null) { throw new NullPointerException("Context node cannot be null"); } if (node.getConfiguration() != config) { throw new IllegalArgumentException("Supplied node uses the wrong Configuration"); } contextNode = node; } /** * Protected, undeprecated version of setContextNode() for use by deprecated paths within the package * (exists to avoid deprecation warnings when compiling Saxon) * @param node the context node */ protected void privatelySetContextNode(/*@Nullable*/ NodeInfo node) { if (node==null) { throw new NullPointerException("Context node cannot be null"); } if (node.getConfiguration() != config) { throw new IllegalArgumentException("Supplied node uses the wrong Configuration"); } contextNode = node; } /** * Execute a prepared XPath expression, returning the results as a List. The context * node must have been set previously using {@link #setContextNode(net.sf.saxon.om.NodeInfo)}. * @return The results of the expression, as a List. The List represents the sequence * of items returned by the expression. Each item in the list will either be an instance * of net.sf.saxon.om.NodeInfo, representing a node, or a Java object representing an atomic value. * For the types of Java object that may be returned, see {@link #evaluate(Object, javax.xml.namespace.QName)} * with the second argument set to NODESET. * @deprecated since 9.0. This method is not present in the JAXP interface. Either use * the JAXP methods such as {@link #evaluate(Object, QName)}, or use the Saxon XPath * API instead of JAXP. */ /*@NotNull*/ public List evaluate() throws XPathException { XPathContextMajor context = new XPathContextMajor(contextNode, executable); context.openStackFrame(stackFrameMap); SequenceIterator iter = expression.iterate(context); SequenceExtent extent = new SequenceExtent(iter); return (List)PJConverter.ToCollection.INSTANCE.convert(extent, List.class, context); } /** * Execute a prepared XPath expression, returning the first item in the result. * This is useful where it is known that the expression will only return * a singleton value (for example, a single node, or a boolean). The context node * must be set previously using {@link #setContextNode(net.sf.saxon.om.NodeInfo)}. * @return The first item in the sequence returned by the expression. If the expression * returns an empty sequence, this method returns null. Otherwise, it returns the first * item in the result sequence, represented as a Java object using the same mapping as for * the evaluate() method * @deprecated since 9.0. This method is not present in the JAXP interface. Either use * the JAXP methods such as {@link #evaluate(Object, QName)}, or use the Saxon XPath * API instead of JAXP. */ /*@Nullable*/ public Object evaluateSingle() throws XPathException { XPathContextMajor context = new XPathContextMajor(contextNode, executable); context.openStackFrame(stackFrameMap); SequenceIterator iterator = expression.iterate(context); Item item = iterator.next(); if (item == null) { return null; } else { return Value.convertToJava(item); } } /** * Get a raw iterator over the results of the expression. This returns results without * any conversion of the returned items to "native" Java classes. This method is intended * for use by applications that need to process the results of the expression using * internal Saxon interfaces. * @param contextItem the context item for evaluating the expression * @return an iterator over the results of the expression, with no conversion of returned items * @since 9.0 */ /*@Nullable*/ public SequenceIterator rawIterator(Item contextItem) throws XPathException { XPathContextMajor context = new XPathContextMajor(contextItem, executable); return rawIterator(context); } /*@Nullable*/ private SequenceIterator rawIterator(/*@NotNull*/ XPathContextMajor context) throws XPathException { context.openStackFrame(stackFrameMap); SequenceIterator iterator = expression.iterate(context); if (sortKey != null) { Expression key = sortKey.expression; if (key.getItemType(config.getTypeHierarchy()) instanceof NodeTest) { sortKey.expression = new Atomizer(key); } SortKeyDefinition sk = new SortKeyDefinition(); sk.setSortKey(sortKey.expression, true); AtomicComparer comp = sk.makeComparator(context); AtomicComparer[] comps = {comp}; iterator = new SortedIterator(context, iterator, this, comps, true); ((SortedIterator)iterator).setHostLanguage(Configuration.XPATH); } return iterator; } /** * JAXP 1.3 evaluate() method * @param node The context node. This must use a representation of nodes that this implementation understands. * This may be a Saxon NodeInfo, or a node in one of the external object models supported, for example * DOM, DOM4J, JDOM, or XOM, provided the support module for that object model is loaded. * *

Contrary to the interface specification, Saxon does not supply an empty * document when the value is null. This is because Saxon supports multiple object models, * and it's unclear what kind of document node would be appropriate. Instead, Saxon uses * the node supplied to the {@link #setContextNode} method if available, and if none * is available, executes the XPath expression with the context item undefined.

*

Saxon does not allow a NodeList to be supplied for this parameter. It's not clear * what this would be intended to mean.

* @param qName Indicates the type of result required. This must be one of the constants defined in * the JAXP {@link XPathConstants} class. * Saxon will attempt to convert the actual result of the expression to the required type using the * XPath 1.0 conversion rules. * @return the result of the evaluation, as a Java object of the appropriate type. Saxon interprets the * rules as follows: * * * * * * * * * * * * *
QNameReturn Value
BOOLEANThe effective boolean value of the actual result, * as a Java Boolean object
STRINGThe result of applying the string() function to the actual result, * as a Java String object
NUMBERThe result of applying the number() function to the actual result, * as a Java Double object
NODEA single node, in the native data model supplied as input. If the * expression returns more than one node, the first is returned. If * the expression returns an empty sequence, null is returned. If the * expression returns an atomic value, or if the first item in the * result sequence is an atomic value, an exception is thrown.
NODESETThis is interpreted as allowing any sequence, of nodes or atomic values. * If the first argument is a wrapper around a DOM Node, then the result is * returned as a DOM NodeList, and an exception is then thrown if the result sequence * contains a value that is not a DOM Node. In all other cases * the result is returned as a Java List object, unless it is empty, in which * case null is returned. The contents of the list may be node objects (in the * native data model supplied as input), or Java objects representing the XPath * atomic values in the actual result: String for an xs:string, Double for a xs:double, * Long for an xs:integer, and so on. (For safety, cast the values to a type * such as xs:string within the XPath expression).
* * @throws XPathExpressionException if evaluation of the expression fails or if the * result cannot be converted to the requested type. */ /*@Nullable*/ public Object evaluate(/*@Nullable*/ Object node, /*@NotNull*/ QName qName) throws XPathExpressionException { NodeInfo contextNode = this.contextNode; if (node != null) { if (node instanceof SingletonItem) { node = ((SingletonItem)node).asItem(); } if (node instanceof NodeInfo) { if (!((NodeInfo)node).getConfiguration().isCompatible(config)) { throw new XPathExpressionException( "Supplied node must be built using the same or a compatible Configuration"); } if (node instanceof DocumentInfo && ((DocumentInfo)node).isTyped() && !executable.isSchemaAware()) { throw new XPathExpressionException( "The expression was compiled to handled untyped data, but the input is typed"); } contextNode = ((NodeInfo)node); } else { JPConverter converter = JPConverter.allocate(node.getClass(), config); ValueRepresentation val; try { val = converter.convert(node, new EarlyEvaluationContext(config, null)); } catch (XPathException e) { throw new XPathExpressionException( "Failure converting a node of class " + node.getClass().getName() + ": " + e.getMessage()); } if (val instanceof NodeInfo) { if (!((NodeInfo)val).getConfiguration().isCompatible(config)) { throw new XPathExpressionException( "Supplied node must be built using the same or a compatible Configuration"); } if (node instanceof DocumentInfo && ((DocumentInfo)node).isTyped() && !executable.isSchemaAware()) { throw new XPathExpressionException( "The expression was compiled to handled untyped data, but the input is typed"); } contextNode = (NodeInfo)val; } else { throw new XPathExpressionException( "Cannot locate an object model implementation for nodes of class " + node.getClass().getName()); } } } XPathContextMajor context = new XPathContextMajor(contextNode, executable); context.openStackFrame(stackFrameMap); try { if (qName.equals(XPathConstants.BOOLEAN)) { return Boolean.valueOf(expression.effectiveBooleanValue(context)); } else if (qName.equals(XPathConstants.STRING)) { SequenceIterator iter = expression.iterate(context); Item first = iter.next(); if (first == null) { return ""; } return first.getStringValue(); } else if (qName.equals(XPathConstants.NUMBER)) { if (atomizer == null) { atomizer = new Atomizer(expression); } SequenceIterator iter = atomizer.iterate(context); Item first = iter.next(); if (first == null) { return new Double(Double.NaN); } if (first instanceof NumericValue) { return new Double(((NumericValue)first).getDoubleValue()); } else { DoubleValue v = NumberFn.convert((AtomicValue)first, getConfiguration()); return new Double(v.getDoubleValue()); } } else if (qName.equals(XPathConstants.NODE)) { SequenceIterator iter = expression.iterate(context); Item first = iter.next(); if (first instanceof VirtualNode) { return ((VirtualNode)first).getRealNode(); } if (first == null || first instanceof NodeInfo) { return first; } throw new XPathExpressionException("Expression result is not a node"); } else if (qName.equals(XPathConstants.NODESET)) { //SequenceIterator iter = expression.iterate(context); SequenceIterator iter = rawIterator(context); SequenceExtent extent = new SequenceExtent(iter); PJConverter converter = PJConverter.allocateNodeListCreator(config, node); return converter.convert(extent, Object.class, context); } else { throw new IllegalArgumentException("qName: Unknown type for expected result"); } } catch (XPathException e) { throw new XPathExpressionException(e); } } /** * Evaluate the expression to return a string value * @param node the initial context node. This must be either an instance of NodeInfo or a node * recognized by a known external object model. *

Contrary to the interface specification, Saxon does not supply an empty * document when the value is null. This is because Saxon supports multiple object models, * and it's unclear what kind of document node would be appropriate. Instead, Saxon uses * the node supplied to the {@link #setContextNode} method if available, and if none * is available, executes the XPath expression with the context item undefined.

* @return the results of the expression, converted to a String * @throws XPathExpressionException if evaluation fails */ /*@NotNull*/ public String evaluate(Object node) throws XPathExpressionException { return (String)evaluate(node, XPathConstants.STRING); } /** * Evaluate the XPath expression against an input source to obtain a result of a specified type * @param inputSource The input source document against which the expression is evaluated. * (Note that there is no caching. This will be parsed, and the parsed result will be discarded.) * If the supplied value is null then (contrary to the JAXP specifications), the XPath expression * is evaluated with the context item undefined. * @param qName The type required, identified by a constant in {@link XPathConstants} * @return the result of the evaluation, as a Java object of the appropriate type: * see {@link #evaluate(Object, javax.xml.namespace.QName)} * @throws XPathExpressionException */ /*@Nullable*/ public Object evaluate(/*@Nullable*/ InputSource inputSource, /*@Nullable*/ QName qName) throws XPathExpressionException { if (qName == null) { throw new NullPointerException("qName"); } try { NodeInfo doc = null; if (inputSource != null) { doc = config.buildDocument(new SAXSource(inputSource)); } return evaluate(doc, qName); } catch (XPathException e) { throw new XPathExpressionException(e); } } /** * Evaluate the XPath expression against an input source to obtain a string result * @param inputSource The input source document against which the expression is evaluated. * (Note that there is no caching. This will be parsed, and the parsed result will be discarded.) * @return the result of the evaluation, converted to a String * @throws XPathExpressionException in the event of an XPath dynamic error * @throws NullPointerException If inputSource is null. */ /*@NotNull*/ public String evaluate(/*@Nullable*/ InputSource inputSource) throws XPathExpressionException { if (inputSource == null) { throw new NullPointerException("inputSource"); } try { NodeInfo doc = config.buildDocument(new SAXSource(inputSource)); return (String)evaluate(doc, XPathConstants.STRING); } catch (XPathException e) { throw new XPathExpressionException(e); } } /** * Callback for evaluating the sort keys. For internal use only. */ /*@Nullable*/ public AtomicValue evaluateSortKey(int n, XPathContext c) throws XPathException { return (AtomicValue)sortKey.getInternalExpression().evaluateItem(c); } /** * Low-level method to get the internal Saxon expression object. This exposes a wide range of * internal methods that may be needed by specialized applications, and allows greater control * over the dynamic context for evaluating the expression. * @return the underlying Saxon expression object. */ public Expression getInternalExpression() { return expression; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/xpath/XPathEvaluator.java0000644000175000017500000006006111722225660025076 0ustar mathieumathieupackage net.sf.saxon.xpath; import net.sf.saxon.Configuration; import net.sf.saxon.dom.DocumentWrapper; import net.sf.saxon.dom.NodeWrapper; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.instruct.Executable; import net.sf.saxon.expr.instruct.SlotManager; import net.sf.saxon.expr.parser.ExpressionTool; import net.sf.saxon.expr.parser.ExpressionVisitor; import net.sf.saxon.lib.ParseOptions; import net.sf.saxon.om.AllElementsSpaceStrippingRule; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.sxpath.SimpleContainer; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.tree.wrapper.SpaceStrippedDocument; import net.sf.saxon.type.SchemaException; import net.sf.saxon.type.Type; import net.sf.saxon.value.Whitespace; import org.w3c.dom.Node; import org.xml.sax.InputSource; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.transform.Source; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamSource; import javax.xml.xpath.*; import java.io.File; import java.util.List; /** *

XPathEvaluator implements the JAXP API for standalone XPath processing (that is, * executing XPath expressions in the absence of an XSLT stylesheet). It is an implementation * of the JAXP 1.3 XPath interface, with additional methods provided (a) for backwards * compatibility (b) to give extra control over the XPath evaluation, and (c) to support * XPath 2.0.

* *

It is intended to evolve this so that it only supports the JAXP style of operation. * Some of the methods are therefore marked as deprecated in this release, and will be * dropped in a future release.

* *

For an alternative XPath API, offering more direct access to Saxon capabilities, * see {@link net.sf.saxon.sxpath.XPathEvaluator}.

* *

Note that the XPathEvaluator links to a Saxon {@link Configuration} * object. By default a new Configuration is created automatically. In many * applications, however, it is desirable to share a configuration. The default configuration * is not schema aware. All source documents used by XPath expressions under this evaluator * must themselves be built using the Configuration used by this evaluator.

* * @author Michael H. Kay */ public class XPathEvaluator implements XPath { private Configuration config; /*@Nullable*/ private NodeInfo contextNode = null; private JAXPXPathStaticContext staticContext; private boolean stripSpace = false; /** * Default constructor. Creates an XPathEvaluator with Configuration appropriate * to the version of the Saxon software being run. */ public XPathEvaluator() { this(Configuration.newConfiguration()); } /** * Construct an XPathEvaluator with a specified configuration. * @param config the configuration to be used. If schema-aware XPath expressions are to be used, * this must be an EnterpriseConfiguration. */ public XPathEvaluator(/*@NotNull*/ Configuration config) { this.config = config; staticContext = new JAXPXPathStaticContext(config); } /** * Construct an XPathEvaluator to process a particular source document. This is equivalent to * using the default constructor and immediately calling setSource(). * @param source The source document (or a specific node within it). */ public XPathEvaluator(/*@NotNull*/ Source source) throws net.sf.saxon.trans.XPathException { if (source instanceof NodeInfo) { config = ((NodeInfo)source).getDocumentRoot().getConfiguration(); } else { config = new Configuration(); } staticContext = new JAXPXPathStaticContext(config); setSource(source); } /** * Get the Configuration used by this XPathEvaluator * @return the Configuration used by this XPathEvaluator */ public Configuration getConfiguration() { return config; } /** * Indicate whether all whitespace text nodes in the source document are to be * removed. This option has no effect unless it is called before the call on setSource(), * and unless the Source supplied to setSource() is a SAXSource or StreamSource. * @param strip True if all whitespace text nodes are to be stripped from the source document, * false otherwise. The default if the method is not called is false. * @deprecated since 8.9. The preferred way to define options for the way in which source * documents are built is to use the class {@link net.sf.saxon.lib.AugmentedSource} for any * of the methods expecting a {@link Source} object. */ public void setStripSpace(boolean strip) { stripSpace = strip; } /** * Supply a document against which XPath expressions are to be executed, converting it to a * Saxon NodeInfo object. *

If the supplied source is a NodeInfo, it is returned unchanged.

*

If the supplied source is a DOMSource, the result is a Saxon NodeInfo * wrapper around the DOM Node contained by the DOMSource.

*

In all other cases, the result is a document node, and is the same as the result of calling * {@link Configuration#buildDocument(javax.xml.transform.Source)} with the same argument; * except that when whitespace stripping has been requested using {@link #setStripSpace(boolean)}, * this request is passed on.

*

Despite the name of this method, it does not change the state of the XPathEvaluator * in any way.

* @param source Any javax.xml.transform.Source object representing the document against * which XPath expressions will be executed. Note that a Saxon {@link net.sf.saxon.om.DocumentInfo DocumentInfo} * (indeed any {@link net.sf.saxon.om.NodeInfo NodeInfo}) * can be used as a Source. To use a third-party DOM Document as a source, create an instance of * {@link javax.xml.transform.dom.DOMSource DOMSource} to wrap it. *

The Source object supplied also determines the initial setting * of the context item. In most cases the context node will be the root of the supplied document; * however, if a NodeInfo or DOMSource is supplied it can be any node in the document.

* @return the NodeInfo of the start node in the resulting document object. * @throws XPathException if the supplied Source is a NodeInfo object that was built using an incompatible * Configuration (that is, a Configuration using a different NamePool). Also, if any error occurs parsing * the document supplied as the Source. */ public NodeInfo setSource(/*@NotNull*/ Source source) throws net.sf.saxon.trans.XPathException { if (source instanceof DOMSource) { Node node = ((DOMSource)source).getNode(); String baseURI = source.getSystemId(); DocumentWrapper documentWrapper = new DocumentWrapper(node.getOwnerDocument(), baseURI, config); NodeWrapper nodeWrapper = documentWrapper.wrap(node); if (stripSpace) { SpaceStrippedDocument sdoc = new SpaceStrippedDocument(documentWrapper, AllElementsSpaceStrippingRule.getInstance()); return sdoc.wrap(nodeWrapper); } else { return nodeWrapper; } } else if (source instanceof NodeInfo) { NodeInfo origin = (NodeInfo)source; if (!origin.getConfiguration().isCompatible(config)) { throw new net.sf.saxon.trans.XPathException( "Supplied node must be built using the same or a compatible Configuration", SaxonErrorCode.SXXP0004); } if (stripSpace) { SpaceStrippedDocument sdoc = new SpaceStrippedDocument(origin.getDocumentRoot(), AllElementsSpaceStrippingRule.getInstance()); return sdoc.wrap(origin); } else { return origin; } } else { ParseOptions options = new ParseOptions(); if (stripSpace) { options.setStripSpace(Whitespace.ALL); } return config.buildDocument(source, options); } } /** * Set the static context for compiling XPath expressions. This provides control over the * environment in which the expression is compiled, for example it allows namespace prefixes to * be declared, variables to be bound and functions to be defined. For most purposes, the static * context can be defined by providing and tailoring an instance of the JAXPXPathStaticContext class. * Until this method is called, a default static context is used, in which no namespaces are defined * other than the standard ones (xml, xslt, and saxon), and no variables or functions (other than the * core XPath functions) are available. * @param context the static context * @throws IllegalArgumentException if the supplied static context uses a different and incompatible * Configuration from the one used in this XPathEvaluator */ public void setStaticContext(/*@NotNull*/ JAXPXPathStaticContext context) { if (!config.isCompatible(context.getConfiguration())) { throw new IllegalArgumentException("Supplied static context uses a different and incompatible Configuration"); } staticContext = context; } /** * Get the current static context * @return the static context */ public JAXPXPathStaticContext getStaticContext() { return staticContext; } /** * Get the executable * @return the executable */ // public Executable getExecutable() { // return staticContext.getExecutable(); // } /** * Prepare an XPath expression for subsequent evaluation. * @param expression The XPath expression to be evaluated, supplied as a string. * @return an XPathExpression object representing the prepared expression * @throws net.sf.saxon.trans.XPathException if the syntax of the expression is wrong, or if it references namespaces, * variables, or functions that have not been declared. * @deprecated since Saxon 8.9 - use {@link #compile(String)} */ /*@NotNull*/ public XPathExpressionImpl createExpression(String expression) throws net.sf.saxon.trans.XPathException { return createExpressionInternal(expression); } /*@NotNull*/ private XPathExpressionImpl createExpressionInternal(String expression) throws net.sf.saxon.trans.XPathException { Executable exec = new Executable(getConfiguration()); SimpleContainer container = new SimpleContainer(exec); Expression exp = ExpressionTool.make(expression, staticContext, container, 0, -1, 1, null); ExpressionVisitor visitor = ExpressionVisitor.make(staticContext, exec); visitor.setExecutable(exec); final ExpressionVisitor.ContextItemType contextItemType = new ExpressionVisitor.ContextItemType(Type.ITEM_TYPE, true); exp = visitor.typeCheck(exp, contextItemType); exp = visitor.optimize(exp, contextItemType); SlotManager map = staticContext.getConfiguration().makeSlotManager(); ExpressionTool.allocateSlots(exp, 0, map); exp.setContainer(container); XPathExpressionImpl xpe = new XPathExpressionImpl(exp, exec); xpe.setStackFrameMap(map); if (contextNode != null) { xpe.privatelySetContextNode(contextNode); } return xpe; } /** * Set the context node. This provides the context node for any expressions executed after this * method is called, including expressions that were prepared before it was called. * @param node The node to be used as the context node. The node must be within a tree built using * the same Saxon {@link Configuration} as used by this XPathEvaluator. * @deprecated since Saxon 8.9 - use the various method defined in the JAXP interface definition, * which allow a NodeInfo object to be supplied as the value of the Source argument * @throws IllegalArgumentException if the supplied node was built using the wrong Configuration */ public void setContextNode(/*@NotNull*/ NodeInfo node) { if (!node.getConfiguration().isCompatible(config)) { throw new IllegalArgumentException( "Supplied node must be built using the same or a compatible Configuration"); } contextNode = node; } public void reset() { contextNode = null; stripSpace = false; staticContext = new JAXPXPathStaticContext(config); } /** * Set XPath 1.0 compatibility mode on or off (by default, it is false). This applies * to any XPath expression compiled while this option is in force. * @param compatible true if XPath 1.0 compatibility mode is to be set to true, false * if it is to be set to false. */ public void setBackwardsCompatible(boolean compatible) { staticContext.setBackwardsCompatibilityMode(compatible); } /** * Get the value of XPath 1.0 compatibility mode * @return true if XPath 1.0 compatibility mode is set */ public boolean isBackwardsCompatible() { return staticContext.isInBackwardsCompatibleMode(); } /** * Set the resolver for XPath variables * @param xPathVariableResolver a resolver for variables */ public void setXPathVariableResolver(XPathVariableResolver xPathVariableResolver) { staticContext.setXPathVariableResolver(xPathVariableResolver); } /** * Get the resolver for XPath variables * @return the resolver, if one has been set */ public XPathVariableResolver getXPathVariableResolver() { return staticContext.getXPathVariableResolver(); } /** * Set the resolver for XPath functions * @param xPathFunctionResolver a resolver for XPath function calls */ public void setXPathFunctionResolver(XPathFunctionResolver xPathFunctionResolver) { staticContext.setXPathFunctionResolver(xPathFunctionResolver); } /** * Get the resolver for XPath functions * @return the resolver, if one has been set */ /*@Nullable*/ public XPathFunctionResolver getXPathFunctionResolver() { return staticContext.getXPathFunctionResolver(); } /** * Set the namespace context to be used. * @param namespaceContext The namespace context */ public void setNamespaceContext(NamespaceContext namespaceContext) { staticContext.setNamespaceContext(namespaceContext); } /** * Get the namespace context, if one has been set using {@link #setNamespaceContext} * @return the namespace context if set, or null otherwise */ public NamespaceContext getNamespaceContext() { return staticContext.getNamespaceContext(); } /** * Import a schema. This is possible only if Saxon-EE is being used, * and if the Configuration is an EnterpriseConfiguration. Having imported a schema, the types * defined in that schema become part of the static context. * @param source A Source object identifying the schema document to be loaded * @throws net.sf.saxon.type.SchemaException if the schema contained in this document is invalid * @throws UnsupportedOperationException if the configuration is not schema-aware */ public void importSchema(Source source) throws SchemaException { staticContext.importSchema(source); staticContext.setSchemaAware(true); } /** * Compile an XPath 2.0 expression * @param expr the XPath 2.0 expression to be compiled, as a string * @return the compiled form of the expression * @throws XPathExpressionException if there are any static errors in the expression. * Note that references to undeclared variables are not treated as static errors, because * variables are not pre-declared using this API. */ /*@NotNull*/ public XPathExpression compile(/*@Nullable*/ String expr) throws XPathExpressionException { if (expr == null) { throw new NullPointerException("expr"); } try { return createExpressionInternal(expr); } catch (net.sf.saxon.trans.XPathException e) { throw new XPathExpressionException(e); } } /** * Single-shot method to compile and execute an XPath 2.0 expression. * @param expr The XPath 2.0 expression to be compiled and executed * @param node The context node for evaluation of the expression. * *

This may be a NodeInfo object, representing a node in Saxon's native * implementation of the data model, or it may be a node in any supported * external object model: DOM, JDOM, DOM4J, or XOM, or any other model for * which support has been configured in the Configuration. Note that the * supporting libraries for the chosen model must be on the class path.

* *

Contrary to the interface specification, Saxon does not supply an empty * document when the value is null. This is because Saxon supports multiple object models, * and it's unclear what kind of document node would be appropriate. Instead, Saxon uses * the node supplied to the {@link #setContextNode} method if available, and if none * is available, executes the XPath expression with the context item undefined.

* * @param qName The type of result required. For details, see * {@link XPathExpressionImpl#evaluate(Object, javax.xml.namespace.QName)} * @return the result of evaluating the expression, returned as described in * {@link XPathExpressionImpl#evaluate(Object, javax.xml.namespace.QName)} * @throws XPathExpressionException if any static or dynamic error occurs * in evaluating the expression. */ public Object evaluate(String expr, Object node, QName qName) throws XPathExpressionException { XPathExpression exp = compile(expr); return exp.evaluate(node, qName); } /** * Single-shot method to compile an execute an XPath 2.0 expression, returning * the result as a string. * @param expr The XPath 2.0 expression to be compiled and executed * @param node The context node for evaluation of the expression * *

This may be a NodeInfo object, representing a node in Saxon's native * implementation of the data model, or it may be a node in any supported * external object model: DOM, JDOM, DOM4J, or XOM, or any other model for * which support has been configured in the Configuration. Note that the * supporting libraries for the chosen model must be on the class path.

* *

Contrary to the interface specification, Saxon does not supply an empty * document when the value is null. This is because Saxon supports multiple object models, * and it's unclear what kind of document node would be appropriate. Instead, Saxon uses * the node supplied to the {@link #setContextNode} method if available, and if none * is available, executes the XPath expression with the context item undefined.

* @return the result of evaluating the expression, converted to a string as if * by calling the XPath string() function * @throws XPathExpressionException if any static or dynamic error occurs * in evaluating the expression. */ public String evaluate(String expr, Object node) throws XPathExpressionException { XPathExpression exp = compile(expr); return exp.evaluate(node); } /** * Single-shot method to parse and build a source document, and * compile an execute an XPath 2.0 expression, against that document * @param expr The XPath 2.0 expression to be compiled and executed * @param inputSource The source document: this will be parsed and built into a tree, * and the XPath expression will be executed with the root node of the tree as the * context node. * @param qName The type of result required. For details, see * {@link XPathExpressionImpl#evaluate(Object, javax.xml.namespace.QName)} * @return the result of evaluating the expression, returned as described in * {@link XPathExpressionImpl#evaluate(Object, javax.xml.namespace.QName)} * @throws XPathExpressionException if any static or dynamic error occurs * in evaluating the expression. * @throws NullPointerException if any of the three arguments is null */ public Object evaluate(/*@Nullable*/ String expr, /*@Nullable*/ InputSource inputSource, /*@Nullable*/ QName qName) throws XPathExpressionException { if (expr == null) { throw new NullPointerException("expr"); } if (inputSource == null) { throw new NullPointerException("inputSource"); } if (qName == null) { throw new NullPointerException("qName"); } XPathExpression exp = compile(expr); return exp.evaluate(inputSource, qName); } /** * Single-shot method to parse and build a source document, and * compile an execute an XPath 2.0 expression, against that document, * returning the result as a string * @param expr The XPath 2.0 expression to be compiled and executed * @param inputSource The source document: this will be parsed and built into a tree, * and the XPath expression will be executed with the root node of the tree as the * context node * @return the result of evaluating the expression, converted to a string as * if by calling the XPath string() function * @throws XPathExpressionException if any static or dynamic error occurs * in evaluating the expression. * @throws NullPointerException if either of the two arguments is null */ public String evaluate(/*@Nullable*/ String expr, /*@Nullable*/ InputSource inputSource) throws XPathExpressionException { if (expr == null) { throw new NullPointerException("expr"); } if (inputSource == null) { throw new NullPointerException("inputSource"); } XPathExpression exp = compile(expr); return exp.evaluate(inputSource); } /** * A simple command-line interface for the XPathEvaluator (not documented). * @param args command line arguments. * First parameter is the filename containing the source document, second * parameter is the XPath expression. * @throws Exception if any error occurs */ public static void main(/*@NotNull*/ String[] args) throws Exception { if (args.length != 2) { System.err.println("format: java XPathEvaluator source.xml \"expression\""); return; } XPathEvaluator xpe = new XPathEvaluator(); List results = (List)xpe.evaluate(args[1], new StreamSource(new File(args[0])), XPathConstants.NODESET); for (int i = 0; i < results.size(); i++) { Object o = results.get(i); System.err.println(o); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/xpath/JAXPVariable.java0000644000175000017500000001347611671711573024415 0ustar mathieumathieupackage net.sf.saxon.xpath; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.IntegerValue; import net.sf.saxon.value.QNameValue; import net.sf.saxon.value.SequenceType; import javax.xml.namespace.QName; import javax.xml.xpath.XPathVariableResolver; /** * An object representing an XPath variable for use in the JAXP XPath API. The object * is created at compile time when the parser tries to bind a variable reference; the * value is fetched at run-time from the XPathVariableResolver. With this interface, * there is no way of reporting a static error if the variable has not been declared. *

* In Saxon terms, this class is both a VariableDeclaration and a Binding. Unlike * a normal VariableDeclaration, it isn't created in advance, but is created on demand * when the parser encounters a variable reference. This actually means that if the * XPath expression contains two references to the same variable, two VariableDeclarations * will be created; however, they will be indistinguishable to the VariableResolver. * Acting as a VariableDeclaration, the object goes through the motions of fixing up * a binding to a variable reference (in practice, of course, there is exactly one * reference to the variable). Acting as a run-time binding, it then evaluates the * variable by calling the XPathVariableResolver supplied by the API caller. If no * XPathVariableResolver was supplied, an error is reported when a variable is encountered; * but if the variable resolver doesn't recognize the variable name, it returns null, * which is treated as an empty sequence. *

*/ public final class JAXPVariable implements VariableDeclaration, Binding { private StructuredQName name; private XPathVariableResolver resolver; /** * Private constructor: for use only be the protected factory method make() * @param name the name of the variable * @param resolver the resolver used in conjunction with this variable */ protected JAXPVariable(StructuredQName name, XPathVariableResolver resolver) { this.name = name; this.resolver = resolver; } public SequenceType getRequiredType() { return SequenceType.ANY_SEQUENCE; } /** * Indicate whether the binding is local or global. A global binding is one that has a fixed * value for the life of a query or transformation; any other binding is local. */ public boolean isGlobal() { return true; } /** * Test whether it is permitted to assign to the variable using the saxon:assign * extension element. This will only be for an XSLT global variable where the extra * attribute saxon:assignable="yes" is present. */ public final boolean isAssignable() { return false; } /** * If this is a local variable held on the local stack frame, return the corresponding slot number. * In other cases, return -1. */ public int getLocalSlotNumber() { return -1; } /** * Get the name of the variable as a structured QName */ public StructuredQName getVariableQName() { return name; } public void addReference(boolean isLoopingReference) { } /** * Method called by the XPath expression parser to register a reference to this variable. * This method should not be called by users of the API. */ public void registerReference(/*@NotNull*/ BindingReference ref) { ref.setStaticType(SequenceType.ANY_SEQUENCE, null, 0); ref.fixup(this); } /** * Get the value of the variable. This method is used by the XPath execution engine * to retrieve the value. * @param context The dynamic evaluation context * @return The value of the variable */ public ValueRepresentation evaluateVariable(/*@NotNull*/ XPathContext context) throws XPathException { Configuration config = context.getConfiguration(); Object value = resolver.resolveVariable(name.toJaxpQName()); if (value == null) { return EmptySequence.getInstance(); } JPConverter converter = JPConverter.allocate(value.getClass(), config); return converter.convert(value, context); //return Value.convertJavaObjectToXPath(value, SequenceType.ANY_SEQUENCE, context); } /** * If the variable is bound to an integer, get the minimum and maximum possible values. * Return null if unknown or not applicable */ /*@Nullable*/ public IntegerValue[] getIntegerBoundsForVariable() { return null; } /** * Construct a JAXP QName from a Saxon QNameValue * @param in the Saxon QNameValue * @return the JAXP QName */ /*@NotNull*/ QName makeQName(/*@NotNull*/ QNameValue in) { return new QName(in.getNamespaceURI(), in.getLocalName(), in.getPrefix()); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/xpath/JAXPXPathStaticContext.java0000644000175000017500000003215011671711573026417 0ustar mathieumathieupackage net.sf.saxon.xpath; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.VariableReference; import net.sf.saxon.expr.instruct.SlotManager; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.sxpath.AbstractStaticContext; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaException; import javax.xml.XMLConstants; import javax.xml.namespace.NamespaceContext; import javax.xml.transform.Source; import javax.xml.xpath.XPathFunctionResolver; import javax.xml.xpath.XPathVariableResolver; import java.io.Serializable; import java.util.Arrays; import java.util.Iterator; import java.util.Set; /** * A JAXPXPathStaticContext provides a context for parsing an XPath expression * in a context other than a stylesheet. In particular, it is used to support * the JAXP 1.3 XPath API. The JAXP API does not actually expose the StaticContext * object directly; rather, the static context (namespaces, variables, and functions) * is manipulated through the XPath object, implemented in Saxon by the {@link XPathEvaluator} */ public class JAXPXPathStaticContext extends AbstractStaticContext implements StaticContext, NamespaceResolver { private SlotManager stackFrameMap; private XPathFunctionLibrary xpathFunctionLibrary; private NamespaceContext namespaceContext = new MinimalNamespaceContext(); private XPathVariableResolver variableResolver; /** * Create a JAXPXPathStaticContext using a specific Configuration. * @param config the Configuration. For schema-aware XPath expressions, this must be an EnterpriseConfiguration. */ public JAXPXPathStaticContext(/*@NotNull*/ Configuration config) { setConfiguration(config); stackFrameMap = config.makeSlotManager(); setDefaultFunctionLibrary(); xpathFunctionLibrary = new XPathFunctionLibrary(); addFunctionLibrary(xpathFunctionLibrary); } /** * Get the granularity of the container. * @return 0 for a temporary container created during parsing; 1 for a container * that operates at the level of an XPath expression; 2 for a container at the level * of a global function or template */ public int getContainerGranularity() { return 1; } /** * Supply the NamespaceContext used to resolve namespaces. */ public void setNamespaceContext(NamespaceContext context) { this.namespaceContext = context; } /** * Get the NamespaceContext that was set using {@link #setNamespaceContext} */ public NamespaceContext getNamespaceContext() { return namespaceContext; } /** * Get the stack frame map containing the slot number allocations for the variables declared * in this static context */ public SlotManager getStackFrameMap() { return stackFrameMap; } /** * Set an XPathVariableResolver. This is used to resolve variable references * if no variable has been explicitly declared. * @param resolver A JAXP 1.3 XPathVariableResolver */ public void setXPathVariableResolver(XPathVariableResolver resolver) { this.variableResolver = resolver; } /** * Get the XPathVariableResolver */ public XPathVariableResolver getXPathVariableResolver() { return variableResolver; } public void setXPathFunctionResolver(XPathFunctionResolver xPathFunctionResolver) { if (xpathFunctionLibrary != null) { xpathFunctionLibrary.setXPathFunctionResolver(xPathFunctionResolver); } } /*@Nullable*/ public XPathFunctionResolver getXPathFunctionResolver() { if (xpathFunctionLibrary != null) { return xpathFunctionLibrary.getXPathFunctionResolver(); } else { return null; } } /** * Get the URI for a prefix, using the declared namespaces as * the context for namespace resolution. The default namespace is NOT used * when the prefix is empty. * This method is provided for use by the XPath parser. * @param prefix The prefix * @throws net.sf.saxon.trans.XPathException if the prefix is not declared */ public String getURIForPrefix(/*@NotNull*/ String prefix) throws XPathException { String uri = getURIForPrefix(prefix, false); if (uri==null) { throw new XPathException("Prefix " + prefix + " has not been declared", "XPST0081"); } return uri; } /*@NotNull*/ public NamespaceResolver getNamespaceResolver() { return this; } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. This method searches * any namespace context supplied using {@link #setNamespaceContext(javax.xml.namespace.NamespaceContext)}. * @param prefix the namespace prefix * @param useDefault true if the default namespace for elements and types is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope. * Return "" if the prefix maps to the null namespace. */ public String getURIForPrefix(/*@NotNull*/ String prefix, boolean useDefault) { if (prefix.length()==0) { if (useDefault) { return getDefaultElementNamespace(); } else { return NamespaceConstant.NULL; } } else { return namespaceContext.getNamespaceURI(prefix); } } /** * Get an iterator over all the prefixes declared in this namespace context. This method is implemented * only in the case where the NamespaceContext supplied using {@link #setNamespaceContext} is an * instance of Saxon's {@link NamespaceResolver} class. In other cases the method throws an * UnsupportedOperationException * @return an iterator over all the inscope namespace prefixes, if available * @throws UnsupportedOperationException if the NamespaceContext object is not a NamespaceResolver. */ public Iterator iteratePrefixes() { if (namespaceContext instanceof NamespaceResolver) { return ((NamespaceResolver)namespaceContext).iteratePrefixes(); } else { throw new UnsupportedOperationException(); } } /** * Bind a variable used in an XPath Expression to the XSLVariable element in which it is declared. * This method is provided for use by the XPath parser, and it should not be called by the user of * the API. * * @throws XPathException if no VariableResolver has been supplied. * @param qName */ /*@NotNull*/ public final Expression bindVariable(StructuredQName qName) throws XPathException { // bindVariable is called at compile time, but the JAXP variable resolver // is designed to be called at run time. So we need to create a variable now, // which will call the variableResolver when called upon to return the run-time value if (variableResolver != null) { return new VariableReference(new JAXPVariable(qName, variableResolver)); } else { throw new XPathException( "Variable is used in XPath expression, but no JAXP VariableResolver is available"); } } /** * Import a schema. This is possible only if Saxon-EE is being used, * and if the Configuration is a EnterpriseConfiguration. Having imported a schema, the types * defined in that schema become part of the static context. * @param source A Source object identifying the schema document to be loaded * @throws net.sf.saxon.type.SchemaException if the schema contained in this document is invalid * @throws UnsupportedOperationException if the configuration is not schema-aware */ public void importSchema(Source source) throws SchemaException { getConfiguration().addSchemaSource(source, getConfiguration().getErrorListener()); setSchemaAware(true); } /** * Determine whether a Schema for a given target namespace has been imported. Note that the * in-scope element declarations, attribute declarations and schema types are the types registered * with the (schema-aware) configuration, provided that their namespace URI is registered * in the static context as being an imported schema namespace. (A consequence of this is that * within a Configuration, there can only be one schema for any given namespace, including the * null namespace). * @return true if schema components for the given namespace have been imported into the * schema-aware configuration */ public boolean isImportedSchema(String namespace) { return getConfiguration().isSchemaAvailable(namespace); } /** * Get the set of imported schemas * * @return a Set, the set of URIs representing the names of imported schemas */ public Set getImportedSchemaNamespaces() { return getConfiguration().getImportedNamespaces(); } /** * Define a minimal namespace context for use when no user-defined namespace context has been * registered */ private static class MinimalNamespaceContext implements NamespaceContext, NamespaceResolver, Serializable { /** * Get the namespace URI bound to a prefix in the current scope.

* @param prefix the prefix to look up * @return Namespace URI bound to prefix in the current scope */ /*@Nullable*/ public String getNamespaceURI(/*@Nullable*/ String prefix) { if (prefix == null) { throw new IllegalArgumentException("prefix"); } else if (prefix.equals(XMLConstants.DEFAULT_NS_PREFIX)) { return ""; //XMLConstants.NULL_NS_URI; } else if (prefix.equals("xml")) { return NamespaceConstant.XML; } else if (prefix.equals("xs")) { return NamespaceConstant.SCHEMA; } else if (prefix.equals("xsi")) { return NamespaceConstant.SCHEMA_INSTANCE; } else if (prefix.equals("saxon")) { return NamespaceConstant.SAXON; } else { return null; } } /** *

Get prefix bound to Namespace URI in the current scope.

* @throws UnsupportedOperationException (always) */ /*@NotNull*/ public String getPrefix(String namespaceURI) { throw new UnsupportedOperationException(); } /** *

Get all prefixes bound to a Namespace URI in the current * @throws UnsupportedOperationException (always) */ /*@NotNull*/ public Iterator getPrefixes(String namespaceURI) { throw new UnsupportedOperationException(); } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { String[] prefixes = {"", "xml", "xs", "xsi", "saxon"}; return Arrays.asList(prefixes).iterator(); } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix. May be the zero-length string, indicating * that there is no prefix. This indicates either the default namespace or the * null namespace, depending on the value of useDefault. * @param useDefault true if the default namespace is to be used when the * prefix is "". If false, the method returns "" when the prefix is "". * @return the uri for the namespace, or null if the prefix is not in scope. * The "null namespace" is represented by the pseudo-URI "". */ /*@Nullable*/ public String getURIForPrefix(String prefix, boolean useDefault) { return getNamespaceURI(prefix); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/xpath/package.html0000644000175000017500000000326411671711573023615 0ustar mathieumathieu Package overview for net.sf.saxon.xpath

This package is Saxon's implementation of the JAXP API designed for executing XPath 1.0 expressions directly from a Java application. Saxon extends the interface to handle XPath 2.0, though if the application makes extensive use of XPath 2.0 features, then the s9api interface offers a better fit to the XPath 2.0 data model. The API can be used either in a free-standing Java application (that is, where there is no XSLT stylesheet), or it can be used from within Java extension functions called from XPath expressions within a stylesheet.

The API itself is defined by JAXP 1.3, in interfaces such as javax.xml.xpath.XPath.< These interfaces are included in Java Standard Edition from JDK 1.5 onwards.

The interfaces provided by Saxon extend the JAXP 1.3 interfaces in various ways. There are three reasons for this:

  • Saxon supports XPath 2.0 rather than 1.0

  • The package retains support for some interfaces that were provided before JAXP 1.3 was released. (These might disappear in the course of time).

  • There are methods that allow an escape into Saxon's more low-level APIs, needed by anyone doing serious software integration.

An alternative XPath interface, which is not dependent on JAXP 1.3, is available in the package net.sf.saxon.sxpath. However, for most applications the preferred interface is the s9api {@link net.sf.saxon.s9api.XPathCompiler}

Michael H. Kay
Saxonica Limited
30 July 2010

saxonhe-9.4.0.7/src/main/java/net/sf/saxon/xpath/XPathFactoryImpl.java0000644000175000017500000002177211734613777025410 0ustar mathieumathieupackage net.sf.saxon.xpath; import net.sf.saxon.Configuration; import net.sf.saxon.lib.FeatureKeys; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.lib.Validation; import javax.xml.XMLConstants; import javax.xml.xpath.*; /** * Saxon implementation of the JAXP 1.3 XPathFactory */ public class XPathFactoryImpl extends XPathFactory { private Configuration config; private XPathVariableResolver variableResolver; private XPathFunctionResolver functionResolver; /** * Default constructor: this creates a Configuration as well as creating the XPathFactory. Any documents * accessed using this XPathFactory must be built using this same Configuration. */ public XPathFactoryImpl() { config = Configuration.newConfiguration(); setConfiguration(config); Configuration.getPlatform().registerAllBuiltInObjectModels(config); } /** * Constructor using a user-supplied Configuration. * This constructor is useful if the document to be queried already exists, as it allows the configuration * associated with the document to be used with this XPathFactory. * @param config the Saxon configuration */ public XPathFactoryImpl(Configuration config) { this.config = config; config.setProcessor(this); } /** * Set the Configuration for the factory * @param config the Saxon Configuration to be used */ public void setConfiguration(Configuration config) { this.config = config; config.setProcessor(this); } /** * Get the Configuration object used by this XPathFactory * @return the Saxon configuration */ public Configuration getConfiguration() { return config; } /** * Test whether a given object model is supported. Returns true if the object model * is the Saxon object model, DOM, JDOM, DOM4J, or XOM * @param model The URI identifying the object model. * @return true if the object model is one of the following (provided that the supporting * JAR file is available on the classpath) * {@link net.sf.saxon.lib.NamespaceConstant#OBJECT_MODEL_SAXON}, * {@link XPathConstants#DOM_OBJECT_MODEL}, * {@link net.sf.saxon.lib.NamespaceConstant#OBJECT_MODEL_JDOM}, or * {@link NamespaceConstant#OBJECT_MODEL_XOM}, or * {@link net.sf.saxon.lib.NamespaceConstant#OBJECT_MODEL_DOM4J}. * Saxon also allows user-defined external object models to be registered with the Configuration, and * this method will return true in respect of any such model. */ public boolean isObjectModelSupported(String model) { boolean debug = System.getProperty("jaxp.debug") != null; if (debug) { System.err.println("JAXP: Calling " + getClass().getName() + ".isObjectModelSupported(\"" + model + "\")"); System.err.println("JAXP: -- returning " + silentIsObjectModelSupported(model)); } return silentIsObjectModelSupported(model); } private boolean silentIsObjectModelSupported(String model) { return model.equals(NamespaceConstant.OBJECT_MODEL_SAXON) || config.getExternalObjectModel(model) != null; } /** * Set a feature of this XPath implementation. The features currently * recognized are: *
    *
  • {@link XMLConstants#FEATURE_SECURE_PROCESSING}
  • *
  • {@link net.sf.saxon.lib.FeatureKeys#SCHEMA_VALIDATION}: requests schema validation of source documents. * The property is rejected if the configuration is not schema-aware.
  • *
*

In addition, any Saxon configuration feature (listed in {@link FeatureKeys} can be used * provided the value is a boolean. (For non-boolean configuration properties, drop down to the underlying * Saxon {@link Configuration} object and call setConfigurationProperty())

* @param feature a URI identifying the feature * @param b true to set the feature on, false to set it off * @throws XPathFactoryConfigurationException if the feature name is not recognized */ public void setFeature(String feature, boolean b) throws XPathFactoryConfigurationException { if (feature.equals(FEATURE_SECURE_PROCESSING)) { config.setAllowExternalFunctions(!b); } else if (feature.equals(FeatureKeys.SCHEMA_VALIDATION)) { config.setSchemaValidationMode(b ? Validation.STRICT : Validation.STRIP); } else { try { config.setConfigurationProperty(feature, b); // TODO: it said 'true', register a bug } catch (IllegalArgumentException err) { throw new XPathFactoryConfigurationException("Unknown or non-boolean feature: " + feature); } } } /** * Get a feature of this XPath implementation. The only features currently * recognized are: *
    *
  • {@link #FEATURE_SECURE_PROCESSING}
  • *
  • {@link net.sf.saxon.lib.FeatureKeys#SCHEMA_VALIDATION}: requests schema validation of source documents.
  • *
*

In addition, any Saxon configuration feature (listed in {@link FeatureKeys} can be used * provided the value is a boolean. (For non-boolean configuration properties, drop down to the underlying * Saxon {@link Configuration} object and call getConfigurationProperty())

* @param feature a URI identifying the feature * @return true if the feature is on, false if it is off * @throws XPathFactoryConfigurationException if the feature name is not recognized */ public boolean getFeature(String feature) throws XPathFactoryConfigurationException { if (feature.equals(FEATURE_SECURE_PROCESSING)) { return !config.isAllowExternalFunctions(); } else if (feature.equals(FeatureKeys.SCHEMA_VALIDATION)) { return config.getSchemaValidationMode() == Validation.STRICT; } else { try { Object o = config.getConfigurationProperty(feature); if (o instanceof Boolean) { return ((Boolean)o); } else { throw new XPathFactoryConfigurationException( "Configuration property " + feature + " is not a boolean (it is an instance of " + o.getClass() + ")"); } } catch (IllegalArgumentException e) { throw new XPathFactoryConfigurationException("Unknown feature: " + feature); } } } /** * Set a resolver for XPath variables. This will be used to obtain the value of * any variable referenced in an XPath expression. The variable resolver must be allocated * before the expression is compiled, but it will only be called when the expression * is evaluated. * @param xPathVariableResolver The object used to resolve references to variables. */ public void setXPathVariableResolver(XPathVariableResolver xPathVariableResolver) { variableResolver = xPathVariableResolver; } /** * Set a resolver for XPath functions. This will be used to obtain an implementation * of any external function referenced in an XPath expression. This is not required for * system functions, Saxon extension functions, constructor functions named after types, * or extension functions bound using a namespace that maps to a Java class. * @param xPathFunctionResolver The object used to resolve references to external functions. */ public void setXPathFunctionResolver(XPathFunctionResolver xPathFunctionResolver) { functionResolver = xPathFunctionResolver; } /** * Create an XPath evaluator * @return an XPath object, which can be used to compile and execute XPath expressions. */ /*@NotNull*/ public XPath newXPath() { XPathEvaluator xpath = new XPathEvaluator(config); xpath.setXPathFunctionResolver(functionResolver); xpath.setXPathVariableResolver(variableResolver); return xpath; } private static String FEATURE_SECURE_PROCESSING = XMLConstants.FEATURE_SECURE_PROCESSING; // "http://javax.xml.XMLConstants/feature/secure-processing"; } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/xpath/XPathFunctionCall.java0000644000175000017500000001774711671711573025540 0ustar mathieumathieupackage net.sf.saxon.xpath; import net.sf.saxon.Configuration; import net.sf.saxon.expr.*; import net.sf.saxon.expr.parser.ExpressionVisitor; import net.sf.saxon.expr.parser.PathMap; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.iter.EmptyIterator; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.Type; import net.sf.saxon.type.TypeHierarchy; import net.sf.saxon.value.Value; import javax.xml.xpath.XPathFunction; import javax.xml.xpath.XPathFunctionException; import java.util.ArrayList; import java.util.List; /** * This class is an expression that calls an external function supplied using the * JAXP XPathFunction interface */ public class XPathFunctionCall extends FunctionCall implements CallableExpression { private XPathFunction function; /** * Default constructor */ public XPathFunctionCall(XPathFunction function) { this.function = function; } /** * preEvaluate: this method suppresses compile-time evaluation by doing nothing * (because the external function might have side-effects and might use the context) * @param visitor an expression visitor */ /*@NotNull*/ public Expression preEvaluate(ExpressionVisitor visitor) { return this; } /** * Method called by the expression parser when all arguments have been supplied */ public void checkArguments(/*@NotNull*/ ExpressionVisitor visitor) throws XPathException { } /** * Determine which aspects of the context the expression depends on. XPath external * functions are given no access to context information so they cannot have any * dependencies on it. */ public int getIntrinsicDependencies() { return 0; } /** * Copy an expression. This makes a deep copy. * * @return the copy of the original expression */ /*@NotNull*/ public Expression copy() { throw new UnsupportedOperationException("XPathFunctionCall.copy()"); } /** * Add a representation of this expression to a PathMap. The PathMap captures a map of the nodes visited * by an expression in a source tree. *

*

The default implementation of this method assumes that an expression does no navigation other than * the navigation done by evaluating its subexpressions, and that the subexpressions are evaluated in the * same context as the containing expression. The method must be overridden for any expression * where these assumptions do not hold. For example, implementations exist for AxisExpression, ParentExpression, * and RootExpression (because they perform navigation), and for the doc(), document(), and collection() * functions because they create a new navigation root. Implementations also exist for PathExpression and * FilterExpression because they have subexpressions that are evaluated in a different context from the * calling expression.

* * @param pathMap the PathMap to which the expression should be added * @param pathMapNodeSet * @return the pathMapNode representing the focus established by this expression, in the case where this * expression is the first operand of a path expression or filter expression. For an expression that does * navigation, it represents the end of the arc in the path map that describes the navigation route. For other * expressions, it is the same as the input pathMapNode. */ /*@NotNull*/ public PathMap.PathMapNodeSet addToPathMap(/*@NotNull*/ PathMap pathMap, PathMap.PathMapNodeSet pathMapNodeSet) { return addExternalFunctionCallToPathMap(pathMap, pathMapNodeSet); } /** * Evaluate the function.
* @param context The context in which the function is to be evaluated * @return a Value representing the result of the function. * @throws XPathException if the function cannot be evaluated. */ /*@NotNull*/ public SequenceIterator iterate(/*@NotNull*/ XPathContext context) throws XPathException { SequenceIterator[] argValues = new SequenceIterator[argument.length]; for (int i=0; iThis method will always return a result, though it may be the best approximation * that is available at the time.

* * @return the item type * @param th the type hierarchy cache */ /*@NotNull*/ public ItemType getItemType(TypeHierarchy th) { return Type.ITEM_TYPE; } /** * Determine the cardinality of the result * @return ZERO_OR_MORE (we don't know) */ public int computeCardinality() { return StaticProperty.ALLOWS_ZERO_OR_MORE; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/xpath/XPathFunctionLibrary.java0000644000175000017500000001240411671711573026252 0ustar mathieumathieupackage net.sf.saxon.xpath; import net.sf.saxon.expr.Container; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; import javax.xml.namespace.QName; import javax.xml.xpath.XPathFunction; import javax.xml.xpath.XPathFunctionResolver; /** * The XPathFunctionLibrary is a FunctionLibrary that supports binding of XPath function * calls to instances of the JAXP XPathFunction interface returned by an XPathFunctionResolver. */ public class XPathFunctionLibrary implements FunctionLibrary { private XPathFunctionResolver resolver; /** * Construct a XPathFunctionLibrary */ public XPathFunctionLibrary() { } /** * Set the resolver * @param resolver The XPathFunctionResolver wrapped by this FunctionLibrary */ public void setXPathFunctionResolver(XPathFunctionResolver resolver) { this.resolver = resolver; } /** * Get the resolver * @return the XPathFunctionResolver wrapped by this FunctionLibrary */ public XPathFunctionResolver getXPathFunctionResolver() { return resolver; } /** * Test whether a function with a given name and arity is available; if so, return its signature. * This supports the function-available() function in XSLT; it is also used to support * higher-order functions introduced in XQuery 1.1. For this function library the method is never * used and therefore returns null. * *

This method may be called either at compile time * or at run time. If the function library is to be used only in an XQuery or free-standing XPath * environment, this method may throw an UnsupportedOperationException.

* @param functionName the qualified name of the function being called * @param arity The number of arguments. This is set to -1 in the case of the single-argument * function-available() function; in this case the method should return true if there is some * function of this name available for calling. * @return if a function of this name and arity is available for calling, then the type signature of the * function, as an array of sequence types in which the zeroth entry represents the return type; or a zero-length * array if the function exists but the signature is not known; or null if the function does not exist */ /*@Nullable*/ public SequenceType[] getFunctionSignature(StructuredQName functionName, int arity) { return null; } /** * Bind a function, given the URI and local parts of the function name, * and the list of expressions supplied as arguments. This method is called at compile * time. * @param functionName * @param staticArgs The expressions supplied statically in the function call. The intention is * that the static type of the arguments (obtainable via getItemType() and getCardinality() may * be used as part of the binding algorithm. * @param env * @param container * @return An object representing the extension function to be called, if one is found; * null if no extension function was found matching the required name, arity, or signature. */ /*@Nullable*/ public Expression bind(/*@NotNull*/ StructuredQName functionName, /*@NotNull*/ Expression[] staticArgs, StaticContext env, Container container) throws XPathException { if (resolver == null) { return null; } QName name = new QName(functionName.getURI(), functionName.getLocalPart()); XPathFunction function = resolver.resolveFunction(name, staticArgs.length); if (function == null) { return null; } XPathFunctionCall fc = new XPathFunctionCall(function); fc.setArguments(staticArgs); return fc; } /** * This method creates a copy of a FunctionLibrary: if the original FunctionLibrary allows * new functions to be added, then additions to this copy will not affect the original, or * vice versa. * * @return a copy of this function library. This must be an instance of the original class. */ /*@NotNull*/ public FunctionLibrary copy() { XPathFunctionLibrary xfl = new XPathFunctionLibrary(); xfl.resolver = resolver; return xfl; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/0000755000175000017500000000000012213124634021151 5ustar mathieumathieusaxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/ComplexType.java0000644000175000017500000002641711671711573024312 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.expr.sort.IntHashSet; /** * A complex type as defined in XML Schema: either a user-defined complex type, or xs:anyType, or xs:untyped. * In the non-schema-aware version of the Saxon product, the only complex type encountered is xs:untyped. */ public interface ComplexType extends SchemaType { public static final int VARIETY_EMPTY = 0; public static final int VARIETY_SIMPLE = 1; public static final int VARIETY_ELEMENT_ONLY = 2; public static final int VARIETY_MIXED = 3; public static final int OPEN_CONTENT_ABSENT = 0; public static final int OPEN_CONTENT_NONE = 1; public static final int OPEN_CONTENT_INTERLEAVE = 2; public static final int OPEN_CONTENT_SUFFIX = 3; /** * Get the variety of this complex type. This will be one of the values * {@link #VARIETY_EMPTY}, {@link #VARIETY_MIXED}, {@link #VARIETY_SIMPLE}, or * {@link #VARIETY_ELEMENT_ONLY} */ public int getVariety(); /** * Test whether this complex type has been marked as abstract. This corresponds to * the {abstract} property in the schema component model. * * @return true if this complex type is abstract. */ public boolean isAbstract(); /** * Test whether this complex type has complex content. This represents one aspect of the * {content type} property in the schema component model. * * @return true if and only if this complex type has a complex content model, that is, if its variety is one * of empty, mixed, or element-only. */ public boolean isComplexContent(); /** * Test whether this complexType has simple content. This represents one aspect of the * {content type} property in the schema component model. * * @return true if and only if this complex type has a simple content model, that is, if its variety is simple. */ public boolean isSimpleContent(); /** * Test whether this complex type has "all" content, that is, a content model * using an xs:all compositor * @return true if the type has an "all" content model */ public boolean isAllContent(); /** * Get the simple content type. This represents one aspect of the * {content type} property in the schema component model. * * @return For a complex type with simple content, returns the simple type of the content. * Otherwise, returns null. */ /*@Nullable*/ public SimpleType getSimpleContentType(); /** * Test whether this complex type is derived by restriction. This corresponds to one * aspect of the {derivation method} property in the schema component model. * * @return true if this complex type is derived by restriction */ public boolean isRestricted(); /** * Test whether the content model of this complex type is empty. This represents one aspect of the * {content type} property in the schema component model. * * @return true if the content model is defined as empty */ public boolean isEmptyContent(); /** * Test whether the content model of this complex type allows empty content. This property applies only if * this is a complex type with complex content. * * @return true if empty content is valid */ public boolean isEmptiable() throws SchemaException; /** * Test whether this complex type allows mixed content. This represents one aspect of the * {content type} property in the schema component model. This property applies only if * this is a complex type with complex content. * * @return true if mixed content is allowed */ public boolean isMixedContent(); /** * Find an element particle within this complex type definition having a given element name * (identified by fingerprint), and return the schema type associated with that element particle. * If there is no such particle, return null. If the fingerprint matches an element wildcard, * return the type of the global element declaration with the given name if one exists, or AnyType * if none exists and lax validation is permitted by the wildcard. * @param fingerprint Identifies the name of the child element within this content model * @param considerExtensions * @return the schema type associated with the child element particle with the given name. * If there is no such particle, return null. */ /*@Nullable*/ public SchemaType getElementParticleType(int fingerprint, boolean considerExtensions) throws SchemaException, ValidationException; /** * Find an element particle within this complex type definition having a given element name * (identified by fingerprint), and return the cardinality associated with that element particle, * that is, the number of times the element can occur within this complex type. The value is one of * {@link net.sf.saxon.expr.StaticProperty#EXACTLY_ONE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_ONE}, * {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_MORE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ONE_OR_MORE}, * If there is no such particle, return {@link net.sf.saxon.expr.StaticProperty#EMPTY}. * @param fingerprint Identifies the name of the child element within this content model * @param considerExtensions * @return the cardinality associated with the child element particle with the given name. * If there is no such particle, return {@link net.sf.saxon.expr.StaticProperty#EMPTY}. */ public int getElementParticleCardinality(int fingerprint, boolean considerExtensions) throws SchemaException, ValidationException; /** * Find an attribute use within this complex type definition having a given attribute name * (identified by fingerprint), and return the schema type associated with that attribute. * If there is no such attribute use, return null. If the fingerprint matches an attribute wildcard, * return the type of the global attribute declaration with the given name if one exists, or AnySimpleType * if none exists and lax validation is permitted by the wildcard. *

* If there are types derived from this type by extension, search those too. * @param fingerprint Identifies the name of the child element within this content model * @return the schema type associated with the attribute use identified by the fingerprint. * If there is no such attribute use, return null. */ /*@Nullable*/ public SimpleType getAttributeUseType(int fingerprint) throws SchemaException; /** * Find an attribute use within this complex type definition having a given attribute name * (identified by fingerprint), and return the cardinality associated with that attribute, * which will always be 0, 1, or 0-or-1. * If there is no such attribute use, return 0. If the fingerprint matches an attribute wildcard, * return 0-or-1. *

* If there are types derived from this type by extension, search those too. * @param fingerprint Identifies the name of the child element within this content model * @return the cardinality associated with the attribute use identified by the fingerprint. */ public int getAttributeUseCardinality(int fingerprint) throws SchemaException; /** * Return true if this type (or any known type derived from it by extension) allows the element * to have one or more attributes. * @return true if attributes (other than the standard xsi: attributes) are allowed. The value * false indicates that only the standard attributes in the xsi namespace are permitted. */ public boolean allowsAttributes(); /** * Get a list of all the names of elements that can appear as children of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), return null. * @param children an integer set, initially empty, which on return will hold the fingerprints of all permitted * child elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the children, typically because of wildcards. In this case the other contents of the set should * @param ignoreWildcards */ public void gatherAllPermittedChildren(IntHashSet children, boolean ignoreWildcards) throws SchemaException; /** * Get a list of all the names of elements that can appear as descendants of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), include a -1 in the result. * @param descendants an integer set, initially empty, which on return will hold the fingerprints of all permitted * descendant elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the descendants, typically because of wildcards. In this case the other contents of the set should * be ignored. */ public void gatherAllPermittedDescendants(IntHashSet descendants) throws SchemaException; /** * Assuming an element is a permitted descendant in the content model of this type, determine * the type of the element when it appears as a descendant. If it appears with more than one type, * return xs:anyType. * @param fingerprint the name of the required descendant element * @return the type of the descendant element; null if the element cannot appear as a descendant; * anyType if it can appear with several different types */ /*@Nullable*/ public SchemaType getDescendantElementType(int fingerprint) throws SchemaException; /** * Assuming an element is a permitted descendant in the content model of this type, determine * the cardinality of the element when it appears as a descendant. * @param fingerprint the name of the required descendant element * @return the cardinality of the descendant element within this complex type */ public int getDescendantElementCardinality(int fingerprint) throws SchemaException; /** * Ask whether this type (or any known type derived from it by extension) allows the element * to have children that match a wildcard * @return true if the content model of this type, or its extensions, contains an element wildcard */ boolean containsElementWildcard(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/ItemType.java0000644000175000017500000001543211671711573023574 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.trans.XPathException; import java.io.Serializable; /** * ItemType is an interface that allows testing of whether an Item conforms to an * expected type. ItemType represents the types in the type hierarchy in the XPath model, * as distinct from the schema model: an item type is either item() (matches everything), * a node type (matches nodes), an atomic type (matches atomic values), or empty() * (matches nothing). Atomic types, represented by the class AtomicType, are also * instances of SimpleType in the schema type hierarchy. Node Types, represented by * the class NodeTest, are also Patterns as used in XSLT. * *

Saxon assumes that apart from {@link AnyItemType} (which corresponds to item() * and matches anything), every ItemType will be either an {@link AtomicType}, a {@link net.sf.saxon.pattern.NodeTest}, * or a {@link FunctionItemType}. User-defined implementations of ItemType must therefore extend one of those * three classes/interfaces.

* @see AtomicType * @see net.sf.saxon.pattern.NodeTest * @see FunctionItemType */ public interface ItemType extends Serializable { /** * Determine whether this item type is an atomic type * @return true if this is ANY_ATOMIC_TYPE or a subtype thereof */ public boolean isAtomicType(); /** * Determine whether this item type is a plain type (that is, whether it can ONLY match * atomic values) * @return true if this is ANY_ATOMIC_TYPE or a subtype thereof, or a * "plain" union type (that is, unions of atomic types that impose no further restrictions) */ public boolean isPlainType(); /** * Test whether a given item conforms to this type * @param item The item to be tested * @param context the XPath dynamic evaluation context * @return true if the item is an instance of this type; false otherwise */ public boolean matches(Item item, XPathContext context); /** * Test whether a given item conforms to this type * @param item The item to be tested * @param allowURIPromotion if a URI value is to be treated as a string * @param config the Saxon configuration * @return true if the item is an instance of this type; false otherwise */ public boolean matchesItem(Item item, boolean allowURIPromotion, Configuration config); /** * Get the type from which this item type is derived by restriction. This * is the supertype in the XPath type heirarchy, as distinct from the Schema * base type: this means that the supertype of xs:boolean is xs:anyAtomicType, * whose supertype is item() (rather than xs:anySimpleType). *

* In fact the concept of "supertype" is not really well-defined, because the types * form a lattice rather than a hierarchy. The only real requirement on this function * is that it returns a type that strictly subsumes this type, ideally as narrowly * as possible. * @return the supertype, or null if this type is item() * @param th the type hierarchy cache */ /*@Nullable*/ public ItemType getSuperType(TypeHierarchy th); /** * Get the primitive item type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue and union types it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that integer, xs:dayTimeDuration, and xs:yearMonthDuration * are considered to be primitive types. * @return the corresponding primitive type */ /*@NotNull*/ public ItemType getPrimitiveItemType(); /** * Get the primitive type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is BuiltInAtomicType.ANY_ATOMIC. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. * @return the integer fingerprint of the corresponding primitive type */ public int getPrimitiveType(); /** * Determine the default priority of this item type when used on its own as a Pattern * @return the default priority */ public abstract double getDefaultPriority(); /** * Produce a representation of this type name for use in error messages. * Where this is a QName, it will use conventional prefixes * @param pool the name pool * @return a string representation of the type, in notation resembling but not necessarily * identical to XPath syntax */ /*@Nullable*/ public String toString(NamePool pool); /** * Get the item type of the atomic values that will be produced when an item * of this type is atomized * @return the best available item type of the atomic values that will be produced when an item * of this type is atomized */ /*@NotNull*/ public PlainType getAtomizedItemType(); /** * Ask whether values of this type are atomizable * @return true unless it is known that these items will be elements with element-only * content, or function items, in which case return false */ public boolean isAtomizable(); /** * Visit all the schema components used in this ItemType definition * @param visitor the visitor class to be called when each component is visited * @throws net.sf.saxon.trans.XPathException if an error occurs */ public void visitNamedSchemaComponents(SchemaComponentVisitor visitor) throws XPathException; } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/AnyFunctionType.java0000644000175000017500000002122311671711573025126 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.TypeCheckerEnvironment; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.parser.RoleLocator; import net.sf.saxon.om.FunctionItem; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; /** * An ItemType representing the type function(). Subtypes represent function items with more specific * type signatures. */ public class AnyFunctionType implements FunctionItemType { /*@NotNull*/ public static AnyFunctionType ANY_FUNCTION = new AnyFunctionType(); public static SequenceType SINGLE_FUNCTION = SequenceType.makeSequenceType(ANY_FUNCTION, StaticProperty.EXACTLY_ONE); /** * Get the singular instance of this type (Note however that subtypes of this type * may have any number of instances) */ /*@NotNull*/ public static AnyFunctionType getInstance() { return ANY_FUNCTION; } /** * Determine whether this item type is an atomic type * * @return true if this is ANY_ATOMIC_TYPE or a subtype thereof */ public boolean isAtomicType() { return false; } /** * Determine whether this item type is atomic (that is, whether it can ONLY match * atomic values) * @return true if this is ANY_ATOMIC_TYPE or a subtype thereof */ public boolean isPlainType() { return false; } /** * Ask whether this function item type is a map type. In this case function coercion (to the map type) * will never succeed. * * @return true if this FunctionItemType is a map type */ public boolean isMapType() { return false; } /** * Get the argument types of the function * @return the argument types, as an array of SequenceTypes, or null if this is the generic function * type function(*) */ /*@Nullable*/ public SequenceType[] getArgumentTypes() { return null; } /** * Test whether a given item conforms to this type * * @param item The item to be tested * @param context the XPath dynamic evaluation context * @return true if the item is an instance of this type; false otherwise */ public boolean matches(Item item, /*@NotNull*/ XPathContext context) { return matchesItem(item, false, context.getConfiguration()); } /** * Test whether a given item conforms to this type * @param item The item to be tested * @param allowURIPromotion * @param config * @return true if the item is an instance of this type; false otherwise */ public boolean matchesItem(Item item, boolean allowURIPromotion, Configuration config) { return (item instanceof FunctionItem); } /** * Get the type from which this item type is derived by restriction. This * is the supertype in the XPath type heirarchy, as distinct from the Schema * base type: this means that the supertype of xs:boolean is xs:anyAtomicType, * whose supertype is item() (rather than xs:anySimpleType). *

* In fact the concept of "supertype" is not really well-defined, because the types * form a lattice rather than a hierarchy. The only real requirement on this function * is that it returns a type that strictly subsumes this type, ideally as narrowly * as possible. * @param th the type hierarchy cache * @return the supertype, or null if this type is item() */ public ItemType getSuperType(TypeHierarchy th) { return AnyItemType.getInstance(); } /** * Get the primitive item type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that integer, xs:dayTimeDuration, and xs:yearMonthDuration * are considered to be primitive types. For function items it is the singular * instance FunctionItemType.getInstance(). */ /*@NotNull*/ public ItemType getPrimitiveItemType() { return ANY_FUNCTION; } /** * Get the primitive type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ public int getPrimitiveType() { return Type.FUNCTION; } /** * Produce a representation of this type name for use in error messages. * @param pool the name pool * @return a string representation of the type, in notation resembling but not necessarily * identical to XPath syntax */ public String toString(NamePool pool) { return "function()"; } /** * Produce a representation of this type name for use in error messages. * @return a string representation of the type, in notation resembling but not necessarily * identical to XPath syntax */ public String toString() { return "function()"; } /** * Get the item type of the atomic values that will be produced when an item * of this type is atomized * @return the item type of the atomic values that will be produced when an item * of this type is atomized */ /*@NotNull*/ public AtomicType getAtomizedItemType() { return null; } /** * Ask whether values of this type are atomizable * @return true unless it is known that these items will be elements with element-only * content, in which case return false */ public boolean isAtomizable() { return false; } /** * Determine the relationship of one function item type to another * @return for example {@link TypeHierarchy#SUBSUMES}, {@link TypeHierarchy#SAME_TYPE} */ public int relationship(FunctionItemType other, TypeHierarchy th) { if (other == this) { return TypeHierarchy.SAME_TYPE; } else { return TypeHierarchy.SUBSUMES; } } /** * Create an expression whose effect is to apply function coercion to coerce a function from this type to another type * @param exp the expression that delivers the supplied sequence of function items (the ones in need of coercion) * @param role information for use in diagnostics * @param visitor the expression visitor, supplies context information * @return the coerced function, a function that calls the original function after checking the parameters */ public Expression makeFunctionSequenceCoercer(Expression exp, RoleLocator role, TypeCheckerEnvironment visitor) throws XPathException { return exp; } /** * Visit all the schema components used in this ItemType definition * @param visitor the visitor class to be called when each component is visited */ public void visitNamedSchemaComponents(SchemaComponentVisitor visitor) throws XPathException { // no action } /** * Get the result type * @return the result type */ public SequenceType getResultType() { return SequenceType.ANY_SEQUENCE; } public double getDefaultPriority() { return 0.5; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/Type.java0000644000175000017500000004055411671711573022760 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.om.FunctionItem; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StandardNames; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.EmptySequenceTest; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.ObjectValue; import java.io.Serializable; /** * This class contains static information about types and methods for constructing type codes. * The class is never instantiated. * *

The constant integers used for type names in earlier versions of this class have been replaced * by constants in {@link StandardNames}. The constants representing {@link AtomicType} objects are now * available through the {@link BuiltInAtomicType} class.

* */ public abstract class Type implements Serializable { // Note that the integer codes representing node kinds are the same as // the codes allocated in the DOM interface, while the codes for built-in // atomic types are fingerprints allocated in StandardNames. These two sets of // codes must not overlap! /** * Type representing an element node - element() */ public static final short ELEMENT = 1; /** * Item type representing an attribute node - attribute() */ public static final short ATTRIBUTE = 2; /** * Item type representing a text node - text() */ public static final short TEXT = 3; /** * Item type representing a text node stored in the tiny tree as compressed whitespace */ public static final short WHITESPACE_TEXT = 4; /** * Item type representing a processing-instruction node */ public static final short PROCESSING_INSTRUCTION = 7; /** * Item type representing a comment node */ public static final short COMMENT = 8; /** * Item type representing a document node */ public static final short DOCUMENT = 9; /** * Item type representing a namespace node */ public static final short NAMESPACE = 13; /** * Dummy node kind used in the tiny tree to mark the end of the tree */ public static final short STOPPER = 11; /** * Dummy node kind used in the tiny tree to contain a parent pointer */ public static final short PARENT_POINTER = 12; /** * An item type that matches any node */ public static final short NODE = 0; public static final ItemType NODE_TYPE = AnyNodeTest.getInstance(); /** * An item type that matches any item */ public static final short ITEM = 88; /*@NotNull*/ public static final ItemType ITEM_TYPE = AnyItemType.getInstance(); /** * A type number for function() */ public static final short FUNCTION = 99; public static final short MAX_NODE_TYPE = 13; /** * Item type that matches no items (corresponds to SequenceType empty()) */ public static final short EMPTY = 15; // a test for this type will never be satisfied private Type() { } /** * Test whether a given type is (some subtype of) node() * * @param type The type to be tested * @return true if the item type is node() or a subtype of node() */ public static boolean isNodeType(ItemType type) { return type instanceof NodeTest; } /** * Get the ItemType of an Item * @param item the item whose type is required * @param th the type hierarchy cache. If null, the returned type may be less precise * @return the item type of the item */ /*@NotNull*/ public static ItemType getItemType(/*@NotNull*/ Item item, /*@Nullable*/ TypeHierarchy th) { if (item instanceof AtomicValue) { return ((AtomicValue)item).getItemType(th); } else if (item instanceof NodeInfo) { return NodeKindTest.makeNodeKindTest(((NodeInfo)item).getNodeKind()); // We could return a more precise type than this, for example one that includes // a ContentTypeTest for the type annotation of the nodes. However, given the way in which // this method is used, this wouldn't be very useful } else { //if (item instanceof FunctionItem) { return ((FunctionItem)item).getFunctionItemType(th); } } /** * Output (for diagnostics) a representation of the type of an item. This * does not have to be the most specific type * @param item the item whose type is to be displayed * @return a string representation of the type of the item */ public static String displayTypeName(/*@NotNull*/ Item item) { if (item instanceof NodeInfo) { NodeInfo node = (NodeInfo)item; switch (node.getNodeKind()) { case DOCUMENT: return "document-node()"; case ELEMENT: SchemaType annotation = node.getSchemaType(); return "element(" + ((NodeInfo)item).getDisplayName() + ", " + (annotation.getDisplayName() + ')'); case ATTRIBUTE: SchemaType annotation2 = node.getSchemaType(); return "attribute(" + ((NodeInfo)item).getDisplayName()+ ", " + annotation2.getDisplayName() + ')'; case TEXT: return "text()"; case COMMENT: return "comment()"; case PROCESSING_INSTRUCTION: return "processing-instruction()"; case NAMESPACE: return "namespace()"; default: return ""; } } else if (item instanceof ObjectValue) { return ((ObjectValue)item).displayTypeName(); } else { return ((AtomicValue)item).getItemType(null).toString(); } } /** * Get the ItemType object for a built-in atomic type * @param namespace the namespace URI of the type * @param localName the local name of the type * @return the ItemType, or null if not found */ /*@Nullable*/ public static ItemType getBuiltInItemType(String namespace, String localName) { SchemaType t = BuiltInType.getSchemaType( StandardNames.getFingerprint(namespace, localName)); if (t instanceof ItemType) { return (ItemType)t; } else { return null; } } /** * Get the SimpleType object for a built-in simple type (atomic type or list type) * @param namespace the namespace URI of the type * @param localName the local name of the type * @return the SimpleType, or null if not found */ /*@Nullable*/ public static SimpleType getBuiltInSimpleType(String namespace, String localName) { SchemaType t = BuiltInType.getSchemaType( StandardNames.getFingerprint(namespace, localName)); if (t instanceof SimpleType && ((SimpleType) t).isBuiltInType()) { return (SimpleType)t; } else { return null; } } /** * Get a type that is a common supertype of two given item types * * @param t1 the first item type * @param t2 the second item type * @param th the type hierarchy cache * @return the item type that is a supertype of both * the supplied item types */ /*@NotNull*/ public static ItemType getCommonSuperType(/*@NotNull*/ ItemType t1, /*@NotNull*/ ItemType t2, /*@NotNull*/ TypeHierarchy th) { if (t1 == t2) { return t1; } if (t1 instanceof EmptySequenceTest) { return t2; } if (t2 instanceof EmptySequenceTest) { return t1; } int r = th.relationship(t1, t2); if (r == TypeHierarchy.SAME_TYPE) { return t1; } else if (r == TypeHierarchy.SUBSUMED_BY) { return t2; } else if (r == TypeHierarchy.SUBSUMES) { return t1; } else { ItemType st = t2.getSuperType(th); if (st == null) { return AnyItemType.getInstance(); } else { return getCommonSuperType(st, t1, th); } // eventually we will hit a type that is a supertype of t2. We reverse // the arguments so we go up each branch of the tree alternately. // If we hit the root of the tree, one of the earlier conditions will be satisfied, // so the recursion will stop. } } /** * Get a type that is a common supertype of two given item types, without the benefit of a TypeHierarchy cache. * This will generally give a less precise answer than the method {@link #getCommonSuperType(ItemType, ItemType, TypeHierarchy)} * * @param t1 the first item type * @param t2 the second item type * @return an item type that is a supertype of both the supplied item types */ /*@NotNull*/ public static ItemType getCommonSuperType(/*@NotNull*/ ItemType t1, /*@NotNull*/ ItemType t2) { if (t1 == t2) { return t1; } if (t1 instanceof EmptySequenceTest) { return t2; } if (t2 instanceof EmptySequenceTest) { return t1; } if (t1 == AnyItemType.getInstance() || t2 == AnyItemType.getInstance()) { return AnyItemType.getInstance(); } if (t1.getPrimitiveItemType() == t2.getPrimitiveItemType()) { return t1.getPrimitiveItemType(); } if (t1.isAtomicType() && t2.isAtomicType()) { return BuiltInAtomicType.ANY_ATOMIC; } if (t1 instanceof NodeTest && t2 instanceof NodeTest) { return AnyNodeTest.getInstance(); } if (t1 instanceof FunctionItemType && t2 instanceof FunctionItemType) { return AnyFunctionType.getInstance(); } return AnyItemType.getInstance(); } /** * Determine whether this type is a primitive type. The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration; * xs:untypedAtomic; the 7 node kinds; and all supertypes of these (item(), node(), xs:anyAtomicType, * xs:numeric, ...) * @param code the item type code to be tested * @return true if the type is considered primitive under the above rules */ public static boolean isPrimitiveType(int code) { return code >= 0 && (code <= StandardNames.XS_INTEGER || code == StandardNames.XS_NUMERIC || code == StandardNames.XS_UNTYPED_ATOMIC || code == StandardNames.XS_ANY_ATOMIC_TYPE || code == StandardNames.XS_DAY_TIME_DURATION || code == StandardNames.XS_YEAR_MONTH_DURATION || code == StandardNames.XS_ANY_SIMPLE_TYPE); } /** * Determine whether two primitive atomic types are comparable under the rules for ValueComparisons * (that is, untyped atomic values treated as strings) * @param t1 the first type to compared. * This must be a primitive atomic type as defined by {@link ItemType#getPrimitiveType} * @param t2 the second type to compared. * This must be a primitive atomic type as defined by {@link ItemType#getPrimitiveType} * @param ordered true if testing for an ordering comparison (lt, gt, le, ge). False * if testing for an equality comparison (eq, ne) * @return true if the types are comparable, as defined by the rules of the "eq" operator */ public static boolean isComparable(/*@NotNull*/ BuiltInAtomicType t1, /*@NotNull*/ BuiltInAtomicType t2, boolean ordered) { if (t1 == t2) { return true; // short cut } if (t1.equals(BuiltInAtomicType.ANY_ATOMIC) || t2.equals(BuiltInAtomicType.ANY_ATOMIC)) { return true; // meaning we don't actually know at this stage } if (t1.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { t1 = BuiltInAtomicType.STRING; } if (t2.equals(BuiltInAtomicType.UNTYPED_ATOMIC)) { t2 = BuiltInAtomicType.STRING; } if (t1.equals(BuiltInAtomicType.ANY_URI)) { t1 = BuiltInAtomicType.STRING; } if (t2.equals(BuiltInAtomicType.ANY_URI)) { t2 = BuiltInAtomicType.STRING; } if (t1.isPrimitiveNumeric()) { t1 = BuiltInAtomicType.NUMERIC; } if (t2.isPrimitiveNumeric()) { t2 = BuiltInAtomicType.NUMERIC; } if (!ordered) { if (t1.equals(BuiltInAtomicType.DAY_TIME_DURATION)) { t1 = BuiltInAtomicType.DURATION; } if (t2.equals(BuiltInAtomicType.DAY_TIME_DURATION)) { t2 = BuiltInAtomicType.DURATION; } if (t1.equals(BuiltInAtomicType.YEAR_MONTH_DURATION)) { t1 = BuiltInAtomicType.DURATION; } if (t2.equals(BuiltInAtomicType.YEAR_MONTH_DURATION)) { t2 = BuiltInAtomicType.DURATION; } } return t1 == t2; } /** * Determine whether two primitive atomic types are comparable under the rules for GeneralComparisons * (that is, untyped atomic values treated as comparable to anything) * @param t1 the first type to compared. * This must be a primitive atomic type as defined by {@link ItemType#getPrimitiveType} * @param t2 the second type to compared. * This must be a primitive atomic type as defined by {@link ItemType#getPrimitiveType} * @param ordered true if testing for an ordering comparison (lt, gt, le, ge). False * if testing for an equality comparison (eq, ne) * @return true if the types are comparable, as defined by the rules of the "=" operator */ public static boolean isGenerallyComparable(/*@NotNull*/ BuiltInAtomicType t1, /*@NotNull*/ BuiltInAtomicType t2, boolean ordered) { return t1.equals(BuiltInAtomicType.ANY_ATOMIC) || t2.equals(BuiltInAtomicType.ANY_ATOMIC) || t1.equals(BuiltInAtomicType.UNTYPED_ATOMIC) || t2.equals(BuiltInAtomicType.UNTYPED_ATOMIC) || isComparable(t1, t2, ordered); } /** * Determine whether two primitive atomic types are guaranteed comparable under the rules for GeneralComparisons * (that is, untyped atomic values treated as comparable to anything). This method returns false if a run-time * check is necessary. * @param t1 the first type to compared. * This must be a primitive atomic type as defined by {@link ItemType#getPrimitiveType} * @param t2 the second type to compared. * This must be a primitive atomic type as defined by {@link ItemType#getPrimitiveType} * @param ordered true if testing for an ordering comparison (lt, gt, le, ge). False * if testing for an equality comparison (eq, ne) * @return true if the types are comparable, as defined by the rules of the "=" operator */ public static boolean isGuaranteedGenerallyComparable(/*@NotNull*/ BuiltInAtomicType t1, /*@NotNull*/ BuiltInAtomicType t2, boolean ordered) { return !(t1.equals(BuiltInAtomicType.ANY_ATOMIC) || t2.equals(BuiltInAtomicType.ANY_ATOMIC)) && isGenerallyComparable(t1, t2, ordered); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/ConversionResult.java0000644000175000017500000000370311671711573025356 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.value.AtomicValue; /** * This is a marker interface used as the result methods that convert or cast values from one type * to another. It is implemented by AtomicValue, which indicates a successful conversion, and by * ValidationFailure, which indicates an unsuccessful conversion. An unsuccessful conversion does not * throw an exception because exceptions are expensive and should not be used on success paths. For example * when validating a union, conversion failures are to be expected. */ public interface ConversionResult { /** * Calling this method on a ConversionResult returns the AtomicValue that results * from the conversion if the conversion was successful, and throws a ValidationException * explaining the conversion error otherwise. * *

Use this method if you are calling a conversion method that returns a ConversionResult, * and if you want to throw an exception if the conversion fails.

* * @return the atomic value that results from the conversion if the conversion was successful * @throws ValidationException if the conversion was not successful */ public AtomicValue asAtomic() throws ValidationException; } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/SchemaType.java0000644000175000017500000003401711671711573024076 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.Value; /** * SchemaType is an interface implemented by all schema types: simple and complex types, built-in and * user-defined types. * *

There is a hierarchy of interfaces that extend SchemaType, representing the top levels of the schema * type system: SimpleType and ComplexType, with SimpleType further subdivided into List, Union, and Atomic * types.

* *

The implementations of these interfaces are organized into a different hierarchy: on the one side, * built-in types such as AnyType, AnySimpleType, and the built-in atomic types and list types; on the other * side, user-defined types defined in a schema.

*/ public interface SchemaType extends SchemaComponent { // DerivationMethods. These constants are copied from org.w3.dom.TypeInfo. They are redefined here to avoid // creating a dependency on the TypeInfo class, which is only available when JAXP 1.3 is available. /** * If the document's schema is an XML Schema [XML Schema Part 1] * , this constant represents the derivation by * restriction if complex types are involved, or a * restriction if simple types are involved. *
The reference type definition is derived by restriction from the * other type definition if the other type definition is the same as the * reference type definition, or if the other type definition can be * reached recursively following the {base type definition} property * from the reference type definition, and all the derivation methods involved are restriction. */ public static final int DERIVATION_RESTRICTION = 0x00000001; /** * If the document's schema is an XML Schema [XML Schema Part 1] * , this constant represents the derivation by * extension. *
The reference type definition is derived by extension from the * other type definition if the other type definition can be reached * recursively following the {base type definition} property from the * reference type definition, and at least one of the derivation methods involved is an extension. */ public static final int DERIVATION_EXTENSION = 0x00000002; /** * If the document's schema is an XML Schema [XML Schema Part 1] * , this constant represents the * union if simple types are involved. *
The reference type definition is derived by union from the other * type definition if there exists two type definitions T1 and T2 such * as the reference type definition is derived from T1 by * DERIVATION_RESTRICTION or * DERIVATION_EXTENSION, T2 is derived from the other type * definition by DERIVATION_RESTRICTION, T1 has {variety} union, and one of the {member type definitions} is T2. Note that T1 could be * the same as the reference type definition, and T2 could be the same * as the other type definition. */ public static final int DERIVATION_UNION = 0x00000004; /** * If the document's schema is an XML Schema [XML Schema Part 1] * , this constant represents the list. *
The reference type definition is derived by list from the other * type definition if there exists two type definitions T1 and T2 such * as the reference type definition is derived from T1 by * DERIVATION_RESTRICTION or * DERIVATION_EXTENSION, T2 is derived from the other type * definition by DERIVATION_RESTRICTION, T1 has {variety} list, and T2 is the {item type definition}. Note that T1 could be the same as * the reference type definition, and T2 could be the same as the other * type definition. */ public static final int DERIVATION_LIST = 0x00000008; /** * Derivation by substitution. * This constant, unlike the others, is NOT defined in the DOM level 3 TypeInfo interface. */ public static final int DERIVE_BY_SUBSTITUTION = 16; /** * Get the local name of this type * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ /*@Nullable*/ public String getName(); /** * Get the target namespace of this type * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ /*@Nullable*/ public String getTargetNamespace(); /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. * @return the namecode. Returns an invented namecode for an anonymous type. */ int getNameCode(); /** * Get the fingerprint of the name of this type * @return the fingerprint. Returns an invented fingerprint for an anonymous type. */ int getFingerprint(); /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * @return a lexical QName identifying the type */ String getDisplayName(); /** * Test whether this SchemaType is a complex type * @return true if this SchemaType is a complex type */ boolean isComplexType(); /** * Test whether this SchemaType is a simple type * @return true if this SchemaType is a simple type */ boolean isSimpleType(); /** * Test whether this SchemaType is an atomic type * @return true if this SchemaType is an atomic type */ boolean isAtomicType(); /** * Test whether this is an anonymous type * @return true if this SchemaType is an anonymous type */ boolean isAnonymousType(); /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * @return the value of the 'block' attribute for this type */ int getBlock(); /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * @return the base type, or null if this is xs:anyType (the root of the type hierarchy) * @throws IllegalStateException if this type is not valid. * @throws UnresolvedReferenceException if the reference from this type to its base * type cannot be resolved; this will generally make the schema unusable, but only * if the type is actually used. */ /*@Nullable*/ SchemaType getBaseType() throws UnresolvedReferenceException; /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ int getDerivationMethod(); /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ boolean allowsDerivation(int derivation); /** * Analyze an XPath expression to see whether the expression is capable of delivering a value of this * type. This method is called during static analysis of a query or stylesheet to give compile-time * warnings when "impossible" paths are used. * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env The static evaluation context for the query or stylesheet * @throws XPathException if the expression will never deliver a value of the correct type */ void analyzeContentExpression(Expression expression, int kind, StaticContext env) throws XPathException; /** * Get the typed value of a node that is annotated with this schema type. The results of this method * are consistent with the {@link #atomize} method, but this version returns a SequenceIterator which may * be more efficient when handling long lists. * * @param node the node whose typed value is required * @return a SequenceIterator over the atomic values making up the typed value of the specified * node. The objects returned by this iterator are of type {@link net.sf.saxon.value.AtomicValue} * @throws net.sf.saxon.trans.XPathException if the node has no typed value (typically, if it is an element with * an element-only content type) */ SequenceIterator getTypedValue(NodeInfo node) throws XPathException; /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * @param node the node whose typed value is required * @return the typed value. * @throws net.sf.saxon.trans.XPathException if the node cannot be atomized, for example if this is a complex type * with element-only content * @since 8.5 */ Value atomize(NodeInfo node) throws XPathException; /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) * @param other the other type * @return true if this is the same type as other */ boolean isSameType(SchemaType other); /** * Get a description of this type for use in error messages. This is the same as the display name * in the case of named types; for anonymous types it identifies the type by its position in a source * schema document. * @return text identifing the type, for use in a phrase such as "the type XXXX". */ String getDescription(); /** * Check that this type is validly derived from a given type, following the rules for the Schema Component * Constraint "Is Type Derivation OK (Simple)" (3.14.6) or "Is Type Derivation OK (Complex)" (3.4.6) as * appropriate. * @param base the base type; the algorithm tests whether derivation from this type is permitted * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException if the derivation is not allowed */ void checkTypeDerivationIsOK(SchemaType base, int block) throws SchemaException; /** * Get the URI of the schema document where the type was originally defined. * @return the URI of the schema document. Returns null if the information is unknown or if this * is a built-in type */ /*@Nullable*/ public String getSystemId(); /** * Ask whether this type is an ID type. This is defined to be any simple type * who typed value may contain atomic values of type xs:ID: that is, it includes types derived * from ID by restriction, list, or union. Note that for a node to be treated * as an ID in XSD 1.0, its typed value must be a *single* atomic value of type ID; the type of the * node, however, can still allow a list. But in XSD 1.1, a list of IDs is permitted * @return true if this type is an ID type */ public boolean isIdType(); /** * Ask whether this type is an IDREF or IDREFS type. This is defined to be any simple type * who typed value may contain atomic values of type xs:IDREF: that is, it includes types derived * from IDREF or IDREFS by restriction, list, or union * @return true if this type is an IDREF type */ public boolean isIdRefType(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/SchemaException.java0000644000175000017500000000405211671711573025107 0ustar mathieumathieu package net.sf.saxon.type; import javax.xml.transform.SourceLocator; import javax.xml.transform.TransformerConfigurationException; /** * An exception that identifies an error in reading, parsing, or * validating a schema. */ public class SchemaException extends TransformerConfigurationException { /** * Creates a new XMLException with no message * or nested Exception. */ public SchemaException() { super(); } public SchemaException(String message, SourceLocator locator) { super(message, locator); } /** * Creates a new XMLException with the given message. * * @param message the message for this Exception */ public SchemaException(String message) { super(message); } /** * Creates a new XMLException with the given nested * exception. * * @param exception the nested exception */ public SchemaException(Throwable exception) { super(exception); } /** * Creates a new XMLException with the given message * and nested exception. * * @param message the detail message for this exception * @param exception the nested exception */ public SchemaException(String message, Throwable exception) { super(message, exception); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/SchemaDeclaration.java0000644000175000017500000000362211671711573025400 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.pattern.NodeTest; /** * This is a marker interface that acts as a surrogate for an object representing * a global element or attribute declaration. * The real implementation of these declarations is available in the schema-aware * version of the Saxon product. */ public interface SchemaDeclaration { /** * Get the name of the schema component * @return the fingerprint of the component name */ public int getFingerprint(); /** * Get the simple or complex type associated with the element or attribute declaration * @return the simple or complex type */ public SchemaType getType(); /** * Create a NodeTest that implements the semantics of schema-element(name) or * schema-attribute(name) applied to this element or attribute declaration. */ public NodeTest makeSchemaNodeTest(); /** * Determine, in the case of an Element Declaration, whether it is nillable. */ public boolean isNillable(); /** * Determine, in the case of an Element Declaration, whether the declaration is abstract */ public boolean isAbstract(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/ISchemaCompiler.java0000644000175000017500000000155611671711573025042 0ustar mathieumathieupackage net.sf.saxon.type; /** * Marker interface: the only instance of this class is the SchemaCompiler object in Saxon-EE */ public interface ISchemaCompiler { } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/UnresolvedReferenceException.java0000644000175000017500000000243511671711573027657 0ustar mathieumathieupackage net.sf.saxon.type; /** * This exception occurs when an attempt is made to dereference a reference from one * schema component to another, if the target of the reference cannot be found. Note that * an unresolved reference is not necessarily an error: a schema containing unresolved * references may be used for validation, provided the components containing the * unresolved references are not actually used. */ public abstract class UnresolvedReferenceException extends RuntimeException { public UnresolvedReferenceException(String ref) { super(ref); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/FunctionItemType.java0000644000175000017500000000537411671711573025306 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.TypeCheckerEnvironment; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.parser.RoleLocator; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceType; /** * Higher-order functions in XPath 3.0 introduce a third kind of Item, namely a Function Item. * This type is represented here by a placeholder interfaces. The implementation of this type * is found only in Saxon-EE */ public interface FunctionItemType extends ItemType { /** * Get the argument types of the function * @return the argument types, as an array of SequenceTypes; or null if this is the generic function type * function(*) */ /*@Nullable*/ public SequenceType[] getArgumentTypes(); /** * Get the result type of the function * @return the result type, as a SequenceType */ public SequenceType getResultType(); /** * Determine the relationship of one function item type to another * @return for example {@link TypeHierarchy#SUBSUMES}, {@link TypeHierarchy#SAME_TYPE} */ public int relationship(FunctionItemType other, TypeHierarchy th); /** * Create an expression whose effect is to apply function coercion to coerce a function to this function type * @param exp the expression that delivers the supplied sequence of function items (the ones in need of coercion) * @param role information for use in diagnostics * @param visitor the expression visitor, supplies context information * @return the coerced function, a function that calls the original function after checking the parameters */ public Expression makeFunctionSequenceCoercer(Expression exp, RoleLocator role, TypeCheckerEnvironment visitor) throws XPathException; /** * Ask whether this function item type is a map type. In this case function coercion (to the map type) * will never succeed. * @return true if this FunctionItemType is a map type */ public boolean isMapType(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/AnyItemType.java0000644000175000017500000001060611671711573024242 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.trans.XPathException; import java.io.Serializable; /** * An implementation of ItemType that matches any item (node or atomic value) */ public class AnyItemType implements ItemType, Serializable { private AnyItemType(){} /*@NotNull*/ private static AnyItemType theInstance = new AnyItemType(); /** * Factory method to get the singleton instance */ /*@NotNull*/ public static AnyItemType getInstance() { return theInstance; } /** * Determine whether this item type is an atomic type * * @return true if this is ANY_ATOMIC_TYPE or a subtype thereof */ public boolean isAtomicType() { return false; } /** * Determine whether this item type is atomic (that is, whether it can ONLY match * atomic values) * * @return false: this type can match nodes or atomic values */ public boolean isPlainType() { return false; } /** * Test whether a given item conforms to this type * * @param item The item to be tested * @param context the XPath dynamic evaluation context * @return true if the item is an instance of this type; false otherwise */ public boolean matches(Item item, XPathContext context) { return true; } /** * Test whether a given item conforms to this type * @param item The item to be tested * @param allowURIPromotion * @param config * @return true if the item is an instance of this type; false otherwise */ public boolean matchesItem(Item item, boolean allowURIPromotion, Configuration config) { return true; } /*@Nullable*/ public ItemType getSuperType(TypeHierarchy th) { return null; } /** * Get the primitive item type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ /*@NotNull*/ public ItemType getPrimitiveItemType() { return this; } public int getPrimitiveType() { return Type.ITEM; } /*@NotNull*/ public AtomicType getAtomizedItemType() { return BuiltInAtomicType.ANY_ATOMIC; } /** * Ask whether values of this type are atomizable * @return true unless it is known that these items will be elements with element-only * content, in which case return false */ public boolean isAtomizable() { return true; } /** * Visit all the schema components used in this ItemType definition * @param visitor the visitor class to be called when each component is visited */ public void visitNamedSchemaComponents(SchemaComponentVisitor visitor) throws XPathException { // no action } public double getDefaultPriority() { return -2; } /*@NotNull*/ public String toString() { return "item()"; } /*@NotNull*/ public String toString(NamePool pool) { return "item()"; } /** * Returns a hash code value for the object. */ public int hashCode() { return "AnyItemType".hashCode(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): // saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/ValidationFailure.java0000644000175000017500000002404411671711573025435 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import org.xml.sax.Locator; import javax.xml.transform.SourceLocator; /** * This exception indicates a failure when validating an instance against a type * defined in a schema. * *

This class holds the same information as a ValidationException, except that it is not an exception, * and does not carry system overheads such as a stack trace. It is used because operations such as "castable", * and validation of values in a union, cause validation failures on a success path and it is costly to throw, * or even to create, exception objects on a success path.

*/ public class ValidationFailure implements SourceLocator, Locator, ConversionResult { private String message; private String systemId; private String publicId; private int lineNumber = -1; private int columnNumber = -1; private int schemaPart = -1; private String constraintName; private String clause; /*@Nullable*/ private StructuredQName errorCode; /** * Creates a new ValidationException with the given message. * @param message the message for this Exception **/ public ValidationFailure(String message) { this.message = message; setErrorCode("FORG0001"); } /** * Creates a new ValidationFailure with the given nested * exception. * @param exception the nested exception **/ public ValidationFailure(/*@NotNull*/ Exception exception) { message = exception.getMessage(); if (exception instanceof XPathException) { errorCode = ((XPathException)exception).getErrorCodeQName(); } else { setErrorCode("FORG0001"); } } /** * Set a reference to the constraint in XML Schema that is not satisfied * @param schemaPart - 1 or 2, depending whether the constraint is in XMLSchema part 1 or part 2 * @param constraintName - the short name of the constraint in XMLSchema, as a fragment identifier in the * HTML of the XML Schema Part 1 specification * @param clause - the clause number within the description of that constraint */ public void setConstraintReference(int schemaPart, String constraintName, String clause) { this.schemaPart = schemaPart; this.constraintName = constraintName; this.clause = clause; } /** * Copy the constraint reference from another exception object * @param e the other exception object from which to copy the information */ public void setConstraintReference(/*@NotNull*/ ValidationFailure e) { schemaPart = e.schemaPart; constraintName = e.constraintName; clause = e.clause; } /** * Get the constraint reference as a string for inserting into an error message. * @return the reference as a message, or null if no information is available */ /*@Nullable*/ public String getConstraintReferenceMessage() { if (schemaPart == -1) { return null; } return "See http://www.w3.org/TR/xmlschema-" + schemaPart + "/#" + constraintName + " clause " + clause; } /** * Get the "schema part" component of the constraint reference * @return 1 or 2 depending on whether the violated constraint is in XML Schema Part 1 or Part 2; * or -1 if there is no constraint reference */ public int getConstraintSchemaPart() { return schemaPart; } /** * Get the constraint name * @return the name of the violated constraint, in the form of a fragment identifier within * the published XML Schema specification; or null if the information is not available. */ public String getConstraintName() { return constraintName; } /** * Get the constraint clause number * @return the section number of the clause containing the constraint that has been violated. * Generally a decimal number in the form n.n.n; possibly a sequence of such numbers separated * by semicolons. Or null if the information is not available. */ public String getConstraintClauseNumber() { return clause; } /** * Get the constraint name and clause in the format defined in XML Schema Part C (Outcome Tabulations). * This mandates the format validation-rule-name.clause-number * @return the constraint reference, for example "cos-ct-extends.1.2"; or null if the reference * is not known. */ /*@NotNull*/ public String getConstraintReference() { return constraintName + '.' + clause; } public String getMessage() { return message; } /** * Returns the String representation of this Exception * @return the String representation of this Exception **/ public String toString() { StringBuffer sb = new StringBuffer("ValidationException: "); String message = getMessage(); if (message != null) { sb.append(message); } return sb.toString(); } public String getPublicId() { SourceLocator loc = getLocator(); if (publicId == null && loc != null && loc != this) { return loc.getPublicId(); } else{ return publicId; } } public String getSystemId() { SourceLocator loc = getLocator(); if (systemId == null && loc != null && loc != this) { return loc.getSystemId(); } else{ return systemId; } } public int getLineNumber() { SourceLocator loc = getLocator(); if (lineNumber == -1 && loc != null && loc != this) { return loc.getLineNumber(); } else{ return lineNumber; } } public int getColumnNumber() { SourceLocator loc = getLocator(); if (columnNumber == -1 && loc != null && loc != this) { return loc.getColumnNumber(); } else{ return columnNumber; } } public void setPublicId(String id) { publicId = id; } public void setSystemId(String id) { systemId = id; } public void setLineNumber(int line) { lineNumber = line; } public void setColumnNumber(int column) { columnNumber = column; } public void setLocator(/*@Nullable*/ SourceLocator locator) { if (locator != null) { setPublicId(locator.getPublicId()); setSystemId(locator.getSystemId()); setLineNumber(locator.getLineNumber()); setColumnNumber(locator.getColumnNumber()); } } public void setSourceLocator(/*@Nullable*/ SourceLocator locator) { if (locator != null) { setPublicId(locator.getPublicId()); setSystemId(locator.getSystemId()); setLineNumber(locator.getLineNumber()); setColumnNumber(locator.getColumnNumber()); } } /*@NotNull*/ public SourceLocator getLocator() { return this; } public void setErrorCode(String errorCode) { this.errorCode = new StructuredQName("err", NamespaceConstant.ERR, errorCode); } public void setErrorCodeQName(StructuredQName errorCode) { this.errorCode = errorCode; } /*@Nullable*/ public String getErrorCode() { return errorCode == null ? null : errorCode.getLocalPart(); } /*@Nullable*/ public StructuredQName getErrorCodeQName() { return errorCode; } /*@NotNull*/ public ValidationException makeException() { ValidationException ve = new ValidationException(message, getLocator()); ve.setConstraintReference(schemaPart, constraintName, clause); if (errorCode == null) { ve.setErrorCode("FORG0001"); } else { ve.setErrorCodeQName(errorCode); } return ve; } /*@Nullable*/ public ValidationException makeException(/*@Nullable*/ String contextMessage) { ValidationException ve = new ValidationException((contextMessage == null ? message : contextMessage + message)); ve.setConstraintReference(schemaPart, constraintName, clause); if (errorCode == null) { ve.setErrorCode("FORG0001"); } else { ve.setErrorCodeQName(errorCode); } return ve; } /** * Calling this method on a ConversionResult returns the AtomicValue that results * from the conversion if the conversion was successful, and throws a ValidationException * explaining the conversion error otherwise. *

*

Use this method if you are calling a conversion method that returns a ConversionResult, * and if you want to throw an exception if the conversion fails.

* * @return the atomic value that results from the conversion if the conversion was successful * @throws net.sf.saxon.type.ValidationException * if the conversion was not successful */ /*@NotNull*/ public AtomicValue asAtomic() throws ValidationException { throw makeException(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/AnySimpleType.java0000644000175000017500000003354611727504124024577 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StandardNames; import net.sf.saxon.tree.iter.SingletonIterator; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import net.sf.saxon.value.Whitespace; /** * This class has a singleton instance which represents the XML Schema built-in type xs:anySimpleType */ public final class AnySimpleType implements SimpleType { /*@NotNull*/ private static AnySimpleType theInstance = new AnySimpleType(); /** * Private constructor */ private AnySimpleType() { } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ /*@NotNull*/ public String getName() { return "anySimpleType"; } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return NamespaceConstant.SCHEMA; } /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects */ public boolean isExternalType() { return false; } /** * Determine whether this is a built-in type or a user-defined type */ public boolean isBuiltInType() { return true; } /** * Ask whether this type is an ID type. This is defined to be any simple type * who typed value may contain atomic values of type xs:ID: that is, it includes types derived * from ID by restriction, list, or union. Note that for a node to be treated * as an ID, its typed value must be a *single* atomic value of type ID; the type of the * node, however, can still allow a list. */ public boolean isIdType() { return false; } /** * Ask whether this type is an IDREF or IDREFS type. This is defined to be any simple type * who typed value may contain atomic values of type xs:IDREF: that is, it includes types derived * from IDREF or IDREFS by restriction, list, or union */ public boolean isIdRefType() { return false; } /** * Get the redefinition level. This is zero for a component that has not been redefined; * for a redefinition of a level-0 component, it is 1; for a redefinition of a level-N * component, it is N+1. This concept is used to support the notion of "pervasive" redefinition: * if a component is redefined at several levels, the top level wins, but it is an error to have * two versions of the component at the same redefinition level. * @return the redefinition level */ public int getRedefinitionLevel() { return 0; } /** * Get the URI of the schema document containing the definition of this type * @return null for a built-in type */ /*@Nullable*/ public String getSystemId() { return null; } /** * Get the singular instance of this class * @return the singular object representing xs:anyType */ /*@NotNull*/ public static AnySimpleType getInstance() { return theInstance; } /** * Get the validation status - always valid */ public int getValidationStatus() { return VALIDATED; } /** * Get the base type * @return AnyType */ public SchemaType getBaseType() { return AnyType.getInstance(); } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public boolean isComplexType() { return false; } /** * Test whether this SchemaType is a simple type * @return true if this SchemaType is a simple type */ public boolean isSimpleType() { return true; } /** * Get the fingerprint of the name of this type * @return the fingerprint. */ public int getFingerprint() { return StandardNames.XS_ANY_SIMPLE_TYPE; } /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. */ public int getNameCode() { return StandardNames.XS_ANY_SIMPLE_TYPE; } /** * Get a description of this type for use in diagnostics * @return the string "xs:anyType" */ /*@NotNull*/ public String getDescription() { return "xs:anySimpleType"; } /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * * @return a lexical QName identifying the type */ /*@NotNull*/ public String getDisplayName() { return "xs:anySimpleType"; } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(SchemaType other) { return (other instanceof AnySimpleType); } /** * Get the typed value of a node that is annotated with this schema type. This shouldn't happen: nodes * are never annotated as xs:anySimpleType; but if it does happen, we treat it as if it were * untypedAtomic. * @param node the node whose typed value is required * @return an iterator returning a single untyped atomic value, equivalent to the string value of the node. */ /*@NotNull*/ public SequenceIterator getTypedValue(/*@NotNull*/ NodeInfo node) { return SingletonIterator.makeIterator(new UntypedAtomicValue(node.getStringValueCS())); } /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ /*@NotNull*/ public Value atomize(/*@NotNull*/ NodeInfo node) { return new UntypedAtomicValue(node.getStringValueCS()); } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException * if the derivation is not allowed */ public void checkTypeDerivationIsOK(SchemaType type, int block) throws SchemaException { if (type == this) { return; } throw new SchemaException("Cannot derive xs:anySimpleType from another type"); } /** * Test whether this Simple Type is an atomic type * @return false, this is not (necessarily) an atomic type */ public boolean isAtomicType() { return false; } public boolean isAnonymousType() { return false; } /** * Determine whether this is a list type * @return false (it isn't a list type) */ public boolean isListType() { return false; } /** * Determin whether this is a union type * @return false (it isn't a union type) */ public boolean isUnionType() { return false; } /** * Get the built-in ancestor of this type in the type hierarchy * @return this type itself */ /*@NotNull*/ public SchemaType getBuiltInBaseType() { return this; } /** * Get the typed value corresponding to a given string value, assuming it is * valid against this type * * @param value the string value * @param resolver a namespace resolver used to resolve any namespace prefixes appearing * in the content of values. Can supply null, in which case any namespace-sensitive content * will be rejected. * @param rules * @return an iterator over the atomic sequence comprising the typed value. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue} */ /*@NotNull*/ public SequenceIterator getTypedValue(CharSequence value, NamespaceResolver resolver, ConversionRules rules) { return SingletonIterator.makeIterator(new UntypedAtomicValue(value)); } /** * Check whether a given input string is valid according to this SimpleType * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param rules * @return null if validation succeeds (which it always does for this implementation) * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ /*@Nullable*/ public ValidationFailure validateContent(/*@NotNull*/ CharSequence value, NamespaceResolver nsResolver, /*@NotNull*/ ConversionRules rules) { return null; } /** * Test whether this type represents namespace-sensitive content * @return false */ public boolean isNamespaceSensitive() { return false; } /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public int getBlock() { return 0; } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ public int getDerivationMethod() { return SchemaType.DERIVATION_RESTRICTION; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public boolean allowsDerivation(int derivation) { return true; } /** * Determine how values of this simple type are whitespace-normalized. * * @return one of {@link net.sf.saxon.value.Whitespace#PRESERVE}, {@link net.sf.saxon.value.Whitespace#COLLAPSE}, * {@link net.sf.saxon.value.Whitespace#REPLACE}. */ public int getWhitespaceAction() { return Whitespace.PRESERVE; } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link net.sf.saxon.type.Type#ELEMENT}, * {@link net.sf.saxon.type.Type#ATTRIBUTE}, or {@link net.sf.saxon.type.Type#DOCUMENT} * @param env */ public void analyzeContentExpression(Expression expression, int kind, StaticContext env) { //return; } /** * Apply any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess * @param input the value to be preprocessed * @return the value after preprocessing */ public CharSequence preprocess(CharSequence input) { return input; } /** * Reverse any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess. This is called when converting a value of this type to * a string * @param input the value to be postprocessed: this is the "ordinary" result of converting * the value to a string * @return the value after postprocessing */ public CharSequence postprocess(CharSequence input) throws ValidationException { return input; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/SchemaComponentVisitor.java0000644000175000017500000000176411671711573026502 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.trans.XPathException; /** * Interface for a general purpose visitor object used to process schema components */ public interface SchemaComponentVisitor { public void visitSchemaComponent(SchemaComponent component) throws XPathException; } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/ListType.java0000644000175000017500000000226411671711573023610 0ustar mathieumathieupackage net.sf.saxon.type; /** * Interface representing a simple type of variety List */ public interface ListType extends SimpleType { /** * Returns the simpleType of the items in this ListType. This method assumes that the * item type has been fully resolved * @return the simpleType of the items in this ListType. * @throws IllegalStateException if the item type has not been fully resolved */ /*@NotNull*/ SimpleType getItemType(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/ExternalObjectType.java0000644000175000017500000006377111671711573025620 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.Literal; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.instruct.ValueOf; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.ObjectValue; import net.sf.saxon.value.Value; import net.sf.saxon.value.Whitespace; import java.io.Serializable; import java.util.HashSet; import java.util.Set; /** * This class represents the type of an external Java object returned by * an extension function, or supplied as an external variable/parameter. */ public class ExternalObjectType implements AtomicType, Serializable { private Class javaClass; private Configuration config; int fingerprint; /** * Create an anonymous external object type. When constructed this way, the type will not * have a nameCode or fingerprint in the name pool, so methods asking for the name of the type * will return no value. * @param javaClass the Java class to which this type corresponds */ public ExternalObjectType(Class javaClass) { this.javaClass = javaClass; } /** * Create an external object type. When constructed this way, the type will * have a fingerprint in the name pool based on the Java class name * @param javaClass the Java class to which this type corresponds * @param config the Saxon configuration */ public ExternalObjectType(/*@NotNull*/ Class javaClass, /*@NotNull*/ Configuration config) { this.javaClass = javaClass; this.config = config; final String localName = javaClass.getName().replace('$', '_'); fingerprint = config.getNamePool().allocate("", NamespaceConstant.JAVA_TYPE, localName); } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ /*@Nullable*/ public String getName() { if (config == null) { return null; } else { return config.getNamePool().getLocalName(fingerprint); } } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ /*@Nullable*/ public String getTargetNamespace() { if (config == null) { return null; } else { return config.getNamePool().getURI(fingerprint); } } /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects */ public boolean isExternalType() { return true; } /** * Determine whether this is a built-in type or a user-defined type * @return false - external types are not built in */ public boolean isBuiltInType() { return false; } /** * Get the name of this type as a StructuredQName, unless the type is anonymous, in which case * return null * @return the name of the atomic type, or null if the type is anonymous. */ /*@Nullable*/ public StructuredQName getTypeName() { return null; } /** * Get the redefinition level. This is zero for a component that has not been redefined; * for a redefinition of a level-0 component, it is 1; for a redefinition of a level-N * component, it is N+1. This concept is used to support the notion of "pervasive" redefinition: * if a component is redefined at several levels, the top level wins, but it is an error to have * two versions of the component at the same redefinition level. * @return the redefinition level */ public int getRedefinitionLevel() { return 0; } /** * Determine whether the type is abstract, that is, whether it cannot have instances that are not also * instances of some concrete subtype * @return false - external types are not abstract */ public boolean isAbstract() { return false; } /** * Determine whether the atomic type is a primitive type. The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration; * xs:untypedAtomic; and all supertypes of these (xs:anyAtomicType, xs:numeric, ...) * * @return true if the type is considered primitive under the above rules */ public boolean isPrimitiveType() { return false; } /** * Determine whether the atomic type is ordered, that is, whether less-than and greater-than comparisons * are permitted * * @return true if ordering operations are permitted */ public boolean isOrdered() { return false; } /** * Ask whether this is a plain type (a type whose instances are always atomic values) * @return true */ public boolean isPlainType() { return false; } /** * Get the URI of the schema document where the type was originally defined. * * @return the URI of the schema document. Returns null if the information is unknown or if this * is a built-in type */ /*@Nullable*/ public String getSystemId() { return null; } /** * Get the validation status - always valid */ public final int getValidationStatus() { return VALIDATED; } /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public final int getBlock() { return 0; } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ public final int getDerivationMethod() { return SchemaType.DERIVATION_RESTRICTION; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public final boolean allowsDerivation(int derivation) { return true; } /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. */ public int getNameCode() { return fingerprint; } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public final boolean isComplexType() { return false; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ /*@NotNull*/ public final SchemaType getBaseType() { return BuiltInAtomicType.ANY_ATOMIC; } /** * Get the primitive item type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ /*@NotNull*/ public ItemType getPrimitiveItemType() { return this; } /** * Get the primitive type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ public int getPrimitiveType() { return StandardNames.XS_ANY_ATOMIC_TYPE; } /** * Produce a representation of this type name for use in error messages. * Where this is a QName, it will use conventional prefixes */ /*@NotNull*/ public String toString(NamePool pool) { return getDisplayName(); } /** * Get the item type of the atomic values that will be produced when an item * of this type is atomized */ /*@NotNull*/ public AtomicType getAtomizedItemType() { return this; } /** * Ask whether values of this type are atomizable * @return true unless it is known that these items will be elements with element-only * content, in which case return false */ public boolean isAtomizable() { return true; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ /*@NotNull*/ public SchemaType getKnownBaseType() { return getBaseType(); } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(/*@NotNull*/ SchemaType other) { return (other.getFingerprint() == getFingerprint()); } /** * Get the relationship of this external object type to another external object type * @param other the other external object type * @return the relationship of this external object type to another external object type, * as one of the constants in class {@link TypeHierarchy}, for example {@link TypeHierarchy#SUBSUMES} */ public int getRelationship(/*@NotNull*/ ExternalObjectType other) { Class j2 = other.javaClass; if (javaClass.equals(j2)) { return TypeHierarchy.SAME_TYPE; } else if (javaClass.isAssignableFrom(j2)) { return TypeHierarchy.SUBSUMES; } else if (j2.isAssignableFrom(javaClass)) { return TypeHierarchy.SUBSUMED_BY; } else if (javaClass.isInterface() || j2.isInterface()) { return TypeHierarchy.OVERLAPS; // there may be an overlap, we play safe } else { return TypeHierarchy.DISJOINT; } } /*@NotNull*/ public String getDescription() { return getDisplayName(); } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException if the derivation is not allowed */ public void checkTypeDerivationIsOK(SchemaType type, int block) throws SchemaException { //return; } /** * Returns true if this SchemaType is a SimpleType * * @return true (always) */ public final boolean isSimpleType() { return true; } /** * Test whether this Simple Type is an atomic type * @return true, this is considered to be an atomic type */ public boolean isAtomicType() { return true; } /** * Ask whether this type is an ID type. This is defined to be any simple type * who typed value may contain atomic values of type xs:ID: that is, it includes types derived * from ID by restriction, list, or union. Note that for a node to be treated * as an ID, its typed value must be a *single* atomic value of type ID; the type of the * node, however, can still allow a list. */ public boolean isIdType() { return false; } /** * Ask whether this type is an IDREF or IDREFS type. This is defined to be any simple type * who typed value may contain atomic values of type xs:IDREF: that is, it includes types derived * from IDREF or IDREFS by restriction, list, or union */ public boolean isIdRefType() { return false; } /** * Returns true if this type is derived by list, or if it is derived by restriction * from a list type, or if it is a union that contains a list as one of its members * * @return true if this is a list type */ public boolean isListType() { return false; } /** * Return true if this type is a union type (that is, if its variety is union) * * @return true for a union type */ public boolean isUnionType() { return false; } /** * Determine the whitespace normalization required for values of this type * * @return one of PRESERVE, REPLACE, COLLAPSE */ public int getWhitespaceAction() { return Whitespace.PRESERVE; } /** * Apply the whitespace normalization rules for this simple type * * @param value the string before whitespace normalization * @return the string after whitespace normalization */ public CharSequence applyWhitespaceNormalization(CharSequence value) throws ValidationException { return value; } /** * Returns the built-in base type this type is derived from. * * @return the first built-in type found when searching up the type hierarchy */ /*@NotNull*/ public SchemaType getBuiltInBaseType() { return this; } /** * Test whether this simple type is namespace-sensitive, that is, whether * it is derived from xs:QName or xs:NOTATION * * @return true if this type is derived from xs:QName or xs:NOTATION */ public boolean isNamespaceSensitive() { return false; } /** * Test whether this is an anonymous type * @return true if this SchemaType is an anonymous type */ public boolean isAnonymousType() { return false; } /** * Get the typed value of a node that is annotated with this schema type * * @param node the node whose typed value is required * @return an iterator over the items making up the typed value of this node. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue} */ /*@NotNull*/ public final SequenceIterator getTypedValue(NodeInfo node) { throw new IllegalStateException("The type annotation of a node cannot be an external object type"); } /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ /*@NotNull*/ public Value atomize(NodeInfo node) throws XPathException { throw new IllegalStateException("The type annotation of a node cannot be an external object type"); } /** * Get the typed value corresponding to a given string value, assuming it is * valid against this type * * @param value the string value * @param resolver a namespace resolver used to resolve any namespace prefixes appearing * in the content of values. Can supply null, in which case any namespace-sensitive content * will be rejected. * @param rules * @return an iterator over the atomic sequence comprising the typed value. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue} */ /*@NotNull*/ public SequenceIterator getTypedValue(CharSequence value, NamespaceResolver resolver, ConversionRules rules) throws ValidationException { throw new ValidationException("Cannot validate a string against an external object type"); } /** * Validate that a primitive atomic value is a valid instance of a type derived from the * same primitive type. * * @param primValue the value in the value space of the primitive type. * @param lexicalValue the value in the lexical space. If null, the string value of primValue * is used. This value is checked against the pattern facet (if any) * @param rules * @return null if the value is valid; otherwise, a ValidationFailure object indicating * the nature of the error. * @throws UnsupportedOperationException in the case of an external object type */ /*@NotNull*/ public ValidationFailure validate(AtomicValue primValue, CharSequence lexicalValue, ConversionRules rules) { throw new UnsupportedOperationException("validate"); } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env the static evaluation context * @throws net.sf.saxon.trans.XPathException * if the expression will never deliver a value of the correct type */ public void analyzeContentExpression(/*@NotNull*/ Expression expression, int kind, StaticContext env) throws XPathException { analyzeContentExpression(this, expression, env, kind); } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * @param simpleType the simple type against which the expression is to be checked * @param expression the expression that delivers the content * @param env the static evaluation context * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @throws net.sf.saxon.trans.XPathException * if the expression will never deliver a value of the correct type */ public static void analyzeContentExpression(SimpleType simpleType, /*@NotNull*/ Expression expression, StaticContext env, int kind) throws XPathException { if (kind == Type.ELEMENT) { expression.checkPermittedContents(simpleType, env, true); } else if (kind == Type.ATTRIBUTE) { // for attributes, do a check only for text nodes and atomic values: anything else gets atomized if (expression instanceof ValueOf || expression instanceof Literal) { expression.checkPermittedContents(simpleType, env, true); } } } /** * Get the Java class to which this external object type corresponds * @return the corresponding Java class */ public Class getJavaClass() { return javaClass; } /** * Test whether a given item conforms to this type * * @param item The item to be tested * @param context the XPath dynamic evaluation context * @return true if the item is an instance of this type; false otherwise */ public boolean matches(/*@NotNull*/ Item item, /*@NotNull*/ XPathContext context) { return matchesItem(item, false, context.getConfiguration()); } /** * Test whether a given item conforms to this type * @param item The item to be tested * @param allowURIPromotion * @param config * @return true if the item is an instance of this type; false otherwise */ public boolean matchesItem(/*@NotNull*/ Item item, boolean allowURIPromotion, Configuration config) { if (item instanceof ObjectValue) { Object obj = ((ObjectValue)item).getObject(); return javaClass.isAssignableFrom(obj.getClass()); } return false; } /** * Check whether a given input string is valid according to this SimpleType * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param rules * @return null if validation succeeds; return a ValidationException describing the validation failure * if validation fails, unless throwException is true, in which case the exception is thrown rather than * being returned. * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ /*@NotNull*/ public ValidationFailure validateContent(/*@NotNull*/ CharSequence value, NamespaceResolver nsResolver, /*@NotNull*/ ConversionRules rules) { throw new UnsupportedOperationException("Cannot use an external object type for validation"); } /*@NotNull*/ public ItemType getSuperType(TypeHierarchy th) { if (javaClass == Object.class) { return BuiltInAtomicType.ANY_ATOMIC; } Class javaSuper = javaClass.getSuperclass(); if (javaSuper == null) { // this happens for an interface return BuiltInAtomicType.ANY_ATOMIC; } return new ExternalObjectType(javaSuper, config); } public int getFingerprint() { return fingerprint; } /*@NotNull*/ public String toString() { String name = javaClass.getName(); name = name.replace('$', '-'); return "javatype:" + name; } /*@NotNull*/ public String getDisplayName() { return toString(); } /** * Returns a hash code value for the object. */ public int hashCode() { return javaClass.hashCode(); } /** * Test whether two ExternalObjectType objects represent the same type * @param obj the other ExternalObjectType * @return true if the two objects represent the same type */ public boolean equals(/*@NotNull*/ Object obj) { return obj instanceof ExternalObjectType && javaClass == ((ExternalObjectType)obj).javaClass; } /** * Apply any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess * @param input the value to be preprocessed * @return the value after preprocessing */ public CharSequence preprocess(CharSequence input) { return input; } /** * Reverse any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess. This is called when converting a value of this type to * a string * @param input the value to be postprocessed: this is the "ordinary" result of converting * the value to a string * @return the value after postprocessing */ public CharSequence postprocess(CharSequence input) throws ValidationException { return input; } /** * Visit all the schema components used in this ItemType definition * @param visitor the visitor class to be called when each component is visited */ public void visitNamedSchemaComponents(SchemaComponentVisitor visitor) throws XPathException { // no action } /** * Get the set of atomic types that are subsumed by this type * * @return for an atomic type, the type itself; for a union type, the set of atomic types * in its transitive membership */ /*@NotNull*/ public Set getPlainMemberTypes() { Set s = new HashSet(1); s.add(this); return s; } public double getDefaultPriority() { return 0.5; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/StringConverter.java0000644000175000017500000011611612113414400025150 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.om.NameChecker; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.QNameException; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.Err; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.util.FastStringBuffer; import net.sf.saxon.value.*; import net.sf.saxon.value.StringValue; import java.util.regex.Pattern; /** * A {@link Converter} that accepts a string as input. This subclass of Converter is provided * to avoid having to wrap the string into a StringValue prior to conversion. Every Converter whose * source type is xs:string must be an instance of this subclass. * *

The input to a StringConverter can also be an xs:untypedAtomic value, since the conversion semantics * are always the same as from a string.

* *

A StringConverter also provides a method to validate that a string is valid against the target type, * without actually performing the conversion.

*/ public abstract class StringConverter extends Converter { // Constants are defined only for converters that are independent of the conversion rules /*@NotNull*/ public final static StringToString STRING_TO_STRING = new StringToString(); /*@NotNull*/ public final static StringToLanguage STRING_TO_LANGUAGE = new StringToLanguage(); /*@NotNull*/ public final static StringToNormalizedString STRING_TO_NORMALIZED_STRING = new StringToNormalizedString(); /*@NotNull*/ public final static StringToToken STRING_TO_TOKEN = new StringToToken(); /*@NotNull*/ public final static StringToDecimal STRING_TO_DECIMAL = new StringToDecimal(); /*@NotNull*/ public final static StringToInteger STRING_TO_INTEGER = new StringToInteger(); /*@NotNull*/ public final static StringToDuration STRING_TO_DURATION = new StringToDuration(); /*@NotNull*/ public final static StringToDayTimeDuration STRING_TO_DAY_TIME_DURATION = new StringToDayTimeDuration(); /*@NotNull*/ public final static StringToYearMonthDuration STRING_TO_YEAR_MONTH_DURATION = new StringToYearMonthDuration(); /*@NotNull*/ public final static StringToTime STRING_TO_TIME = new StringToTime(); /*@NotNull*/ public final static StringToBoolean STRING_TO_BOOLEAN = new StringToBoolean(); /*@NotNull*/ public final static StringToHexBinary STRING_TO_HEX_BINARY = new StringToHexBinary(); /*@NotNull*/ public final static StringToBase64BinaryConverter STRING_TO_BASE64_BINARY = new StringToBase64BinaryConverter(); /*@NotNull*/ public final static StringToUntypedAtomic STRING_TO_UNTYPED_ATOMIC = new StringToUntypedAtomic(); /** * Create a StringConverter */ public StringConverter(){} /** * Create a StringConverter * @param rules the conversion rules to be applied */ public StringConverter(ConversionRules rules) { super(rules); } /** * Convert a string to the target type of this converter. * @param input the string to be converted * @return either an {@link net.sf.saxon.value.AtomicValue} of the appropriate type for this converter (if conversion * succeeded), or a {@link ValidationFailure} if conversion failed. */ /*@NotNull*/ public abstract ConversionResult convertString(/*@NotNull*/ CharSequence input); /** * Validate a string for conformance to the target type, without actually performing * the conversion * @param input the string to be validated * @return null if validation is successful, or a ValidationFailure indicating the reasons for failure * if unsuccessful */ /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ CharSequence input) { ConversionResult result = convertString(input); return (result instanceof ValidationFailure ? (ValidationFailure)result : null); } /*@NotNull*/ @Override public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return convertString(input.getStringValueCS()); } /** * Static factory method to get a StringConverter for a specific target type * @param targetType the target type of the conversion * @param rules the conversion rules in use * @return a StringConverter that can be used to convert strings to the target type, or to * validate strings against the target type */ /*@NotNull*/ public static StringConverter getStringConverter(/*@NotNull*/ final AtomicType targetType, /*@NotNull*/ final ConversionRules rules) { int tt = targetType.getPrimitiveType(); if (targetType.isBuiltInType()) { if (tt == StandardNames.XS_STRING) { switch (targetType.getFingerprint()) { case StandardNames.XS_STRING: return STRING_TO_STRING; case StandardNames.XS_NORMALIZED_STRING: return STRING_TO_NORMALIZED_STRING; case StandardNames.XS_TOKEN: return STRING_TO_TOKEN; case StandardNames.XS_LANGUAGE: return STRING_TO_LANGUAGE; case StandardNames.XS_NAME: return new StringToName(rules); case StandardNames.XS_NCNAME: case StandardNames.XS_ID: case StandardNames.XS_IDREF: case StandardNames.XS_ENTITY: return new StringToNCName(rules, targetType); case StandardNames.XS_NMTOKEN: return new StringToNMTOKEN(rules); default: throw new AssertionError("Unknown built-in subtype of xs:string"); } } else if (tt == StandardNames.XS_UNTYPED_ATOMIC) { return STRING_TO_UNTYPED_ATOMIC; } else if (targetType.isPrimitiveType()) { // converter to built-in types unrelated to xs:string Converter converter = getConverter(BuiltInAtomicType.STRING, targetType, rules); assert converter != null; return (StringConverter)converter; } else if (tt == StandardNames.XS_INTEGER) { return new StringToIntegerSubtype((BuiltInAtomicType)targetType); } else { switch (targetType.getFingerprint()) { case StandardNames.XS_DAY_TIME_DURATION: return STRING_TO_DAY_TIME_DURATION; case StandardNames.XS_YEAR_MONTH_DURATION: return STRING_TO_YEAR_MONTH_DURATION; case StandardNames.XS_DATE_TIME_STAMP: StringConverter first = new StringToDateTime(rules); DownCastingConverter second = new DownCastingConverter(targetType, rules); return new StringToNonStringDerivedType(first, second); default: throw new AssertionError("Unknown built in type " + targetType.toString()); } } } else { if (tt == StandardNames.XS_STRING) { if (targetType.getBuiltInBaseType() == BuiltInAtomicType.STRING) { // converter to user-defined subtypes of xs:string return new StringToStringSubtype(rules, targetType); } else { // converter to user-defined subtypes of built-in subtypes of xs:string return new StringToDerivedStringSubtype(rules, targetType); } } if (targetType instanceof ExternalObjectType) { return new StringToExternalObjectType(); } else if (Configuration.getPlatform().isDotNet()) { String className = "net.sf.saxon.dotnet.DotNetExternalObjectType"; Class theClass; ClassLoader classLoader = StringConverter.class.getClassLoader(); try { try{ theClass = classLoader.loadClass(className); }catch(Exception ex) { theClass = Class.forName(className); } if(theClass.isInstance(targetType)) { return new StringToExternalObjectType(); } } catch(ClassNotFoundException ex) {} } // converter to user-defined types derived from types other than xs:string StringConverter first = getStringConverter((AtomicType)targetType.getPrimitiveItemType(), rules); DownCastingConverter second = new DownCastingConverter(targetType, rules); return new StringToNonStringDerivedType(first, second); } // } else { // // converter to built-in types unrelated to xs:string // Converter converter = getConverter(BuiltInAtomicType.STRING, targetType, rules); // return (StringConverter)converter; // } } /** * Converter from string to a derived type (derived from a type other than xs:string), * where the derived type needs to retain the original * string for validating against lexical facets such as pattern. */ public static class StringToNonStringDerivedType extends StringConverter { private StringConverter phaseOne; private DownCastingConverter phaseTwo; public StringToNonStringDerivedType(StringConverter phaseOne, DownCastingConverter phaseTwo) { this.phaseOne = phaseOne; this.phaseTwo = phaseTwo; } @Override public void setNamespaceResolver(NamespaceResolver resolver) { phaseOne.setNamespaceResolver(resolver); phaseTwo.setNamespaceResolver(resolver); } /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { CharSequence in = input.getStringValueCS(); try { in = phaseTwo.getTargetType().preprocess(in); } catch (ValidationException err) { return new ValidationFailure(err); } ConversionResult temp = phaseOne.convertString(in); if (temp instanceof ValidationFailure) { return temp; } return phaseTwo.convert((AtomicValue) temp, in); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { try { input = phaseTwo.getTargetType().preprocess(input); } catch (ValidationException err) { return new ValidationFailure(err); } ConversionResult temp = phaseOne.convertString(input); if (temp instanceof ValidationFailure) { return temp; } return phaseTwo.convert((AtomicValue) temp, input); } } /** * Converts from xs:string or xs:untypedAtomic to xs:String */ public static class StringToString extends StringConverter { /*@NotNull*/@Override public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new StringValue(input.getStringValueCS()); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return new StringValue(input); } /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ CharSequence input) { return null; } public boolean isAlwaysSuccessful() { return true; } } /** * Converts from xs:string or xs:untypedAtomic to xs:untypedAtomic */ public static class StringToUntypedAtomic extends StringConverter { /*@NotNull*/@Override public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new UntypedAtomicValue(input.getStringValueCS()); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return new UntypedAtomicValue(input); } /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ CharSequence input) { return null; } public boolean isAlwaysSuccessful() { return true; } } /** * Converts from xs:string to xs:normalizedString */ public static class StringToNormalizedString extends StringConverter { /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return new StringValue(Whitespace.normalizeWhitespace(input), BuiltInAtomicType.NORMALIZED_STRING); } /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ CharSequence input) { return null; } public boolean isAlwaysSuccessful() { return true; } } /** * Converts from xs:string to xs:token */ public static class StringToToken extends StringConverter { /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return new StringValue(Whitespace.collapseWhitespace(input), BuiltInAtomicType.TOKEN); } /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ CharSequence input) { return null; } public boolean isAlwaysSuccessful() { return true; } } /** * Converts from xs:string to xs:language */ public static class StringToLanguage extends StringConverter { private final static Pattern regex = Pattern.compile("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*"); // See erratum E2-25 to XML Schema Part 2. /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { CharSequence trimmed = Whitespace.trimWhitespace(input); if (!regex.matcher(trimmed).matches()) { return new ValidationFailure("The value '" + input + "' is not a valid xs:language"); } return new StringValue(trimmed, BuiltInAtomicType.LANGUAGE); } /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ CharSequence input) { if (regex.matcher(Whitespace.trimWhitespace(input)).matches()) { return null; } else { return new ValidationFailure("The value '" + input + "' is not a valid xs:language"); } } } /** * Converts from xs:string to xs:NCName, xs:ID, xs:IDREF, or xs:ENTITY */ public static class StringToNCName extends StringConverter { NameChecker checker; AtomicType targetType; public StringToNCName(/*@NotNull*/ ConversionRules rules, AtomicType targetType) { super(rules); checker = rules.getNameChecker(); this.targetType = targetType; } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { CharSequence trimmed = Whitespace.trimWhitespace(input); if (checker.isValidNCName(trimmed)) { return new StringValue(trimmed, targetType); } else { return new ValidationFailure("The value '" + input + "' is not a valid xs:NCName"); } } /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ CharSequence input) { if (checker.isValidNCName(Whitespace.trimWhitespace(input))) { return null; } else { return new ValidationFailure("The value '" + input + "' is not a valid xs:NCName"); } } } /** * Converts from xs:string to xs:NMTOKEN */ public static class StringToNMTOKEN extends StringConverter { NameChecker checker; public StringToNMTOKEN(/*@NotNull*/ ConversionRules rules) { super(rules); checker = rules.getNameChecker(); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { CharSequence trimmed = Whitespace.trimWhitespace(input); if (checker.isValidNmtoken(trimmed)) { return new StringValue(trimmed, BuiltInAtomicType.NMTOKEN); } else { return new ValidationFailure("The value '" + input + "' is not a valid xs:NMTOKEN"); } } /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ CharSequence input) { if (checker.isValidNmtoken(Whitespace.trimWhitespace(input))) { return null; } else { return new ValidationFailure("The value '" + input + "' is not a valid xs:NMTOKEN"); } } } /** * Converts from xs:string to xs:Name */ public static class StringToName extends StringToNCName { public StringToName(/*@NotNull*/ ConversionRules rules) { super(rules, BuiltInAtomicType.NAME); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { ValidationFailure vf = validate(input); if (vf == null) { return new StringValue(Whitespace.trimWhitespace(input), BuiltInAtomicType.NAME); } else { return vf; } } /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ CharSequence input) { // if it's valid as an NCName then it's OK CharSequence trimmed = Whitespace.trimWhitespace(input); if (checker.isValidNCName(trimmed)) { return null; } // if not, replace any colons by underscores and then test if it's a valid NCName FastStringBuffer buff = new FastStringBuffer(trimmed.length()); buff.append(trimmed); for (int i = 0; i < buff.length(); i++) { if (buff.charAt(i) == ':') { buff.setCharAt(i, '_'); } } if (checker.isValidNCName(buff)) { return null; } else { return new ValidationFailure("The value '" + trimmed + "' is not a valid xs:Name"); } } } /** * Converts from xs;string to a user-defined type derived directly from xs:string */ public static class StringToStringSubtype extends StringConverter { AtomicType targetType; int whitespaceAction; public StringToStringSubtype(ConversionRules rules, /*@NotNull*/ AtomicType targetType) { super(rules); this.targetType = targetType; this.whitespaceAction = targetType.getWhitespaceAction(); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { CharSequence cs = Whitespace.applyWhitespaceNormalization(whitespaceAction, input); try { cs = targetType.preprocess(cs); } catch (ValidationException err) { return new ValidationFailure(err); } StringValue sv = new StringValue(cs); ValidationFailure f = targetType.validate(sv, cs, getConversionRules()); if (f == null) { sv.setTypeLabel(targetType); return sv; } else { return f; } } public ValidationFailure validate(/*@NotNull*/ CharSequence input) { CharSequence cs = Whitespace.applyWhitespaceNormalization(whitespaceAction, input); return targetType.validate(new StringValue(cs), cs, getConversionRules()); } } /** * Converts from xs;string to a user-defined type derived from a built-in subtype of xs:string */ public static class StringToDerivedStringSubtype extends StringConverter { AtomicType targetType; StringConverter builtInValidator; int whitespaceAction; public StringToDerivedStringSubtype(/*@NotNull*/ ConversionRules rules, /*@NotNull*/ AtomicType targetType) { super(rules); this.targetType = targetType; this.whitespaceAction = targetType.getWhitespaceAction(); builtInValidator = getStringConverter((AtomicType)targetType.getBuiltInBaseType(), rules); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { CharSequence cs = Whitespace.applyWhitespaceNormalization(whitespaceAction, input); try { cs = targetType.preprocess(cs); } catch (ValidationException err) { return new ValidationFailure(err); } ValidationFailure f = builtInValidator.validate(cs); if (f != null) { return f; } StringValue sv = new StringValue(cs); f = targetType.validate(sv, cs, getConversionRules()); if (f == null) { sv.setTypeLabel(targetType); return sv; } else { return f; } } } /** * Converts a string to xs:float */ public static class StringToFloat extends StringConverter { public StringToFloat(ConversionRules rules) { super(rules); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { try { float flt = (float) getConversionRules().getStringToDoubleConverter().stringToNumber(input); return new FloatValue(flt); } catch (NumberFormatException err) { ValidationFailure ve = new ValidationFailure("Cannot convert string to float: " + input.toString()); ve.setErrorCode("FORG0001"); return ve; } } } /** * Converts a string to a double. The rules change in XSD 1.1 to permit "+INF" */ public static class StringToDouble extends StringConverter { net.sf.saxon.type.StringToDouble worker; public StringToDouble(/*@NotNull*/ ConversionRules rules) { super(rules); worker = rules.getStringToDoubleConverter(); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { try { double dble = worker.stringToNumber(input); return new DoubleValue(dble); } catch (NumberFormatException err) { return new ValidationFailure("Cannot convert string to double: " + Err.wrap(input.toString(), Err.VALUE)); } } } /** * Converts a string to an xs:decimal */ public static class StringToDecimal extends StringConverter { /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return DecimalValue.makeDecimalValue(input, true); } /*@Nullable*/ @Override public ValidationFailure validate(/*@NotNull*/ CharSequence input) { if (DecimalValue.castableAsDecimal(input)) { return null; } else { return new ValidationFailure("Cannot convert string to decimal: " + input.toString()); } } } /** * Converts a string to an integer */ public static class StringToInteger extends StringConverter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return IntegerValue.stringToInteger(input.getStringValueCS()); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return IntegerValue.stringToInteger(input); } @Override public ValidationFailure validate(/*@NotNull*/ CharSequence input) { return IntegerValue.castableAsInteger(input); } } /** * Converts a string to a built-in subtype of integer */ public static class StringToIntegerSubtype extends StringConverter { BuiltInAtomicType targetType; public StringToIntegerSubtype(BuiltInAtomicType targetType) { this.targetType = targetType; } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { ConversionResult iv = IntegerValue.stringToInteger(input); if (iv instanceof Int64Value) { boolean ok = IntegerValue.checkRange(((Int64Value)iv).longValue(), targetType); if (ok) { return ((Int64Value)iv).copyAsSubType(targetType); } else { return new ValidationFailure("Integer value is out of range for type " + targetType.toString()); } } else if (iv instanceof BigIntegerValue) { boolean ok = IntegerValue.checkBigRange(((BigIntegerValue)iv).asBigInteger(), targetType); if (ok) { ((BigIntegerValue)iv).setTypeLabel(targetType); return iv; } else { return new ValidationFailure("Integer value is out of range for type " + targetType.toString()); } } else { assert (iv instanceof ValidationFailure); return iv; } } } /** * Converts a string to a duration */ public static class StringToDuration extends StringConverter { /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return DurationValue.makeDuration(input); } } /** * Converts a string to a dayTimeDuration */ public static class StringToDayTimeDuration extends StringConverter { /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return DayTimeDurationValue.makeDayTimeDurationValue(input); } } /** * Converts a string to a yearMonthDuration */ public static class StringToYearMonthDuration extends StringConverter { /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return YearMonthDurationValue.makeYearMonthDurationValue(input); } } /** * Converts a string to a dateTime */ public static class StringToDateTime extends StringConverter { public StringToDateTime(ConversionRules rules) { super(rules); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return DateTimeValue.makeDateTimeValue(input, getConversionRules()); } } /** * Converts a string to a date */ public static class StringToDate extends StringConverter{ public StringToDate(ConversionRules rules) { super(rules); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return DateValue.makeDateValue(input, getConversionRules()); } } /** * Converts a string to a gMonth */ public static class StringToGMonth extends StringConverter { public StringToGMonth(ConversionRules rules) { super(rules); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return GMonthValue.makeGMonthValue(input, getConversionRules()); } } /** * Converts a string to a gYearMonth */ public static class StringToGYearMonth extends StringConverter { public StringToGYearMonth(ConversionRules rules) { super(rules); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return GYearMonthValue.makeGYearMonthValue(input, getConversionRules()); } } /** * Converts a string to a gYear */ public static class StringToGYear extends StringConverter { public StringToGYear(ConversionRules rules) { super(rules); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return GYearValue.makeGYearValue(input, getConversionRules()); } } /** * Converts a string to a gMonthDay */ public static class StringToGMonthDay extends StringConverter { public StringToGMonthDay(ConversionRules rules) { super(rules); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return GMonthDayValue.makeGMonthDayValue(input, getConversionRules()); } } /** * Converts a string to a gDay */ public static class StringToGDayConverter extends StringConverter { public StringToGDayConverter(ConversionRules rules) { super(rules); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return GDayValue.makeGDayValue(input, getConversionRules()); } } /** * Converts a string to a time */ public static class StringToTime extends StringConverter { /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return TimeValue.makeTimeValue(input); } } /** * Converts a string to a boolean */ public static class StringToBoolean extends StringConverter { /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return BooleanValue.fromString(input); } } /** * Converts a string to hexBinary */ public static class StringToHexBinary extends StringConverter { /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { try { return new HexBinaryValue(input); } catch (XPathException e) { return new ValidationFailure(e); } } } /** * Converts String to QName */ public static class StringToQName extends StringConverter { NamespaceResolver nsResolver; public StringToQName(ConversionRules rules) { super(rules); } @Override public boolean isXPath30Conversion() { return true; } public void setNamespaceResolver(NamespaceResolver resolver) { this.nsResolver = resolver; } @Override public NamespaceResolver getNamespaceResolver() { return nsResolver; } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { if (nsResolver == null) { throw new UnsupportedOperationException("Cannot validate a QName without a namespace resolver"); } try { NameChecker nameChecker = getConversionRules().getNameChecker(); String[] parts = nameChecker.getQNameParts(Whitespace.trimWhitespace(input)); String uri = nsResolver.getURIForPrefix(parts[0], true); if (uri == null) { return new ValidationFailure("Namespace prefix " + Err.wrap(parts[0]) + " has not been declared"); } // if (fingerprint == StandardNames.XS_NOTATION) { // // This check added in 9.3. The XSLT spec says that this check should not be performed during // // validation. However, this appears to be based on an incorrect assumption: see spec bug 6952 // if (!rules.isDeclaredNotation(uri, parts[1])) { // return new ValidationFailure("Notation {" + uri + "}" + parts[1] + " is not declared in the schema"); // } // } return new QNameValue(parts[0], uri, parts[1], BuiltInAtomicType.QNAME, nameChecker); } catch (QNameException err) { return new ValidationFailure("Invalid lexical QName " + Err.wrap(input)); } catch (XPathException err) { return new ValidationFailure(err.getMessage()); } } } /** * Converts String to NOTATION */ public static class StringToNotation extends StringConverter { NamespaceResolver nsResolver; public StringToNotation(ConversionRules rules) { super(rules); } @Override public void setNamespaceResolver(NamespaceResolver resolver) { nsResolver = resolver; } @Override public NamespaceResolver getNamespaceResolver() { return nsResolver; } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { if (getNamespaceResolver() == null) { throw new UnsupportedOperationException("Cannot validate a NOTATION without a namespace resolver"); } try { NameChecker nameChecker = getConversionRules().getNameChecker(); String[] parts = nameChecker.getQNameParts(Whitespace.trimWhitespace(input)); String uri = getNamespaceResolver().getURIForPrefix(parts[0], true); if (uri == null) { return new ValidationFailure("Namespace prefix " + Err.wrap(parts[0]) + " has not been declared"); } // This check added in 9.3. The XSLT spec says that this check should not be performed during // validation. However, this appears to be based on an incorrect assumption: see spec bug 6952 if (!getConversionRules().isDeclaredNotation(uri, parts[1])) { return new ValidationFailure("Notation {" + uri + "}" + parts[1] + " is not declared in the schema"); } return new NotationValue(parts[0], uri, parts[1], nameChecker); } catch (QNameException err) { return new ValidationFailure("Invalid lexical QName " + Err.wrap(input)); } catch (XPathException err) { return new ValidationFailure(err.getMessage()); } } } /** * Converts string to anyURI */ public static class StringToAnyURI extends StringConverter { public StringToAnyURI(ConversionRules rules) { super(rules); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { if (getConversionRules().isValidURI(input)) { return new AnyURIValue(input); } else { return new ValidationFailure("Invalid URI: " + input.toString()); } } /*@Nullable*/@Override public ValidationFailure validate(/*@NotNull*/ CharSequence input) { if (getConversionRules().isValidURI(input)) { return null; } else { return new ValidationFailure("Invalid URI: " + input.toString()); } } } /** * Converter that does nothing - it returns the input unchanged */ public static class IdentityConverter extends StringConverter { /*@NotNull*/ public static IdentityConverter THE_INSTANCE = new IdentityConverter(); /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return input; } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { return StringValue.makeStringValue(input); } public boolean isAlwaysSuccessful() { return true; } /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ CharSequence input) { return null; } } /** * Converter from string to plain union types */ public static class StringToUnionConverter extends StringConverter { SimpleType targetType; ConversionRules rules; public StringToUnionConverter(PlainType targetType, ConversionRules rules) { if (!targetType.isPlainType()) { throw new IllegalArgumentException(); } if (((SimpleType)targetType).isNamespaceSensitive()) { throw new IllegalArgumentException(); } this.targetType = (SimpleType)targetType; this.rules = rules; } /** * Convert a string to the target type of this converter. * * @param input the string to be converted * @return either an {@link net.sf.saxon.value.AtomicValue} of the appropriate type for this converter (if conversion * succeeded), or a {@link net.sf.saxon.type.ValidationFailure} if conversion failed. */ /*@NotNull*/ @Override public ConversionResult convertString(/*@NotNull*/ CharSequence input) { try { return targetType.getTypedValue(input, null, rules).next(); } catch (XPathException err) { return new ValidationFailure(ValidationException.makeXPathException(err)); } } } public static class StringToExternalObjectType extends StringConverter { @Override public ConversionResult convertString(CharSequence input) { return new ValidationFailure("Cannot convert string to external object"); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/BuiltInListType.java0000644000175000017500000004442111671711573025100 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.expr.*; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.iter.UnfailingIterator; import net.sf.saxon.value.*; import java.io.Serializable; /** *

This class is used to implement the built-in * list types NMTOKENS, ENTITIES, IDREFS. It is also used to represent the anonymous type of the * xsi:schemaLocation attribute (a list of xs:anyURI values).

* **/ public class BuiltInListType implements ListType, Serializable { private int fingerprint; /*@NotNull*/ public static BuiltInListType ENTITIES = makeListType(NamespaceConstant.SCHEMA, "ENTITIES"); /*@NotNull*/ public static BuiltInListType IDREFS = makeListType(NamespaceConstant.SCHEMA, "IDREFS"); /*@NotNull*/ public static BuiltInListType NMTOKENS = makeListType(NamespaceConstant.SCHEMA, "NMTOKENS"); /*@NotNull*/ public static BuiltInListType ANY_URIS = makeListType(NamespaceConstant.SCHEMA_INSTANCE, "anonymous_schemaLocationType"); /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects */ public boolean isExternalType() { return false; } /** * Determine whether this is a built-in type or a user-defined type */ public boolean isBuiltInType() { return true; } /** * Get the URI of the schema document containing the definition of this type * @return null for a built-in type */ /*@Nullable*/ public String getSystemId() { return null; } /** * Get the redefinition level. This is zero for a component that has not been redefined; * for a redefinition of a level-0 component, it is 1; for a redefinition of a level-N * component, it is N+1. This concept is used to support the notion of "pervasive" redefinition: * if a component is redefined at several levels, the top level wins, but it is an error to have * two versions of the component at the same redefinition level. * @return the redefinition level */ public int getRedefinitionLevel() { return 0; } /** * Determine how values of this simple type are whitespace-normalized. * * @return one of {@link net.sf.saxon.value.Whitespace#PRESERVE}, {@link net.sf.saxon.value.Whitespace#COLLAPSE}, * {@link net.sf.saxon.value.Whitespace#REPLACE}. */ public int getWhitespaceAction() { return Whitespace.COLLAPSE; } /** * The SimpleType of the items in the list. */ /*@NotNull*/ private BuiltInAtomicType itemType; /** * Create a new ListType. * @param fingerprint identifies the name of the type */ public BuiltInListType(int fingerprint) { this.fingerprint = fingerprint; switch (fingerprint) { case StandardNames.XS_ENTITIES: itemType = BuiltInAtomicType.ENTITY; break; case StandardNames.XS_IDREFS: itemType = BuiltInAtomicType.IDREF; break; case StandardNames.XS_NMTOKENS: itemType = BuiltInAtomicType.NMTOKEN; break; case StandardNames.XSI_SCHEMA_LOCATION_TYPE: itemType = BuiltInAtomicType.ANY_URI; break; } } /** * Get the validation status - always valid */ public int getValidationStatus() { return VALIDATED; } /** * Returns the base type that this type inherits from. * If this type is a Simpletype that is a built in primitive type then null is returned. * @return the base type. */ /*@NotNull*/ public SchemaType getBaseType() { return AnySimpleType.getInstance(); } /** * Test whether this Simple Type is an atomic type * @return false, this is not an atomic type */ public boolean isAtomicType() { return false; } /** * Ask whether this type is an ID type. This is defined to be any simple type * who typed value may contain atomic values of type xs:ID: that is, it includes types derived * from ID by restriction, list, or union. Note that for a node to be treated * as an ID, its typed value must be a *single* atomic value of type ID; the type of the * node, however, can still allow a list. */ public boolean isIdType() { return false; } /** * Ask whether this type is an IDREF or IDREFS type. This is defined to be any simple type * who typed value may contain atomic values of type xs:IDREF: that is, it includes types derived * from IDREF or IDREFS by restriction, list, or union */ public boolean isIdRefType() { return fingerprint == StandardNames.XS_IDREFS; } /** * Returns true if this type is derived by list, or if it is derived by restriction * from a list type, or if it is a union that contains a list as one of its members */ public boolean isListType() { return true; } public boolean isUnionType() { return false; } /** * Test whether this is an anonymous type * @return true if this SchemaType is an anonymous type */ public boolean isAnonymousType() { return false; } /*@NotNull*/ public SchemaType getBuiltInBaseType() { return this; } public boolean isNamespaceSensitive() { return false; } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ public String getName() { return StandardNames.getLocalName(fingerprint); } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return NamespaceConstant.SCHEMA; } /** * Get the fingerprint of the name of this type * @return the fingerprint. Returns an invented fingerprint for an anonymous type. */ public int getFingerprint() { return fingerprint; } /** * Get the namecode of the name of this type. Because built-in types don't depend on the namePool, * this actually returns the fingerprint, which contains no information about the namespace prefix */ public int getNameCode() { return fingerprint; } /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * * @return a lexical QName identifying the type */ public String getDisplayName() { return StandardNames.getDisplayName(fingerprint); } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public boolean isComplexType() { return false; } /** * Test whether this SchemaType is a simple type * @return true if this SchemaType is a simple type */ public boolean isSimpleType() { return true; } /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public int getBlock() { return 0; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ /*@NotNull*/ public SchemaType getKnownBaseType() throws IllegalStateException { return AnySimpleType.getInstance(); } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ public int getDerivationMethod() { return SchemaType.DERIVATION_LIST; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public boolean allowsDerivation(int derivation) { return true; } /** * Get the typed value of a node that is annotated with this schema type. This method must be called * only for a valid type. * * @param node the node whose typed value is required * @return a SequenceIterator over the atomic values making up the typed value of the specified * node. The objects returned by this iterator are of type {@link net.sf.saxon.value.AtomicValue} */ /*@NotNull*/ public SequenceIterator getTypedValue(/*@NotNull*/ NodeInfo node) throws XPathException { try { return getTypedValue(node.getStringValue(), new InscopeNamespaceResolver(node), node.getConfiguration().getConversionRules()); } catch (ValidationException err) { throw new XPathException("Internal error: value doesn't match its type annotation. " + err.getMessage()); } } /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ public Value atomize(/*@NotNull*/ NodeInfo node) throws XPathException { return new SequenceExtent(getTypedValue(node)).simplify(); } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(/*@NotNull*/ SchemaType other) { return other.getFingerprint() == getFingerprint(); } public String getDescription() { return getDisplayName(); } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException * if the derivation is not allowed */ public void checkTypeDerivationIsOK(SchemaType type, int block) throws SchemaException { // } /** * Get the local name of this type * @return the local part of the name, or null if the type is anonymous */ public String getLocalName() { return getDisplayName().substring(3); } /** * Returns the simpleType of the items in this ListType. * @return the simpleType of the items in this ListType. */ /*@NotNull*/ public SimpleType getItemType() { return itemType; } /** * Apply the whitespace normalization rules for this simple type * @param value the string before whitespace normalization * @return the string after whitespace normalization */ public String applyWhitespaceNormalization(String value) { return Whitespace.collapseWhitespace(value).toString(); } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env the XPath static context * @throws net.sf.saxon.trans.XPathException * if the expression will never deliver a value of the correct type */ public void analyzeContentExpression(/*@NotNull*/ Expression expression, int kind, StaticContext env) throws XPathException { BuiltInAtomicType.analyzeContentExpression(this, expression, env, kind); } /** * Check whether a given input string is valid according to this SimpleType * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param rules the conversion rules for this configuration * @return either null to indicate that validation succeeded, or a ValidationFailure object giving information * about why it failed * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ /*@Nullable*/ public ValidationFailure validateContent( /*@NotNull*/ CharSequence value, /*@Nullable*/ NamespaceResolver nsResolver, /*@NotNull*/ ConversionRules rules) { SimpleType base = getItemType(); StringTokenIterator iter = new StringTokenIterator(value.toString()); int count = 0; while (true) { StringValue val = (StringValue)iter.next(); if (val == null) break; count++; ValidationFailure v = base.validateContent(val.getStringValue(), nsResolver, rules); if (v != null) { return v; } } if (count == 0) { return new ValidationFailure("The built-in list type " + StandardNames.getDisplayName(fingerprint) + " does not allow a zero-length list"); } return null; } /** * Get the typed value of a given input string. This method assumes that the input value * is valid according to this SimpleType * @param value the string whose typed value is required * @param resolver namespace resolver for namespace-sensitive content * @param rules */ /*@NotNull*/ public SequenceIterator getTypedValue(/*@NotNull*/ CharSequence value, NamespaceResolver resolver, ConversionRules rules) throws ValidationException { UnfailingIterator iter = new StringTokenIterator(value.toString()); ListTypeMappingFunction map = new ListTypeMappingFunction(); map.resolver = resolver; map.atomicType = (AtomicType)getItemType(); map.rules = rules; return new MappingIterator(iter, map); } /*@NotNull*/ private static BuiltInListType makeListType(String namespace, String lname) { BuiltInListType t = new BuiltInListType(StandardNames.getFingerprint(namespace, lname)); BuiltInType.register(t.getFingerprint(), t); return t; } private static class ListTypeMappingFunction implements MappingFunction { public NamespaceResolver resolver; /*@Nullable*/ public AtomicType atomicType; public ConversionRules rules; /** * The typed value of a list-valued node is obtained by tokenizing the string value and * applying a mapping function to the sequence of tokens. * This method implements the mapping function. It is for internal use only. * For details see {@link net.sf.saxon.expr.MappingFunction} */ public SequenceIterator map(/*@NotNull*/ StringValue item) throws XPathException { try { return atomicType.getTypedValue(item.getStringValue(), resolver, rules); } catch (ValidationException err) { throw new XPathException(err); } } } /** * Apply any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess * @param input the value to be preprocessed * @return the value after preprocessing */ public CharSequence preprocess(CharSequence input) { return input; } /** * Reverse any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess. This is called when converting a value of this type to * a string * @param input the value to be postprocessed: this is the "ordinary" result of converting * the value to a string * @return the value after postprocessing */ public CharSequence postprocess(CharSequence input) throws ValidationException { return input; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/ValidationException.java0000644000175000017500000002316411671711573026006 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.util.Navigator; import org.xml.sax.Locator; import javax.xml.transform.SourceLocator; /** * This exception indicates a failure when validating an instance against a type * defined in a schema. */ public class ValidationException extends XPathException implements SourceLocator, Locator { private String systemId; private String publicId; private int lineNumber = -1; private int columnNumber = -1; /*@Nullable*/ private NodeInfo node; private int schemaPart = -1; private String constraintName; private String constraintClauseNumber; private String path; // TODO: during output validation, it would sometimes be useful to know what the position in the input file was. /** * Creates a new ValidationException with the given message. * @param message the message for this Exception */ public ValidationException(String message) { super(message); setIsTypeError(true); } /** * Creates a new ValidationException with the given nested * exception. * @param exception the nested exception */ public ValidationException(Exception exception) { super(exception); setIsTypeError(true); } /** * Creates a new ValidationException with the given message * and nested exception. * @param message the detail message for this exception * @param exception the nested exception */ public ValidationException(String message, Exception exception) { super(message, exception); setIsTypeError(true); } /** * Create a new ValidationException from a message and a Locator. * @param message The error or warning message. * @param locator The locator object for the error or warning. */ public ValidationException(String message, SourceLocator locator) { super(message, locator); setIsTypeError(true); // With Xerces, it's enough to store the locator as part of the exception. But with Crimson, // the locator is destroyed when the parse terminates, which means the location information // will not be available in the final error message. So we copy the location information now, // as part of the exception object itself. setSourceLocator(locator); } /** * Set a reference to the constraint in XML Schema that is not satisfied * @param schemaPart - 1 or 2, depending whether the constraint is in XMLSchema part 1 or part 2 * @param constraintName - the short name of the constraint in XMLSchema, as a fragment identifier in the * HTML of the XML Schema Part 1 specification * @param clause - the clause number within the description of that constraint */ public void setConstraintReference(int schemaPart, String constraintName, String clause) { this.schemaPart = schemaPart; this.constraintName = constraintName; this.constraintClauseNumber = clause; } /** * Copy the constraint reference from another exception object * @param e the other exception object from which to copy the information */ public void setConstraintReference(/*@NotNull*/ ValidationException e) { schemaPart = e.schemaPart; constraintName = e.constraintName; constraintClauseNumber = e.constraintClauseNumber; } /** * Get the constraint reference as a string for inserting into an error message. * @return the reference as a message, or null if no information is available */ /*@Nullable*/ public String getConstraintReferenceMessage() { if (schemaPart == -1) { return null; } return "See http://www.w3.org/TR/xmlschema11-" + schemaPart + "/#" + constraintName + " clause " + constraintClauseNumber; } /** * Get the "schema part" component of the constraint reference * @return 1 or 2 depending on whether the violated constraint is in XML Schema Part 1 or Part 2; * or -1 if there is no constraint reference */ public int getConstraintSchemaPart() { return schemaPart; } /** * Get the constraint name * @return the name of the violated constraint, in the form of a fragment identifier within * the published XML Schema specification; or null if the information is not available. */ /*@Nullable*/ public String getConstraintName() { return constraintName; } /** * Get the constraint clause number * @return the section number of the clause containing the constraint that has been violated. * Generally a decimal number in the form n.n.n; possibly a sequence of such numbers separated * by semicolons. Or null if the information is not available. */ /*@Nullable*/ public String getConstraintClauseNumber() { return constraintClauseNumber; } /** * Get the constraint name and clause in the format defined in XML Schema Part C (Outcome Tabulations). * This mandates the format validation-rule-name.clause-number * @return the constraint reference, for example "cos-ct-extends.1.2"; or null if the reference * is not known. */ /*@NotNull*/ public String getConstraintReference() { return (constraintName == null ? "" : constraintName) + '.' + (constraintClauseNumber == null ? "" : constraintClauseNumber); } /** * Set the path in the source document * @param path the path to the invalid element in the source document */ public void setPath(String path) { this.path = path; } /** * Returns the String representation of this Exception * @return the String representation of this Exception **/ public String toString() { StringBuilder sb = new StringBuilder("ValidationException: "); String message = getMessage(); if (message != null) { sb.append(message); } return sb.toString(); } public String getPublicId() { SourceLocator loc = getLocator(); if (publicId == null && loc != null && loc != this) { return loc.getPublicId(); } else{ return publicId; } } public String getSystemId() { SourceLocator loc = getLocator(); if (systemId == null && loc != null && loc != this) { return loc.getSystemId(); } else{ return systemId; } } public int getLineNumber() { SourceLocator loc = getLocator(); if (lineNumber == -1 && loc != null && loc != this) { return loc.getLineNumber(); } else{ return lineNumber; } } public int getColumnNumber() { SourceLocator loc = getLocator(); if (columnNumber == -1 && loc != null && loc != this) { return loc.getColumnNumber(); } else{ return columnNumber; } } /*@Nullable*/ public NodeInfo getNode() { return node; } /*@Nullable*/ public String getPath() { if (path != null) { return path; } else if (node != null) { return Navigator.getPath(node); } else { return null; } } public void setPublicId(String id) { publicId = id; } public void setSystemId(String id) { systemId = id; } public void setLineNumber(int line) { lineNumber = line; } public void setColumnNumber(int column) { columnNumber = column; } public void setLocator(/*@Nullable*/ Locator locator) { if (locator != null) { setPublicId(locator.getPublicId()); setSystemId(locator.getSystemId()); setLineNumber(locator.getLineNumber()); setColumnNumber(locator.getColumnNumber()); if (locator instanceof NodeInfo) { node = ((NodeInfo)locator); } } super.setLocator(null); } public void setSourceLocator(/*@Nullable*/ SourceLocator locator) { if (locator != null) { setPublicId(locator.getPublicId()); setSystemId(locator.getSystemId()); setLineNumber(locator.getLineNumber()); setColumnNumber(locator.getColumnNumber()); if (locator instanceof NodeInfo) { node = ((NodeInfo)locator); } } super.setLocator(null); } public SourceLocator getLocator() { SourceLocator loc = super.getLocator(); if (loc != null) { return loc; } else { return this; } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/BuiltInType.java0000644000175000017500000000564311671711573024247 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.expr.sort.IntHashMap; import net.sf.saxon.om.StandardNames; import java.io.Serializable; /** * This non-instantiable class acts as a register of Schema objects containing all the built-in types: * that is, the types defined in the "xs" namespace. * *

Previously called BuiltInSchemaFactory; but its original function has largely been moved to the two * classes {@link BuiltInAtomicType} and {@link BuiltInListType} */ public abstract class BuiltInType implements Serializable { /** * Table of all built in types */ /*@NotNull*/ private static IntHashMap lookup = new IntHashMap(100); /** * Class is never instantiated */ private BuiltInType() { } static { register(StandardNames.XS_ANY_SIMPLE_TYPE, AnySimpleType.getInstance()); register(StandardNames.XS_ANY_TYPE, AnyType.getInstance()); register(StandardNames.XS_UNTYPED, Untyped.getInstance()); register(StandardNames.XS_ERROR, ErrorType.getInstance()); } /** * Get the schema type with a given fingerprint * @param fingerprint the fingerprint representing the name of the required type * @return the SchemaType object representing the given type, if known, otherwise null */ public static SchemaType getSchemaType(int fingerprint) { SchemaType st = lookup.get(fingerprint); if (st == null) { // this means the method has been called before doing the static initialization of BuiltInAtomicType // or BuiltInListType. So force it now if (BuiltInAtomicType.DOUBLE == null || BuiltInListType.NMTOKENS == null) { // no action, except to force the initialization to run } st = lookup.get(fingerprint); } return st; } /** * Method for internal use to register a built in type with this class * @param fingerprint the fingerprint of the type name * @param type the SchemaType representing the built in type */ static void register(int fingerprint, SchemaType type) { lookup.put(fingerprint, type); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/PlainType.java0000644000175000017500000000247011671711573023737 0ustar mathieumathieupackage net.sf.saxon.type; import java.util.Set; /** * A "plain type" is either an atomic type, or a union type that (a) imposes no restrictions other * than those imposed by its member types, and (b) has exclusively plain types as its member types */ public interface PlainType extends ItemType { public boolean isExternalType(); /** * Get the set of plain types that are subsumed by this type * @return for an atomic type, the type itself; for a plain union type, the set of plain types * in its transitive membership */ public Set getPlainMemberTypes(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/Untyped.java0000644000175000017500000004774611671711573023501 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.expr.sort.IntHashSet; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StandardNames; import net.sf.saxon.tree.iter.SingletonIterator; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import java.io.Serializable; /** * This class has a singleton instance which represents the complex type xdt:untyped, * used for elements that have not been validated. */ public final class Untyped implements ComplexType, Serializable { /*@NotNull*/ private static Untyped theInstance = new Untyped(); /** * Private constructor */ private Untyped() { } /** * Get the validation status - always valid */ public int getValidationStatus() { return VALIDATED; } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ /*@NotNull*/ public String getName() { return "untyped"; } /** * Get the redefinition level. This is zero for a component that has not been redefined; * for a redefinition of a level-0 component, it is 1; for a redefinition of a level-N * component, it is N+1. This concept is used to support the notion of "pervasive" redefinition: * if a component is redefined at several levels, the top level wins, but it is an error to have * two versions of the component at the same redefinition level. * @return the redefinition level */ public int getRedefinitionLevel() { return 0; } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return NamespaceConstant.SCHEMA; } /** * Get the variety of this complex type. This will be one of the values * {@link #VARIETY_EMPTY}, {@link #VARIETY_MIXED}, {@link #VARIETY_SIMPLE}, or * {@link #VARIETY_ELEMENT_ONLY} */ public int getVariety() { return VARIETY_MIXED; } /** * Get the URI of the schema document containing the definition of this type * @return null for a built-in type */ /*@Nullable*/ public String getSystemId() { return null; } /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public int getBlock() { return 0; } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ public int getDerivationMethod() { return 0; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public boolean allowsDerivation(int derivation) { return false; } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration */ public void checkTypeDerivationIsOK(SchemaType type, int block) { } /** * Get the fingerprint of the name of this type * * @return the fingerprint. Returns an invented fingerprint for an anonymous type. */ public int getFingerprint() { return StandardNames.XS_UNTYPED; } /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. */ public int getNameCode() { return StandardNames.XS_UNTYPED; } /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * * @return a lexical QName identifying the type */ /*@NotNull*/ public String getDisplayName() { return "xs:untyped"; } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public boolean isComplexType() { return true; } /** * Test whether this is an anonymous type * * @return true if this SchemaType is an anonymous type */ public boolean isAnonymousType() { return false; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ /*@NotNull*/ public SchemaType getKnownBaseType() throws IllegalStateException { return AnyType.getInstance(); } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(SchemaType other) { return (other instanceof Untyped); } /** * Returns the base type that this type inherits from. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. */ /*@NotNull*/ public SchemaType getBaseType() { return AnyType.getInstance(); } /** * Get the singular instance of this class * * @return the singular object representing xs:anyType */ /*@NotNull*/ public static Untyped getInstance() { return theInstance; } /** * Test whether this ComplexType has been marked as abstract. * * @return false: this class is not abstract. */ public boolean isAbstract() { return false; } /** * Test whether this SchemaType is a simple type * * @return true if this SchemaType is a simple type */ public boolean isSimpleType() { return false; } /** * Test whether this SchemaType is an atomic type * * @return true if this SchemaType is an atomic type */ public boolean isAtomicType() { return false; } /** * Ask whether this type is an ID type. This is defined to be any simple type * who typed value may contain atomic values of type xs:ID: that is, it includes types derived * from ID by restriction, list, or union. Note that for a node to be treated * as an ID, its typed value must be a *single* atomic value of type ID; the type of the * node, however, can still allow a list. */ public boolean isIdType() { return false; } /** * Ask whether this type is an IDREF or IDREFS type. This is defined to be any simple type * who typed value may contain atomic values of type xs:IDREF: that is, it includes types derived * from IDREF or IDREFS by restriction, list, or union */ public boolean isIdRefType() { return false; } /** * Test whether this complex type has complex content * * @return true: this complex type has complex content */ public boolean isComplexContent() { return true; } /** * Test whether this complex type has simple content * * @return false: this complex type has complex content */ public boolean isSimpleContent() { return false; } /** * Test whether this complex type has "all" content, that is, a content model * using an xs:all compositor * * @return false: this complex type does not use an "all" compositor */ public boolean isAllContent() { return false; } /** * For a complex type with simple content, return the simple type of the content. * Otherwise, return null. * * @return null: this complex type does not have simple content */ /*@Nullable*/ public SimpleType getSimpleContentType() { return null; } /** * Test whether this complex type is derived by restriction * * @return true: this type is treated as a restriction of xs:anyType */ public boolean isRestricted() { return true; } /** * Test whether the content type of this complex type is empty * * @return false: the content model is not empty */ public boolean isEmptyContent() { return false; } /** * Test whether the content model of this complexType allows empty content * * @return true: the content is allowed to be empty */ public boolean isEmptiable() { return true; } /** * Test whether this complex type allows mixed content * * @return true: mixed content is allowed */ public boolean isMixedContent() { return true; } /** * Get a description of this type for use in diagnostics * * @return the string "xs:anyType" */ /*@NotNull*/ public String getDescription() { return "xs:untyped"; } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env the static context */ public void analyzeContentExpression(Expression expression, int kind, StaticContext env) { //return; } /** * Get the typed value of a node that is annotated with this schema type * * @param node the node whose typed value is required * @return an iterator returning a single untyped atomic value, equivalent to the string value of the node. This * follows the standard rules for elements with mixed content. */ /*@NotNull*/ public SequenceIterator getTypedValue(/*@NotNull*/ NodeInfo node) { return SingletonIterator.makeIterator(new UntypedAtomicValue(node.getStringValueCS())); } /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ /*@NotNull*/ public Value atomize(/*@NotNull*/ NodeInfo node) { return new UntypedAtomicValue(node.getStringValue()); } /** * Test whether this complex type subsumes another complex type. The algorithm * used is as published by Thompson and Tobin, XML Europe 2003. * * @param sub the other type (the type that is derived by restriction, validly or otherwise) * @param compiler used for error reporting * @return null indicating that this type does indeed subsume the other; or a string indicating * why it doesn't. */ // public String subsumes(ComplexType sub, ISchemaCompiler compiler) { // return null; // } /** * Find an element particle within this complex type definition having a given element name * (identified by fingerprint), and return the schema type associated with that element particle. * If there is no such particle, return null. If the fingerprint matches an element wildcard, * return the type of the global element declaration with the given name if one exists, or AnyType * if none exists and lax validation is permitted by the wildcard. * * @param fingerprint Identifies the name of the child element within this content model * @param considerExtensions */ /*@NotNull*/ public SchemaType getElementParticleType(int fingerprint, boolean considerExtensions) { return this; } /** * Find an element particle within this complex type definition having a given element name * (identified by fingerprint), and return the cardinality associated with that element particle, * that is, the number of times the element can occur within this complex type. The value is one of * {@link net.sf.saxon.expr.StaticProperty#EXACTLY_ONE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_ONE}, * {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ZERO_OR_MORE}, {@link net.sf.saxon.expr.StaticProperty#ALLOWS_ONE_OR_MORE}, * If there is no such particle, return zero. * * @param fingerprint Identifies the name of the child element within this content model * @param considerExtensions */ public int getElementParticleCardinality(int fingerprint, boolean considerExtensions) { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Find an attribute use within this complex type definition having a given attribute name * (identified by fingerprint), and return the schema type associated with that attribute. * If there is no such attribute use, return null. If the fingerprint matches an attribute wildcard, * return the type of the global attribute declaration with the given name if one exists, or AnySimpleType * if none exists and lax validation is permitted by the wildcard. * * @param fingerprint Identifies the name of the child element within this content model */ /*@NotNull*/ public SimpleType getAttributeUseType(int fingerprint) { return BuiltInAtomicType.UNTYPED_ATOMIC; } /** * Find an attribute use within this complex type definition having a given attribute name * (identified by fingerprint), and return the cardinality associated with that attribute, * which will always be 0, 1, or 0-or-1. * If there is no such attribute use, return null. If the fingerprint matches an attribute wildcard, * return the type of the global attribute declaration with the given name if one exists, or AnySimpleType * if none exists and lax validation is permitted by the wildcard. *

* If there are types derived from this type by extension, search those too. * @param fingerprint Identifies the name of the child element within this content model * @return the schema type associated with the attribute use identified by the fingerprint. * If there is no such attribute use, return null. */ public int getAttributeUseCardinality(int fingerprint) throws SchemaException { return StaticProperty.ALLOWS_ZERO_OR_ONE; } /** * Return true if this type (or any known type derived from it by extension) allows the element * to have one or more attributes. * @return true if attributes are allowed */ public boolean allowsAttributes() { return true; } /** * Get a list of all the names of elements that can appear as children of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), return null. * * @param children an integer set, initially empty, which on return will hold the fingerprints of all permitted * child elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the children, typically because of wildcards. In this case the other contents of the set should * @param ignoreWildcards */ public void gatherAllPermittedChildren(/*@NotNull*/ IntHashSet children, boolean ignoreWildcards) throws SchemaException { children.add(-1); } /** * Get a list of all the names of elements that can appear as descendants of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), return null. * * @param descendants an integer set, initially empty, which on return will hold the fingerprints of all permitted * descendant elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the descendants, typically because of wildcards. In this case the other contents of the set should * be ignored. */ public void gatherAllPermittedDescendants(/*@NotNull*/ IntHashSet descendants) throws SchemaException { descendants.add(-1); } /** * Assuming an element is a permitted descendant in the content model of this type, determine * the type of the element when it appears as a descendant. If it appears with more than one type, * return xs:anyType. * @param fingerprint the name of the required descendant element * @return the type of the descendant element; null if the element cannot appear as a descendant; * anyType if it can appear with several different types */ /*@NotNull*/ public SchemaType getDescendantElementType(int fingerprint) throws SchemaException { return this; } /** * Assuming an element is a permitted descendant in the content model of this type, determine * the cardinality of the element when it appears as a descendant. * @param fingerprint the name of the required descendant element * @return the cardinality of the descendant element within this complex type */ public int getDescendantElementCardinality(int fingerprint) throws SchemaException { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Ask whether this type (or any known type derived from it by extension) allows the element * to have children that match a wildcard * @return true if the content model of this type, or its extensions, contains an element wildcard */ public boolean containsElementWildcard() { 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/BuiltInAtomicType.java0000644000175000017500000012645311671711573025407 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.Literal; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.expr.instruct.ValueOf; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.iter.EmptyIterator; import net.sf.saxon.tree.iter.SingletonIterator; import net.sf.saxon.value.*; import java.io.Serializable; import java.util.HashSet; import java.util.Set; /** * This class represents a built-in atomic type, which may be either a primitive type * (such as xs:decimal or xs:anyURI) or a derived type (such as xs:ID or xs:dayTimeDuration). */ public class BuiltInAtomicType implements AtomicType, Serializable { int fingerprint; int baseFingerprint; int primitiveFingerprint; boolean ordered = false; /*@NotNull*/ public static BuiltInAtomicType ANY_ATOMIC = makeAtomicType(StandardNames.XS_ANY_ATOMIC_TYPE, AnySimpleType.getInstance(), true); /*@NotNull*/ public static BuiltInAtomicType NUMERIC = makeAtomicType(StandardNames.XS_NUMERIC, ANY_ATOMIC, true); /*@NotNull*/ public static BuiltInAtomicType STRING = makeAtomicType(StandardNames.XS_STRING, ANY_ATOMIC, true); /*@NotNull*/ public static BuiltInAtomicType BOOLEAN = makeAtomicType(StandardNames.XS_BOOLEAN, ANY_ATOMIC, true); /*@NotNull*/ public static BuiltInAtomicType DURATION = makeAtomicType(StandardNames.XS_DURATION, ANY_ATOMIC, false); /*@NotNull*/ public static BuiltInAtomicType DATE_TIME = makeAtomicType(StandardNames.XS_DATE_TIME, ANY_ATOMIC, true); /*@NotNull*/ public static BuiltInAtomicType DATE = makeAtomicType(StandardNames.XS_DATE, ANY_ATOMIC, true); /*@NotNull*/ public static BuiltInAtomicType TIME = makeAtomicType(StandardNames.XS_TIME, ANY_ATOMIC, true); /*@NotNull*/ public static BuiltInAtomicType G_YEAR_MONTH = makeAtomicType(StandardNames.XS_G_YEAR_MONTH, ANY_ATOMIC, false); /*@NotNull*/ public static BuiltInAtomicType G_MONTH = makeAtomicType(StandardNames.XS_G_MONTH, ANY_ATOMIC, false); /*@NotNull*/ public static BuiltInAtomicType G_MONTH_DAY = makeAtomicType(StandardNames.XS_G_MONTH_DAY, ANY_ATOMIC, false); /*@NotNull*/ public static BuiltInAtomicType G_YEAR = makeAtomicType(StandardNames.XS_G_YEAR, ANY_ATOMIC, false); /*@NotNull*/ public static BuiltInAtomicType G_DAY = makeAtomicType(StandardNames.XS_G_DAY, ANY_ATOMIC, false); /*@NotNull*/ public static BuiltInAtomicType HEX_BINARY = makeAtomicType(StandardNames.XS_HEX_BINARY, ANY_ATOMIC, false); /*@NotNull*/ public static BuiltInAtomicType BASE64_BINARY = makeAtomicType(StandardNames.XS_BASE64_BINARY, ANY_ATOMIC, false); /*@NotNull*/ public static BuiltInAtomicType ANY_URI = makeAtomicType(StandardNames.XS_ANY_URI, ANY_ATOMIC, true);; /*@NotNull*/ public static BuiltInAtomicType QNAME = makeAtomicType(StandardNames.XS_QNAME, ANY_ATOMIC, false); /*@NotNull*/ public static BuiltInAtomicType NOTATION = makeAtomicType(StandardNames.XS_NOTATION, ANY_ATOMIC, false); /*@NotNull*/ public static BuiltInAtomicType UNTYPED_ATOMIC = makeAtomicType(StandardNames.XS_UNTYPED_ATOMIC, ANY_ATOMIC, true); /*@NotNull*/ public static BuiltInAtomicType DECIMAL = makeAtomicType(StandardNames.XS_DECIMAL, NUMERIC, true); /*@NotNull*/ public static BuiltInAtomicType FLOAT = makeAtomicType(StandardNames.XS_FLOAT, NUMERIC, true); /*@NotNull*/ public static BuiltInAtomicType DOUBLE = makeAtomicType(StandardNames.XS_DOUBLE, NUMERIC, true); /*@NotNull*/ public static BuiltInAtomicType INTEGER = makeAtomicType(StandardNames.XS_INTEGER, DECIMAL, true); /*@NotNull*/ public static BuiltInAtomicType NON_POSITIVE_INTEGER = makeAtomicType(StandardNames.XS_NON_POSITIVE_INTEGER, INTEGER, true); /*@NotNull*/ public static BuiltInAtomicType NEGATIVE_INTEGER = makeAtomicType(StandardNames.XS_NEGATIVE_INTEGER, NON_POSITIVE_INTEGER, true); /*@NotNull*/ public static BuiltInAtomicType LONG = makeAtomicType(StandardNames.XS_LONG, INTEGER, true); /*@NotNull*/ public static BuiltInAtomicType INT = makeAtomicType(StandardNames.XS_INT, LONG, true); /*@NotNull*/ public static BuiltInAtomicType SHORT = makeAtomicType(StandardNames.XS_SHORT, INT, true); /*@NotNull*/ public static BuiltInAtomicType BYTE = makeAtomicType(StandardNames.XS_BYTE, SHORT, true); /*@NotNull*/ public static BuiltInAtomicType NON_NEGATIVE_INTEGER = makeAtomicType(StandardNames.XS_NON_NEGATIVE_INTEGER, INTEGER, true); /*@NotNull*/ public static BuiltInAtomicType POSITIVE_INTEGER = makeAtomicType(StandardNames.XS_POSITIVE_INTEGER, NON_NEGATIVE_INTEGER, true); /*@NotNull*/ public static BuiltInAtomicType UNSIGNED_LONG = makeAtomicType(StandardNames.XS_UNSIGNED_LONG, NON_NEGATIVE_INTEGER, true); /*@NotNull*/ public static BuiltInAtomicType UNSIGNED_INT = makeAtomicType(StandardNames.XS_UNSIGNED_INT, UNSIGNED_LONG, true); /*@NotNull*/ public static BuiltInAtomicType UNSIGNED_SHORT = makeAtomicType(StandardNames.XS_UNSIGNED_SHORT, UNSIGNED_INT, true); /*@NotNull*/ public static BuiltInAtomicType UNSIGNED_BYTE = makeAtomicType(StandardNames.XS_UNSIGNED_BYTE, UNSIGNED_SHORT, true); /*@NotNull*/ public static BuiltInAtomicType YEAR_MONTH_DURATION = makeAtomicType(StandardNames.XS_YEAR_MONTH_DURATION, DURATION, true); /*@NotNull*/ public static BuiltInAtomicType DAY_TIME_DURATION = makeAtomicType(StandardNames.XS_DAY_TIME_DURATION, DURATION, true); /*@NotNull*/ public static BuiltInAtomicType NORMALIZED_STRING = makeAtomicType(StandardNames.XS_NORMALIZED_STRING, STRING, true); /*@NotNull*/ public static BuiltInAtomicType TOKEN = makeAtomicType(StandardNames.XS_TOKEN, NORMALIZED_STRING, true); /*@NotNull*/ public static BuiltInAtomicType LANGUAGE = makeAtomicType(StandardNames.XS_LANGUAGE, TOKEN, true); /*@NotNull*/ public static BuiltInAtomicType NAME = makeAtomicType(StandardNames.XS_NAME, TOKEN, true); /*@NotNull*/ public static BuiltInAtomicType NMTOKEN = makeAtomicType(StandardNames.XS_NMTOKEN, TOKEN, true); /*@NotNull*/ public static BuiltInAtomicType NCNAME = makeAtomicType(StandardNames.XS_NCNAME, NAME, true); /*@NotNull*/ public static BuiltInAtomicType ID = makeAtomicType(StandardNames.XS_ID, NCNAME, true); /*@NotNull*/ public static BuiltInAtomicType IDREF = makeAtomicType(StandardNames.XS_IDREF, NCNAME, true); /*@NotNull*/ public static BuiltInAtomicType ENTITY = makeAtomicType(StandardNames.XS_ENTITY, NCNAME, true); /*@NotNull*/ public static BuiltInAtomicType DATE_TIME_STAMP = makeAtomicType(StandardNames.XS_DATE_TIME_STAMP, DATE_TIME, true); static { } private BuiltInAtomicType(int fingerprint) { this.fingerprint = fingerprint; } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ public String getName() { if (fingerprint == StandardNames.XS_NUMERIC) { return "numeric"; } else { return StandardNames.getLocalName(fingerprint); } } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return NamespaceConstant.SCHEMA; } /** * Determine whether the type is abstract, that is, whether it cannot have instances that are not also * instances of some concrete subtype */ public boolean isAbstract() { switch (fingerprint) { case StandardNames.XS_NOTATION: case StandardNames.XS_ANY_ATOMIC_TYPE: case StandardNames.XS_NUMERIC: case StandardNames.XS_ANY_SIMPLE_TYPE: return true; default: return false; } } /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects */ public boolean isExternalType() { return false; } /** * Determine whether this is a built-in type or a user-defined type */ public boolean isBuiltInType() { return true; } /** * Get the name of this type as a StructuredQName, unless the type is anonymous, in which case * return null * @return the name of the atomic type, or null if the type is anonymous. */ /*@NotNull*/ public StructuredQName getTypeName() { return new StructuredQName( StandardNames.getPrefix(fingerprint), StandardNames.getURI(fingerprint), StandardNames.getLocalName(fingerprint) ); } /** * Get the redefinition level. This is zero for a component that has not been redefined; * for a redefinition of a level-0 component, it is 1; for a redefinition of a level-N * component, it is N+1. This concept is used to support the notion of "pervasive" redefinition: * if a component is redefined at several levels, the top level wins, but it is an error to have * two versions of the component at the same redefinition level. * @return the redefinition level */ public int getRedefinitionLevel() { return 0; } /** * Determine whether the atomic type is ordered, that is, whether less-than and greater-than comparisons * are permitted * * @return true if ordering operations are permitted */ public boolean isOrdered() { return ordered; } /** * Get the URI of the schema document where the type was originally defined. * * @return the URI of the schema document. Returns null if the information is unknown or if this * is a built-in type */ /*@Nullable*/ public String getSystemId() { return null; } /** * Determine whether the atomic type is numeric * * @return true if the type is a built-in numeric type */ public boolean isPrimitiveNumeric() { switch (fingerprint) { case StandardNames.XS_INTEGER: case StandardNames.XS_DECIMAL: case StandardNames.XS_DOUBLE: case StandardNames.XS_FLOAT: case StandardNames.XS_NUMERIC: return true; default: return false; } } /** * Get the validation status - always valid */ public final int getValidationStatus() { return VALIDATED; } /** * Returns the value of the 'block' attribute for this type, as a bit-significant * integer with fields such as {@link SchemaType#DERIVATION_LIST} and {@link SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public final int getBlock() { return 0; } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link SchemaType#DERIVATION_RESTRICTION} */ public final int getDerivationMethod() { return SchemaType.DERIVATION_RESTRICTION; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public final boolean allowsDerivation(int derivation) { return true; } /** * Set the base type of this type * * @param baseFingerprint the namepool fingerprint of the name of the base type */ public final void setBaseTypeFingerprint(int baseFingerprint) { this.baseFingerprint = baseFingerprint; } /** * Get the fingerprint of the name of this type * * @return the fingerprint. Returns an invented fingerprint for an anonymous type. */ public int getFingerprint() { return fingerprint; } /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. */ public int getNameCode() { return fingerprint; } /** * Get the name of the type as a QName * * @return a StructuredQName containing the name of the type. The conventional prefix "xs" is used * to represent the XML Schema namespace */ /*@NotNull*/ public StructuredQName getQualifiedName() { return new StructuredQName("xs", NamespaceConstant.SCHEMA, StandardNames.getLocalName(fingerprint)); } /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * * @return a lexical QName identifying the type */ public String getDisplayName() { if (fingerprint == StandardNames.XS_NUMERIC) { return "numeric"; } else { return StandardNames.getDisplayName(fingerprint); } } /** * Ask whether the atomic type is a primitive type. The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration; * xs:untypedAtomic; and all supertypes of these (xs:anyAtomicType, xs:numeric, ...) * * @return true if the type is considered primitive under the above rules */ public boolean isPrimitiveType() { return Type.isPrimitiveType(fingerprint); } /** * Ask whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public final boolean isComplexType() { return false; } /** * Ask whether this is an anonymous type * * @return true if this SchemaType is an anonymous type */ public boolean isAnonymousType() { return false; } /** * Ask whether this is a plain type (a type whose instances are always atomic values) * @return true */ public boolean isPlainType() { return true; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ /*@Nullable*/ public final SchemaType getBaseType() { if (baseFingerprint == -1) { return null; } else { return BuiltInType.getSchemaType(baseFingerprint); } } /** * Test whether a given item conforms to this type * * @param item The item to be tested * @param context the XPath dynamic evaluation context * @return true if the item is an instance of this type; false otherwise */ public boolean matches(Item item, /*@NotNull*/ XPathContext context) { return matchesItem(item, false, context.getConfiguration()); } /** * Test whether a given item conforms to this type * * @param item The item to be tested * @param allowURIPromotion true if we regard a URI as effectively a subtype of String * @param config the Saxon configuration (used to locate the type hierarchy cache) * @return true if the item is an instance of this type; false otherwise */ public boolean matchesItem(Item item, boolean allowURIPromotion, /*@NotNull*/ Configuration config) { if (item instanceof AtomicValue) { AtomicValue value = (AtomicValue)item; // Try to match primitive types first if (value.getPrimitiveType() == this) { return true; } AtomicType type = value.getTypeLabel(); if (type.getFingerprint() == getFingerprint()) { // note, with compiled stylesheets one can have two objects representing // the same type, so comparing identity is not safe return true; } final TypeHierarchy th = config.getTypeHierarchy(); boolean ok = th.isSubType(type, this); if (ok) { return true; } if (allowURIPromotion && getFingerprint() == StandardNames.XS_STRING && th.isSubType(type, BuiltInAtomicType.ANY_URI)) { // allow promotion from anyURI to string return true; } } return false; } /** * Get the type from which this item type is derived by restriction. This * is the supertype in the XPath type heirarchy, as distinct from the Schema * base type: this means that the supertype of xs:boolean is xs:anyAtomicType, * whose supertype is item() (rather than xs:anySimpleType). * * @param th the type hierarchy cache, not used in this implementation * @return the supertype, or null if this type is item() */ /*@NotNull*/ public ItemType getSuperType(TypeHierarchy th) { SchemaType base = getBaseType(); if (base instanceof AnySimpleType) { return AnyItemType.getInstance(); } else { return (ItemType)base; } } /** * Get the primitive item type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ /*@NotNull*/ public ItemType getPrimitiveItemType() { if (isPrimitiveType()) { return this; } else { ItemType s = (ItemType)getBaseType(); if (s.isPlainType()) { return s.getPrimitiveItemType(); } else { return this; } } } /** * Get the primitive type corresponding to this item type. For item(), * this is Type.ITEM. For node(), it is Type.NODE. For specific node kinds, * it is the value representing the node kind, for example Type.ELEMENT. * For anyAtomicValue it is Type.ATOMIC_VALUE. For numeric it is Type.NUMBER. * For other atomic types it is the primitive type as defined in XML Schema, * except that INTEGER is considered to be a primitive type. */ public int getPrimitiveType() { return primitiveFingerprint; } /** * Determine whether this type is supported in a basic XSLT 2.0 processor (all types are * allowed in a basic XSLT 3.0 processor) * * @return true if this type is permitted in a basic XSLT 2.0 processor */ public boolean isAllowedInBasicXSLT() { return (isPrimitiveType() && getFingerprint() != StandardNames.XS_NOTATION); } /** * Determine whether this type is supported when using XSD 1.0 * @return true if this type is permitted in XSD 1.0 */ public boolean isAllowedInXSD10() { return (getFingerprint() != StandardNames.XS_DATE_TIME_STAMP); } /** * Produce a representation of this type name for use in error messages. * Where this is a QName, it will use conventional prefixes */ public String toString(NamePool pool) { return getDisplayName(); } /** * Get the item type of the atomic values that will be produced when an item * of this type is atomized */ /*@NotNull*/ public AtomicType getAtomizedItemType() { return this; } /** * Ask whether values of this type are atomizable * @return true unless it is known that these items will be elements with element-only * content, in which case return false */ public boolean isAtomizable() { return true; } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * If this type is a Simpletype that is a built in primitive type then null is returned. * * @return the base type. * @throws IllegalStateException if this type is not valid. */ /*@Nullable*/ public SchemaType getKnownBaseType() { return getBaseType(); } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(/*@NotNull*/ SchemaType other) { return other.getFingerprint() == getFingerprint(); } public String getDescription() { return getDisplayName(); } public String toString() { return getDisplayName(); } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration * @throws SchemaException if the derivation is not allowed */ public void checkTypeDerivationIsOK(/*@NotNull*/ SchemaType type, int block) throws SchemaException { if (type == AnySimpleType.getInstance()) { // OK } else if (isSameType(type)) { // OK } else { SchemaType base = getBaseType(); if (base == null) { throw new SchemaException("Type " + getDescription() + " is not validly derived from type " + type.getDescription()); } try { base.checkTypeDerivationIsOK(type, block); } catch (SchemaException se) { throw new SchemaException("Type " + getDescription() + " is not validly derived from type " + type.getDescription()); } } } /** * Returns true if this SchemaType is a SimpleType * * @return true (always) */ public final boolean isSimpleType() { return true; } /** * Test whether this Simple Type is an atomic type * * @return true, this is an atomic type */ public boolean isAtomicType() { return true; } /** * Ask whether this type is an ID type. This is defined to be any simple type * who typed value may contain atomic values of type xs:ID: that is, it includes types derived * from ID by restriction, list, or union. Note that for a node to be treated * as an ID, its typed value must be a *single* atomic value of type ID; the type of the * node, however, can still allow a list. */ public boolean isIdType() { return fingerprint == StandardNames.XS_ID; } /** * Ask whether this type is an IDREF or IDREFS type. This is defined to be any simple type * who typed value may contain atomic values of type xs:IDREF: that is, it includes types derived * from IDREF or IDREFS by restriction, list, or union */ public boolean isIdRefType() { return fingerprint == StandardNames.XS_IDREF; } /** * Returns true if this type is derived by list, or if it is derived by restriction * from a list type, or if it is a union that contains a list as one of its members * * @return true if this is a list type */ public boolean isListType() { return false; } /** * Return true if this type is a union type (that is, if its variety is union) * * @return true for a union type */ public boolean isUnionType() { return false; } /** * Determine the whitespace normalization required for values of this type * * @return one of PRESERVE, REPLACE, COLLAPSE */ public int getWhitespaceAction() { switch (getFingerprint()) { case StandardNames.XS_STRING: return Whitespace.PRESERVE; case StandardNames.XS_NORMALIZED_STRING: return Whitespace.REPLACE; default: return Whitespace.COLLAPSE; } } /** * Returns the built-in base type this type is derived from. * * @return the first built-in type found when searching up the type hierarchy */ /*@Nullable*/ public SchemaType getBuiltInBaseType() { BuiltInAtomicType base = this; while ((base != null) && (base.getFingerprint() > 1023)) { base = (BuiltInAtomicType)base.getBaseType(); } return base; } /** * Test whether this simple type is namespace-sensitive, that is, whether * it is derived from xs:QName or xs:NOTATION * * @return true if this type is derived from xs:QName or xs:NOTATION */ public boolean isNamespaceSensitive() { BuiltInAtomicType base = this; int fp = base.getFingerprint(); while (fp > 1023) { base = (BuiltInAtomicType)base.getBaseType(); fp = base.getFingerprint(); } return fp == StandardNames.XS_QNAME || fp == StandardNames.XS_NOTATION; } /** * Check whether a given input string is valid according to this SimpleType * * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param rules * @return XPathException if the value is invalid. Note that the exception is returned rather than being thrown. * Returns null if the value is valid. * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ /*@Nullable*/ public ValidationFailure validateContent(/*@NotNull*/ CharSequence value, /*@Nullable*/ NamespaceResolver nsResolver, /*@NotNull*/ ConversionRules rules) { int f = getFingerprint(); if (f == StandardNames.XS_STRING || f == StandardNames.XS_ANY_SIMPLE_TYPE || f == StandardNames.XS_UNTYPED_ATOMIC || f == StandardNames.XS_ANY_ATOMIC_TYPE) { return null; } StringConverter converter = rules.getStringConverter(this); if (isNamespaceSensitive()) { if (nsResolver == null) { throw new UnsupportedOperationException("Cannot validate a QName without a namespace resolver"); } converter.setNamespaceResolver(nsResolver); ConversionResult result = converter.convertString(value); if (result instanceof ValidationFailure) { return (ValidationFailure)result; } if (fingerprint == StandardNames.XS_NOTATION) { NotationValue nv = (NotationValue)result; // This check added in 9.3. The XSLT spec says that this check should not be performed during // validation. However, this appears to be based on an incorrect assumption: see spec bug 6952 if (!rules.isDeclaredNotation(nv.getNamespaceURI(), nv.getLocalName())) { return new ValidationFailure("Notation {" + nv.getNamespaceURI() + "}" + nv.getLocalName() + " is not declared in the schema"); } } return null; } else { return converter.validate(value); } } /** * Get the typed value of a node that is annotated with this schema type * * @param node the node whose typed value is required * @return an iterator over the items making up the typed value of this node. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue} */ /*@NotNull*/ public final SequenceIterator getTypedValue(/*@NotNull*/ NodeInfo node) throws XPathException { try { CharSequence stringValue = node.getStringValueCS(); if (stringValue.length() == 0 && node.isNilled()) { return EmptyIterator.getInstance(); } return getTypedValue(stringValue, new InscopeNamespaceResolver(node), node.getConfiguration().getConversionRules()); } catch (ValidationException err) { throw new XPathException("Internal error: value doesn't match its type annotation. " + err.getMessage()); } } /** * Get the typed value of a node that is annotated with this schema type. * The result of this method will always be consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ public Value atomize(/*@NotNull*/ NodeInfo node) throws XPathException { // Fast path for common cases CharSequence stringValue = node.getStringValueCS(); if (stringValue.length() == 0 && node.isNilled()) { return EmptySequence.getInstance(); } if (fingerprint == StandardNames.XS_STRING) { return StringValue.makeStringValue(stringValue); } else if (fingerprint == StandardNames.XS_UNTYPED_ATOMIC) { return new UntypedAtomicValue(stringValue); } final Configuration config = node.getConfiguration(); StringConverter converter = config.getConversionRules().getStringConverter(this); if (isNamespaceSensitive()) { converter.setNamespaceResolver(new InscopeNamespaceResolver(node)); } return converter.convertString(stringValue).asAtomic(); } /** * Get the typed value corresponding to a given string value, assuming it is * valid against this type (and that the containing node is not nilled) * * @param value the string value * @param resolver a namespace resolver used to resolve any namespace prefixes appearing * in the content of values. Can supply null, in which case any namespace-sensitive content * will be rejected. * @param rules * @return an iterator over the atomic sequence comprising the typed value. The objects * returned by this SequenceIterator will all be of type {@link AtomicValue} * @throws ValidationException This method should be called only if it is known that the value is * valid. If the value is not valid, there is no guarantee that this method will perform validation, * but if it does detect a validity error, then it MAY throw a ValidationException. */ /*@NotNull*/ public SequenceIterator getTypedValue(CharSequence value, NamespaceResolver resolver, /*@NotNull*/ ConversionRules rules) throws ValidationException { // Fast path for common cases if (fingerprint == StandardNames.XS_STRING) { return SingletonIterator.makeIterator(StringValue.makeStringValue(value)); } else if (fingerprint == StandardNames.XS_UNTYPED_ATOMIC) { return SingletonIterator.makeIterator(new UntypedAtomicValue(value)); } StringConverter converter = rules.getStringConverter(this); if (isNamespaceSensitive()) { converter.setNamespaceResolver(resolver); } AtomicValue val = converter.convertString(value).asAtomic(); return SingletonIterator.makeIterator(val); } /** * Two types are equal if they have the same fingerprint. * Note: it is normally safe to use ==, because we always use the static constants, one instance * for each built in atomic type. However, after serialization and deserialization a different instance * can appear. */ public boolean equals(/*@NotNull*/ Object obj) { return obj instanceof BuiltInAtomicType && getFingerprint() == ((BuiltInAtomicType)obj).getFingerprint(); } /** * The fingerprint can be used as a hashcode */ public int hashCode() { return getFingerprint(); } /** * Validate that a primitive atomic value is a valid instance of a type derived from the * same primitive type. * * @param primValue the value in the value space of the primitive type. * @param lexicalValue the value in the lexical space. If null, the string value of primValue * is used. This value is checked against the pattern facet (if any) * @param rules * @return null if the value is valid; otherwise, a ValidationFailure object indicating * the nature of the error. * @throws UnsupportedOperationException in the case of an external object type */ /*@Nullable*/ public ValidationFailure validate(/*@NotNull*/ AtomicValue primValue, CharSequence lexicalValue, ConversionRules rules) { switch (fingerprint) { case StandardNames.XS_NUMERIC: case StandardNames.XS_STRING: case StandardNames.XS_BOOLEAN: case StandardNames.XS_DURATION: case StandardNames.XS_DATE_TIME: case StandardNames.XS_DATE: case StandardNames.XS_TIME: case StandardNames.XS_G_YEAR_MONTH: case StandardNames.XS_G_MONTH: case StandardNames.XS_G_MONTH_DAY: case StandardNames.XS_G_YEAR: case StandardNames.XS_G_DAY: case StandardNames.XS_HEX_BINARY: case StandardNames.XS_BASE64_BINARY: case StandardNames.XS_ANY_URI: case StandardNames.XS_QNAME: case StandardNames.XS_NOTATION: case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_DECIMAL: case StandardNames.XS_FLOAT: case StandardNames.XS_DOUBLE: case StandardNames.XS_INTEGER: return null; case StandardNames.XS_NON_POSITIVE_INTEGER: case StandardNames.XS_NEGATIVE_INTEGER: case StandardNames.XS_LONG: case StandardNames.XS_INT: case StandardNames.XS_SHORT: case StandardNames.XS_BYTE: case StandardNames.XS_NON_NEGATIVE_INTEGER: case StandardNames.XS_POSITIVE_INTEGER: case StandardNames.XS_UNSIGNED_LONG: case StandardNames.XS_UNSIGNED_INT: case StandardNames.XS_UNSIGNED_SHORT: case StandardNames.XS_UNSIGNED_BYTE: return ((IntegerValue)primValue).validateAgainstSubType(this); case StandardNames.XS_YEAR_MONTH_DURATION: case StandardNames.XS_DAY_TIME_DURATION: return null; // treated as primitive case StandardNames.XS_DATE_TIME_STAMP: return (((CalendarValue)primValue).getTimezoneInMinutes() == CalendarValue.NO_TIMEZONE) ? new ValidationFailure("xs:dateTimeStamp value must have a timezone") : null; case StandardNames.XS_NORMALIZED_STRING: case StandardNames.XS_TOKEN: case StandardNames.XS_LANGUAGE: case StandardNames.XS_NAME: case StandardNames.XS_NMTOKEN: case StandardNames.XS_NCNAME: case StandardNames.XS_ID: case StandardNames.XS_IDREF: case StandardNames.XS_ENTITY: StringConverter sc = StringConverter.getStringConverter(this, rules); return sc.validate(primValue.getStringValueCS()); default: throw new IllegalArgumentException(); } } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env the static context * @throws net.sf.saxon.trans.XPathException * if the expression will never deliver a value of the correct type */ public void analyzeContentExpression(/*@NotNull*/ Expression expression, int kind, StaticContext env) throws XPathException { analyzeContentExpression(this, expression, env, kind); } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param simpleType the simple type against which the expression is to be checked * @param expression the expression that delivers the content * @param env the static context of the expression * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @throws net.sf.saxon.trans.XPathException * if the expression will never deliver a value of the correct type */ public static void analyzeContentExpression(SimpleType simpleType, /*@NotNull*/ Expression expression, StaticContext env, int kind) throws XPathException { if (kind == Type.ELEMENT) { expression.checkPermittedContents(simpleType, env, true); // // if we are building the content of an element or document, no atomization will take // // place, and therefore the presence of any element or attribute nodes in the content will // // cause a validity error, since only simple content is allowed // if (Type.isSubType(itemType, NodeKindTest.makeNodeKindTest(Type.ELEMENT))) { // throw new XPathException("The content of an element with a simple type must not include any element nodes"); // } // if (Type.isSubType(itemType, NodeKindTest.makeNodeKindTest(Type.ATTRIBUTE))) { // throw new XPathException("The content of an element with a simple type must not include any attribute nodes"); // } } else if (kind == Type.ATTRIBUTE) { // for attributes, do a check only for text nodes and atomic values: anything else gets atomized if (expression instanceof ValueOf || expression instanceof Literal) { expression.checkPermittedContents(simpleType, env, true); } } } /** * Internal factory method to create a BuiltInAtomicType. There is one instance for each of the * built-in atomic types * * @param fingerprint The name of the type * @param baseType The base type from which this type is derived * @return the newly constructed built in atomic type */ /*@NotNull*/ private static BuiltInAtomicType makeAtomicType(int fingerprint, /*@NotNull*/ SimpleType baseType, boolean ordered) { BuiltInAtomicType t = new BuiltInAtomicType(fingerprint); t.setBaseTypeFingerprint(baseType.getFingerprint()); if (t.isPrimitiveType()) { t.primitiveFingerprint = fingerprint; } else { t.primitiveFingerprint = ((AtomicType)baseType).getPrimitiveType(); } t.ordered = ordered; BuiltInType.register(fingerprint, t); return t; } /** * Apply any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess * @param input the value to be preprocessed * @return the value after preprocessing */ public CharSequence preprocess(CharSequence input) { return input; } /** * Reverse any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess. This is called when converting a value of this type to * a string * @param input the value to be postprocessed: this is the "ordinary" result of converting * the value to a string * @return the value after postprocessing */ public CharSequence postprocess(CharSequence input) throws ValidationException { return input; } /** * Visit all the schema components used in this ItemType definition * @param visitor the visitor class to be called when each component is visited */ public void visitNamedSchemaComponents(SchemaComponentVisitor visitor) throws XPathException { // no action } /** * Get the set of atomic types that are subsumed by this type * * @return for an atomic type, the type itself; for a union type, the set of atomic types * in its transitive membership */ /*@NotNull*/ public Set getPlainMemberTypes() { Set s = new HashSet(1); s.add(this); return s; } public double getDefaultPriority() { int steps = -1; AtomicType base = this; while (base.getFingerprint() != StandardNames.XS_ANY_ATOMIC_TYPE) { if (base.getFingerprint() != StandardNames.XS_NUMERIC) { // don't count "numeric" because it doesn't officially exist steps++; } base = (AtomicType)base.getBaseType(); } return steps; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/package.html0000644000175000017500000000304711671711573023451 0ustar mathieumathieu Package overview for net.sf.saxon.type

This package contains classes that implement the XPath 2.0 type system. It contains that part of the functionality relevant to a non-schema-aware implementation: that is, the overall structure of the type system, together with representations of the built-in types.

The hierarchy of schema types is represented by the interfaces SchemaType, ComplexType, SimpleType, ListType, and AtomicType. (Union types never arise in non-schema-aware processing). There are concrete classes representing built-in types such as AnyType, BuiltInAtomicType, and BuiltInListType: the corresponding classes for user-defined types are in the com.saxonica.schema package.

The class SequenceType ought logically to be in this package but is actually in net.sf.saxon.value. A sequence type contains an ItemType which may be an AtomicType or a NodeTest: NodeTests are found in the package net.sf.saxon.pattern.

The logic for performing type checking is partly in the singleton class Type (which also contains many useful constants), and partly in the class TypeChecker found in package net.sf.saxon.expr.

Michael H. Kay
Saxonica Limited
9 February 2005

saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/Converter.java0000644000175000017500000013353411744241511023776 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.*; import java.math.BigDecimal; /** * A converter implements conversions from one atomic type to another - that is, it implements the casting * rules for a (source type, destination type) pair. *

*

There is potentially one Converter implementation for each pair of (source, target) classes; though in many * cases the same implementation handles a number of such pairs.

*

*

In cases where the conversion rules are fixed (specifically, where they do not depend on differences between * versions of the XSD or QT specifications), the appropriate Converter can be obtained as a static constant, for example * {@link #BOOLEAN_TO_DOUBLE}. In other cases the converter is paramaterized by the {@link ConversionRules} object, * and should be obtained by calling the appropriate factory method on the ConversionRules.

*

*

Where the source type of the conversion is xs:string, the converter will always be a subclass of * {@link StringConverter}

*/ public abstract class Converter { /*@NotNull*/ public final static StringConverter.IdentityConverter IDENTITY_CONVERTER = new StringConverter.IdentityConverter(); /*@NotNull*/ public final static ToUntypedAtomicConverter TO_UNTYPED_ATOMIC = new ToUntypedAtomicConverter(); /*@NotNull*/ public final static ToStringConverter TO_STRING = new ToStringConverter(); /*@NotNull*/ public final static NumericToFloat NUMERIC_TO_FLOAT = new NumericToFloat(); /*@NotNull*/ public final static BooleanToFloat BOOLEAN_TO_FLOAT = new BooleanToFloat(); /*@NotNull*/ public final static NumericToDouble NUMERIC_TO_DOUBLE = new NumericToDouble(); /*@NotNull*/ public final static BooleanToDouble BOOLEAN_TO_DOUBLE = new BooleanToDouble(); /*@NotNull*/ public final static DoubleToDecimal DOUBLE_TO_DECIMAL = new DoubleToDecimal(); /*@NotNull*/ public final static FloatToDecimal FLOAT_TO_DECIMAL = new FloatToDecimal(); /*@NotNull*/ public final static IntegerToDecimal INTEGER_TO_DECIMAL = new IntegerToDecimal(); /*@NotNull*/ public final static NumericToDecimal NUMERIC_TO_DECIMAL = new NumericToDecimal(); /*@NotNull*/ public final static BooleanToDecimal BOOLEAN_TO_DECIMAL = new BooleanToDecimal(); /*@NotNull*/ public final static DoubleToInteger DOUBLE_TO_INTEGER = new DoubleToInteger(); /*@NotNull*/ public final static FloatToInteger FLOAT_TO_INTEGER = new FloatToInteger(); /*@NotNull*/ public final static DecimalToInteger DECIMAL_TO_INTEGER = new DecimalToInteger(); /*@NotNull*/ public final static NumericToInteger NUMERIC_TO_INTEGER = new NumericToInteger(); /*@NotNull*/ public final static BooleanToInteger BOOLEAN_TO_INTEGER = new BooleanToInteger(); /*@NotNull*/ public final static DurationToDayTimeDuration DURATION_TO_DAY_TIME_DURATION = new DurationToDayTimeDuration(); /*@NotNull*/ public final static DurationToYearMonthDuration DURATION_TO_YEAR_MONTH_DURATION = new DurationToYearMonthDuration(); /*@NotNull*/ public final static DateToDateTime DATE_TO_DATE_TIME = new DateToDateTime(); /*@NotNull*/ public final static DateTimeToDate DATE_TIME_TO_DATE = new DateTimeToDate(); /*@NotNull*/ public final static DateTimeToGMonth DATE_TIME_TO_G_MONTH = new DateTimeToGMonth(); /*@NotNull*/ public final static DateTimeToGYearMonth DATE_TIME_TO_G_YEAR_MONTH = new DateTimeToGYearMonth(); /*@NotNull*/ public final static DateTimeToGYear DATE_TIME_TO_G_YEAR = new DateTimeToGYear(); /*@NotNull*/ public final static DateTimeToGMonthDay DATE_TIME_TO_G_MONTH_DAY = new DateTimeToGMonthDay(); /*@NotNull*/ public final static DateTimeToGDay DATE_TIME_TO_G_DAY = new DateTimeToGDay(); /*@NotNull*/ public final static DateTimeToTime DATE_TIME_TO_TIME = new DateTimeToTime(); /*@NotNull*/ public final static NumericToBoolean NUMERIC_TO_BOOLEAN = new NumericToBoolean(); /*@NotNull*/ public final static Base64BinaryToHexBinary BASE64_BINARY_TO_HEX_BINARY = new Base64BinaryToHexBinary(); /*@NotNull*/ public final static HexBinaryToBase64Binary HEX_BINARY_TO_BASE64_BINARY = new HexBinaryToBase64Binary(); /*@NotNull*/ public final static NotationToQName NOTATION_TO_QNAME = new NotationToQName(); /*@NotNull*/ public final static QNameToNotation QNAME_TO_NOTATION = new QNameToNotation(); /** * Convenience method to convert a given value to a given type. Note: it is more efficient * to obtain a converter in advance and to reuse it for multiple conversions * @param value the value to be converted * @param targetType the type to which the value is to be converted * @param rules the conversion rules for the configuration * @return the converted value * @throws ValidationException if conversion fails */ public static AtomicValue convert(/*@NotNull*/ AtomicValue value, /*@NotNull*/ AtomicType targetType, /*@NotNull*/ ConversionRules rules) throws ValidationException { Converter converter = rules.getConverter(value.getPrimitiveType(), targetType); if (converter == null) { ValidationException ve = new ValidationException("Cannot convert value from " + value.getPrimitiveType() + " to " + targetType); ve.setErrorCode("FORG0001"); throw ve; } return converter.convert(value).asAtomic(); } /** * Get a converter that handles conversion from one primitive type to another. *

*

This method is intended for internal use only. The approved way to get a converter is using the * factory method {@link ConversionRules#getConverter(net.sf.saxon.type.AtomicType, net.sf.saxon.type.AtomicType)}}

* * @param sourceType the fingerprint of the source primitive type * @param targetType the fingerprint of the target primitive type * @param rules the conversion rules to be applied * @return the converter if one is available; or null otherwise */ /*@Nullable*/ public static Converter getConverter(/*@NotNull*/ AtomicType sourceType, /*@NotNull*/ AtomicType targetType, ConversionRules rules) { if (sourceType == targetType) { return StringConverter.IdentityConverter.THE_INSTANCE; } int tt = targetType.getFingerprint(); int tp = targetType.getPrimitiveType(); int st = sourceType.getPrimitiveType(); if ((st == StandardNames.XS_STRING || st == StandardNames.XS_UNTYPED_ATOMIC) && (tp == StandardNames.XS_STRING || tp == StandardNames.XS_UNTYPED_ATOMIC)) { return StringConverter.getStringConverter(targetType, rules); } if (!(targetType.isPrimitiveType())) { AtomicType primTarget = (AtomicType) targetType.getPrimitiveItemType(); if (sourceType == primTarget) { return new DownCastingConverter(targetType, rules); } else if (st == StandardNames.XS_STRING || st == StandardNames.XS_UNTYPED_ATOMIC) { return StringConverter.getStringConverter(targetType, rules); } else { Converter stageOne = getConverter(sourceType, primTarget, rules); if (stageOne == null) { return null; } Converter stageTwo = new DownCastingConverter(targetType, rules); return new TwoPhaseConverter(stageOne, stageTwo); } } if (st == tt) { // we are casting between subtypes of the same primitive type. // TODO: (optimization) check whether the targetType is a supertype of the source type, in which case // it's a simple upcast. (Unfortunately, we don't have the TypeHierarchy available) Converter upcast = new UpCastingConverter((AtomicType) sourceType.getPrimitiveItemType()); Converter downcast = new DownCastingConverter(targetType, rules); return new TwoPhaseConverter(upcast, downcast); } switch (tt) { case StandardNames.XS_UNTYPED_ATOMIC: return TO_UNTYPED_ATOMIC; case StandardNames.XS_STRING: return TO_STRING; case StandardNames.XS_FLOAT: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToFloat(rules); case StandardNames.XS_DOUBLE: case StandardNames.XS_DECIMAL: //case StandardNames.XS_PRECISION_DECIMAL: case StandardNames.XS_INTEGER: case StandardNames.XS_NUMERIC: return NUMERIC_TO_FLOAT; case StandardNames.XS_BOOLEAN: return BOOLEAN_TO_FLOAT; default: return null; } case StandardNames.XS_DOUBLE: case StandardNames.XS_NUMERIC: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToDouble(rules); case StandardNames.XS_FLOAT: case StandardNames.XS_DECIMAL: //case StandardNames.XS_PRECISION_DECIMAL: case StandardNames.XS_INTEGER: case StandardNames.XS_NUMERIC: return NUMERIC_TO_DOUBLE; case StandardNames.XS_BOOLEAN: return BOOLEAN_TO_DOUBLE; default: return null; } case StandardNames.XS_DECIMAL: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return StringConverter.STRING_TO_DECIMAL; case StandardNames.XS_FLOAT: return FLOAT_TO_DECIMAL; case StandardNames.XS_DOUBLE: return DOUBLE_TO_DECIMAL; // case StandardNames.XS_PRECISION_DECIMAL: // return PRECISION_DECIMAL_TO_DECIMAL; case StandardNames.XS_INTEGER: return INTEGER_TO_DECIMAL; case StandardNames.XS_NUMERIC: return NUMERIC_TO_DECIMAL; case StandardNames.XS_BOOLEAN: return BOOLEAN_TO_DECIMAL; default: return null; } case StandardNames.XS_INTEGER: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return StringConverter.STRING_TO_INTEGER; case StandardNames.XS_FLOAT: return FLOAT_TO_INTEGER; case StandardNames.XS_DOUBLE: return DOUBLE_TO_INTEGER; case StandardNames.XS_DECIMAL: //case StandardNames.XS_PRECISION_DECIMAL: return DECIMAL_TO_INTEGER; case StandardNames.XS_NUMERIC: return NUMERIC_TO_INTEGER; case StandardNames.XS_BOOLEAN: return BOOLEAN_TO_INTEGER; default: return null; } case StandardNames.XS_DURATION: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return StringConverter.STRING_TO_DURATION; case StandardNames.XS_DAY_TIME_DURATION: case StandardNames.XS_YEAR_MONTH_DURATION: return new UpCastingConverter(BuiltInAtomicType.DURATION); default: return null; } case StandardNames.XS_YEAR_MONTH_DURATION: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return StringConverter.STRING_TO_YEAR_MONTH_DURATION; case StandardNames.XS_DURATION: case StandardNames.XS_DAY_TIME_DURATION: return DURATION_TO_YEAR_MONTH_DURATION; default: return null; } case StandardNames.XS_DAY_TIME_DURATION: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return StringConverter.STRING_TO_DAY_TIME_DURATION; case StandardNames.XS_DURATION: case StandardNames.XS_YEAR_MONTH_DURATION: return DURATION_TO_DAY_TIME_DURATION; default: return null; } case StandardNames.XS_DATE_TIME: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToDateTime(rules); case StandardNames.XS_DATE: return DATE_TO_DATE_TIME; default: return null; } case StandardNames.XS_TIME: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return StringConverter.STRING_TO_TIME; case StandardNames.XS_DATE_TIME: return DATE_TIME_TO_TIME; default: return null; } case StandardNames.XS_DATE: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToDate(rules); case StandardNames.XS_DATE_TIME: return DATE_TIME_TO_DATE; default: return null; } case StandardNames.XS_G_YEAR_MONTH: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToGYearMonth(rules); case StandardNames.XS_DATE: return TwoPhaseConverter.makeTwoPhaseConverter( BuiltInAtomicType.DATE, BuiltInAtomicType.DATE_TIME, BuiltInAtomicType.G_YEAR_MONTH, rules); case StandardNames.XS_DATE_TIME: return DATE_TIME_TO_G_YEAR_MONTH; default: return null; } case StandardNames.XS_G_YEAR: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToGYear(rules); case StandardNames.XS_DATE: return TwoPhaseConverter.makeTwoPhaseConverter(BuiltInAtomicType.DATE, BuiltInAtomicType.DATE_TIME, BuiltInAtomicType.G_YEAR, rules); case StandardNames.XS_DATE_TIME: return DATE_TIME_TO_G_YEAR; default: return null; } case StandardNames.XS_G_MONTH_DAY: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToGMonthDay(rules); case StandardNames.XS_DATE: return TwoPhaseConverter.makeTwoPhaseConverter(BuiltInAtomicType.DATE, BuiltInAtomicType.DATE_TIME, BuiltInAtomicType.G_MONTH_DAY, rules); case StandardNames.XS_DATE_TIME: return DATE_TIME_TO_G_MONTH_DAY; default: return null; } case StandardNames.XS_G_DAY: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToGDayConverter(rules); case StandardNames.XS_DATE: return TwoPhaseConverter.makeTwoPhaseConverter(BuiltInAtomicType.DATE, BuiltInAtomicType.DATE_TIME, BuiltInAtomicType.G_DAY, rules); case StandardNames.XS_DATE_TIME: return DATE_TIME_TO_G_DAY; default: return null; } case StandardNames.XS_G_MONTH: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToGMonth(rules); case StandardNames.XS_DATE: return TwoPhaseConverter.makeTwoPhaseConverter(BuiltInAtomicType.DATE, BuiltInAtomicType.DATE_TIME, BuiltInAtomicType.G_MONTH, rules); case StandardNames.XS_DATE_TIME: return DATE_TIME_TO_G_MONTH; default: return null; } case StandardNames.XS_BOOLEAN: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return StringConverter.STRING_TO_BOOLEAN; case StandardNames.XS_FLOAT: case StandardNames.XS_DOUBLE: case StandardNames.XS_DECIMAL: // case StandardNames.XS_PRECISION_DECIMAL: case StandardNames.XS_INTEGER: case StandardNames.XS_NUMERIC: return NUMERIC_TO_BOOLEAN; default: return null; } case StandardNames.XS_BASE64_BINARY: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return StringConverter.STRING_TO_BASE64_BINARY; case StandardNames.XS_HEX_BINARY: return HEX_BINARY_TO_BASE64_BINARY; default: return null; } case StandardNames.XS_HEX_BINARY: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return StringConverter.STRING_TO_HEX_BINARY; case StandardNames.XS_BASE64_BINARY: return BASE64_BINARY_TO_HEX_BINARY; default: return null; } case StandardNames.XS_ANY_URI: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToAnyURI(rules); default: return null; } case StandardNames.XS_QNAME: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToQName(rules); case StandardNames.XS_NOTATION: return NOTATION_TO_QNAME; default: return null; } case StandardNames.XS_NOTATION: switch (st) { case StandardNames.XS_UNTYPED_ATOMIC: case StandardNames.XS_STRING: return new StringConverter.StringToNotation(rules); case StandardNames.XS_QNAME: return QNAME_TO_NOTATION; default: return null; } case StandardNames.XS_ANY_ATOMIC_TYPE: return IDENTITY_CONVERTER; default: throw new IllegalArgumentException("Unknown primitive type " + tt); } } // All converters can hold a reference to the conversion rules, though many don't private ConversionRules conversionRules; // Protected constructor for a Converter protected Converter() { } /** * Construct a converter with a given set of conversion rules. For use in constructing subclasses * * @param rules the conversion rules for the configuration */ protected Converter(ConversionRules rules) { setConversionRules(rules); } /** * Convert an atomic value from the source type to the target type * * @param input the atomic value to be converted, which the caller guarantees to be of the appropriate * type for the converter * @return the result of the conversion, as an {@link AtomicValue}, if conversion succeeds, or a {@link ValidationFailure} * object describing the reasons for failure if conversion is not possible. Note that the ValidationFailure * object is not (and does not contain) an exception, because it does not necessarily result in an error being * thrown, and creating exceptions on non-failure paths is expensive. */ /*@NotNull*/ public abstract ConversionResult convert(/*@NotNull*/ AtomicValue input); /** * Set the conversion rules to be used by this Converter * * @param rules the conversion rules */ public final void setConversionRules(ConversionRules rules) { this.conversionRules = rules; } /** * Get the conversion rules to be used by this Converter * * @return the conversion rules */ public final ConversionRules getConversionRules() { return conversionRules; } /** * Ask if this converter implements a conversion that requires XPath 3.0 (or XQuery 3.0 etc) * to be enabled * * @return true if XPath 3.0 support is required */ public boolean isXPath30Conversion() { return false; } /** * Ask if this converter will always succeed * * @return true if this Converter will never return a ValidationFailure */ public boolean isAlwaysSuccessful() { return false; } /** * Provide a namespace resolver, needed for conversion to namespace-sensitive types such as QName and NOTATION. * The resolver is ignored if the target type is not namespace-sensitive * * @param resolver the namespace resolver to be used */ public void setNamespaceResolver(NamespaceResolver resolver) { // no action } /** * Get the namespace resolver if one has been supplied * * @return the namespace resolver, or null if none has been supplied */ /*@Nullable*/ public NamespaceResolver getNamespaceResolver() { return null; } /** * Converter that does nothing except change the type annotation of the value. The caller * is responsible for ensuring that this type annotation is legimite, that is, that the value * is in the value space of this type */ public static class UpCastingConverter extends Converter { private AtomicType newTypeAnnotation; public UpCastingConverter(AtomicType annotation) { this.newTypeAnnotation = annotation; } /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return input.copyAsSubType(newTypeAnnotation); } public boolean isAlwaysSuccessful() { return true; } } /** * Converter that does nothing except change the type annotation of the value. The caller * is responsible for ensuring that this type annotation is legimite, that is, that the value * is in the value space of this type */ public static class DownCastingConverter extends Converter { private AtomicType newType; public DownCastingConverter(AtomicType annotation, ConversionRules rules) { this.newType = annotation; setConversionRules(rules); } public AtomicType getTargetType() { return newType; } /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return convert(input, input.getStringValueCS()); } public ConversionResult convert(/*@NotNull*/ AtomicValue input, CharSequence lexicalForm) { ValidationFailure f = newType.validate(input, lexicalForm, getConversionRules()); if (f == null) { // success return input.copyAsSubType(newType); } else { // validation failed return f; } } } /** * Converter that operates in two phases, via an intermediate type */ public static class TwoPhaseConverter extends StringConverter { private Converter phaseOne; private Converter phaseTwo; public TwoPhaseConverter(Converter phaseOne, Converter phaseTwo) { this.phaseOne = phaseOne; this.phaseTwo = phaseTwo; } /*@Nullable*/ public static TwoPhaseConverter makeTwoPhaseConverter(/*@NotNull*/ AtomicType inputType, /*@NotNull*/ AtomicType viaType, /*@NotNull*/ AtomicType outputType, ConversionRules rules) { return new TwoPhaseConverter( getConverter(inputType, viaType, rules), getConverter(viaType, outputType, rules)); } @Override public void setNamespaceResolver(NamespaceResolver resolver) { phaseOne.setNamespaceResolver(resolver); phaseTwo.setNamespaceResolver(resolver); } /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { ConversionResult temp = phaseOne.convert(input); if (temp instanceof ValidationFailure) { return temp; } return phaseTwo.convert((AtomicValue) temp); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { ConversionResult temp = ((StringConverter) phaseOne).convertString(input); if (temp instanceof ValidationFailure) { return temp; } return ((DownCastingConverter) phaseTwo).convert((AtomicValue) temp, input); } } /** * Converts any value to untyped atomic */ public static class ToUntypedAtomicConverter extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new UntypedAtomicValue(input.getStringValueCS()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts any value to a string */ public static class ToStringConverter extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new StringValue(input.getStringValueCS()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts any numeric value to xs:float */ public static class NumericToFloat extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new FloatValue(((NumericValue) input).getFloatValue()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a boolean to an xs:float */ public static class BooleanToFloat extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new FloatValue(((BooleanValue) input).getBooleanValue() ? 1.0f : 0.0f); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts any numeric value to a double. */ public static class NumericToDouble extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { if (input instanceof DoubleValue) { return input; } else { return new DoubleValue(((NumericValue) input).getDoubleValue()); } } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a boolean to a double */ public static class BooleanToDouble extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new DoubleValue(((BooleanValue) input).getBooleanValue() ? 1.0e0 : 0.0e0); } public boolean isAlwaysSuccessful() { return true; } } /** * Convers a double to a decimal */ public static class DoubleToDecimal extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { try { return new DecimalValue(((DoubleValue) input).getDoubleValue()); } catch (ValidationException e) { return new ValidationFailure(e); } } } /** * Converts a float to a decimal */ public static class FloatToDecimal extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { try { return new DecimalValue(((FloatValue) input).getFloatValue()); } catch (ValidationException e) { return new ValidationFailure(e); } } } /** * Converts an integer to a decimal */ public static class IntegerToDecimal extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { if (input instanceof Int64Value) { return new DecimalValue(((Int64Value) input).longValue()); } else { return new DecimalValue(((BigIntegerValue) input).asDecimal()); } } public boolean isAlwaysSuccessful() { return true; } } /** * Converts any numeric value to a decimal */ public static class NumericToDecimal extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { try { BigDecimal decimal = ((NumericValue) input).getDecimalValue(); return new DecimalValue(decimal); } catch (XPathException e) { return new ValidationFailure(e); } } } /** * Converts a boolean to a decimal */ public static class BooleanToDecimal extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return ((BooleanValue) input).getBooleanValue() ? DecimalValue.ONE : DecimalValue.ZERO; } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a double to an integer */ public static class DoubleToInteger extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return IntegerValue.makeIntegerValue((DoubleValue) input); } } /** * Converts a float to an integer */ public static class FloatToInteger extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return IntegerValue.makeIntegerValue(new DoubleValue(((FloatValue) input).getDoubleValue())); } } /** * Converts a decimal to an integer. Because an xs:integer is an xs:decimal, * this must also be prepared to accept an xs:integer */ public static class DecimalToInteger extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { if (input instanceof IntegerValue) { return input; } return BigIntegerValue.makeIntegerValue(((DecimalValue) input).getDecimalValue().toBigInteger()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts any numeric value to an integer. */ public static class NumericToInteger extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { try { if (input instanceof IntegerValue) { return input; } else if (input instanceof DoubleValue) { return IntegerValue.makeIntegerValue((DoubleValue) input); } else if (input instanceof FloatValue) { return IntegerValue.makeIntegerValue(new DoubleValue(((FloatValue) input).getDoubleValue())); } else { return BigIntegerValue.makeIntegerValue(((NumericValue) input).getDecimalValue().toBigInteger()); } } catch (XPathException e) { return new ValidationFailure(e); } } } /** * Converts a boolean to an integer */ public static class BooleanToInteger extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return ((BooleanValue) input).getBooleanValue() ? Int64Value.PLUS_ONE : Int64Value.ZERO; } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a duration to a dayTimeDuration */ public static class DurationToDayTimeDuration extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { DurationValue d = (DurationValue) input; return new DayTimeDurationValue(d.signum(), d.getDays(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMicroseconds()); } } /** * Converts a duration to a yearMonthDuration */ public static class DurationToYearMonthDuration extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { DurationValue d = (DurationValue) input; return YearMonthDurationValue.fromMonths(d.getTotalMonths()); } } /** * Converts a date to a dateTime */ public static class DateToDateTime extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return ((DateValue) input).toDateTime(); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a dateTime to a date */ public static class DateTimeToDate extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { DateTimeValue dt = (DateTimeValue) input; return new DateValue(dt.getYear(), dt.getMonth(), dt.getDay(), dt.getTimezoneInMinutes(), dt.isXsd10Rules()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a dateTime to a gMonth */ public static class DateTimeToGMonth extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { DateTimeValue dt = (DateTimeValue) input; return new GMonthValue(dt.getMonth(), dt.getTimezoneInMinutes()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a dateTime to a gYearMonth */ public static class DateTimeToGYearMonth extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { DateTimeValue dt = (DateTimeValue) input; return new GYearMonthValue(dt.getYear(), dt.getMonth(), dt.getTimezoneInMinutes(), dt.isXsd10Rules()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a dateTime to a gYear */ public static class DateTimeToGYear extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { DateTimeValue dt = (DateTimeValue) input; return new GYearValue(dt.getYear(), dt.getTimezoneInMinutes(), dt.isXsd10Rules()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a dateTime to a gMonthDay */ public static class DateTimeToGMonthDay extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { DateTimeValue dt = (DateTimeValue) input; return new GMonthDayValue(dt.getMonth(), dt.getDay(), dt.getTimezoneInMinutes()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a dateTime to a gDay */ public static class DateTimeToGDay extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { DateTimeValue dt = (DateTimeValue) input; return new GDayValue(dt.getDay(), dt.getTimezoneInMinutes()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a dateTime to a time */ public static class DateTimeToTime extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { DateTimeValue dt = (DateTimeValue) input; return new TimeValue(dt.getHour(), dt.getMinute(), dt.getSecond(), dt.getMicrosecond(), dt.getTimezoneInMinutes()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts a numeric value to a boolean */ public static class NumericToBoolean extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { try { return BooleanValue.get(input.effectiveBooleanValue()); } catch (XPathException err) { throw new AssertionError(err); } } public boolean isAlwaysSuccessful() { return true; } } /** * Converts base64 to hexBinary */ public static class Base64BinaryToHexBinary extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new HexBinaryValue(((Base64BinaryValue) input).getBinaryValue()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts string to base64 */ public static class StringToBase64BinaryConverter extends StringConverter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return convertString(input.getStringValueCS()); } /*@NotNull*/ public ConversionResult convertString(/*@NotNull*/ CharSequence input) { try { return new Base64BinaryValue(input); } catch (XPathException e) { return new ValidationFailure(e); } } } /** * Converts hexBinary to base64Binary */ public static class HexBinaryToBase64Binary extends Converter { /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new Base64BinaryValue(((HexBinaryValue) input).getBinaryValue()); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts Notation to QName */ public static class NotationToQName extends Converter { @Override public boolean isXPath30Conversion() { return true; } /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new QNameValue(((NotationValue) input).getStructuredQName(), BuiltInAtomicType.QNAME); } public boolean isAlwaysSuccessful() { return true; } } /** * Converts QName to Notation */ public static class QNameToNotation extends Converter { @Override public boolean isXPath30Conversion() { return true; } /*@NotNull*/ public ConversionResult convert(/*@NotNull*/ AtomicValue input) { return new NotationValue(((QNameValue) input).getStructuredQName(), BuiltInAtomicType.NOTATION); } } /** * Converter that implements the promotion rules to a required type of xs:double */ public static class PromoterToDouble extends Converter { /*@Nullable*/ private StringConverter stringToDouble = null; /*@NotNull*/ @Override public ConversionResult convert(/*@NotNull*/ AtomicValue input) { if (input instanceof DoubleValue) { return input; } else if (input instanceof NumericValue) { return new DoubleValue(((NumericValue) input).getDoubleValue()); } else if (input instanceof UntypedAtomicValue) { if (stringToDouble == null) { stringToDouble = StringConverter.getStringConverter(BuiltInAtomicType.DOUBLE, getConversionRules()); } return stringToDouble.convert(input); } else { ValidationFailure err = new ValidationFailure( "Cannot promote non-numeric value to xs:double"); err.setErrorCode("XPTY0004"); return err; } } } /** * Converter that implements the promotion rules to a required type of xs:float */ public static class PromoterToFloat extends Converter { /*@Nullable*/ private StringConverter stringToFloat = null; /*@NotNull*/ @Override public ConversionResult convert(/*@NotNull*/ AtomicValue input) { if (input instanceof FloatValue) { return input; } else if (input instanceof DoubleValue) { ValidationFailure err = new ValidationFailure( "Cannot promote from xs:double to xs:float"); err.setErrorCode("XPTY0004"); return err; } else if (input instanceof NumericValue) { return new FloatValue((float) ((NumericValue) input).getDoubleValue()); } else if (input instanceof UntypedAtomicValue) { if (stringToFloat == null) { stringToFloat = StringConverter.getStringConverter(BuiltInAtomicType.FLOAT, getConversionRules()); } return stringToFloat.convert(input); } else { ValidationFailure err = new ValidationFailure( "Cannot promote non-numeric value to xs:double"); err.setErrorCode("XPTY0004"); return err; } } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/TypeHierarchy.java0000644000175000017500000004726211754672153024624 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.Configuration; import net.sf.saxon.expr.sort.IntHashSet; import net.sf.saxon.expr.sort.IntIterator; import net.sf.saxon.expr.sort.IntSet; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.StandardNames; import net.sf.saxon.pattern.*; import java.io.Serializable; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * This class exists to provide answers to questions about the type hierarchy. Because * such questions are potentially expensive, it caches the answers. There is one instance of * this class for a Configuration. */ public class TypeHierarchy implements Serializable { private Map map; private Configuration config; /** * Constant denoting relationship between two types: A is the same type as B */ public static final int SAME_TYPE = 0; /** * Constant denoting relationship between two types: A subsumes B */ public static final int SUBSUMES = 1; /** * Constant denoting relationship between two types: A is subsumed by B */ public static final int SUBSUMED_BY = 2; /** * Constant denoting relationship between two types: A overlaps B */ public static final int OVERLAPS = 3; /** * Constant denoting relationship between two types: A is disjoint from B */ public static final int DISJOINT = 4; //private String[] relnames = {"SAME", "SUBSUMES", "SUBSUMED_BY", "OVERLAPS", "DISJOINT"}; /** * Create the type hierarchy cache for a configuration * @param config the configuration */ public TypeHierarchy(Configuration config){ this.config = config; map = new ConcurrentHashMap(); } /** * Get the Saxon configuration to which this type hierarchy belongs * @return the configuration */ public Configuration getConfiguration() { return config; } /** * Determine whether type A is type B or one of its subtypes, recursively. * "Subtype" here means a type that is subsumed, that is, a type whose instances * are a subset of the instances of the other type. * * @param subtype identifies the first type * @param supertype identifies the second type * @return true if the first type is the second type or is subsumed by the second type */ public boolean isSubType(ItemType subtype, /*@NotNull*/ ItemType supertype) { int relation = relationship(subtype, supertype); return (relation==SAME_TYPE || relation==SUBSUMED_BY); } /** * Determine the relationship of one item type to another. * @param t1 the first item type * @param t2 the second item type * @return {@link #SAME_TYPE} if the types are the same; {@link #SUBSUMES} if the first * type subsumes the second (that is, all instances of the second type are also instances * of the first); {@link #SUBSUMED_BY} if the second type subsumes the first; * {@link #OVERLAPS} if the two types overlap (have a non-empty intersection, but neither * subsumes the other); {@link #DISJOINT} if the two types are disjoint (have an empty intersection) */ public int relationship(/*@Nullable*/ ItemType t1, /*@NotNull*/ ItemType t2) { if (t1 == null) { throw new NullPointerException(); } if (t1.equals(t2)) { return SAME_TYPE; } ItemTypePair pair = new ItemTypePair(t1, t2); Integer result = map.get(pair); if (result == null) { result = computeRelationship(t1, t2); map.put(pair, result); } return result; } /** * Determine the relationship of one item type to another. * @param t1 the first item type * @param t2 the second item type * @return {@link #SAME_TYPE} if the types are the same; {@link #SUBSUMES} if the first * type subsumes the second (that is, all instances of the second type are also instances * of the first); {@link #SUBSUMED_BY} if the second type subsumes the first; * {@link #OVERLAPS} if the two types overlap (have a non-empty intersection, but neither * subsumes the other); {@link #DISJOINT} if the two types are disjoint (have an empty intersection) */ private int computeRelationship(/*@NotNull*/ ItemType t1, /*@NotNull*/ ItemType t2) { if (t1 == t2) { return SAME_TYPE; } if (t1 instanceof AnyItemType) { if (t2 instanceof AnyItemType) { return SAME_TYPE; } else { return SUBSUMES; } } else if (t2 instanceof AnyItemType) { return SUBSUMED_BY; } else if (t1.isPlainType()) { if (t2 instanceof NodeTest || t2 instanceof FunctionItemType) { return DISJOINT; } else if (t1 instanceof ExternalObjectType) { if (t2 instanceof ExternalObjectType) { return ((ExternalObjectType)t1).getRelationship((ExternalObjectType)t2); } else if (((AtomicType)t2).getFingerprint() == StandardNames.XS_ANY_ATOMIC_TYPE) { return SUBSUMED_BY; } else { return DISJOINT; } } else if (t2 instanceof ExternalObjectType) { if (((AtomicType)t1).getFingerprint() == StandardNames.XS_ANY_ATOMIC_TYPE) { return SUBSUMES; } else { return DISJOINT; } } else if (t1 instanceof AtomicType && t2 instanceof AtomicType) { if (((AtomicType)t1).getFingerprint() == ((AtomicType)t2).getFingerprint()) { return SAME_TYPE; } ItemType t = t2; while (t.isPlainType()) { if (((AtomicType)t1).getFingerprint() == ((AtomicType)t).getFingerprint()) { return SUBSUMES; } t = t.getSuperType(this); } t = t1; while (t.isPlainType()) { if (((AtomicType)t).getFingerprint() == ((AtomicType)t2).getFingerprint()) { return SUBSUMED_BY; } t = t.getSuperType(this); } return DISJOINT; } else if (t1.isPlainType() && !(t1.isAtomicType()) && t2 instanceof PlainType) { // relationship(union, atomic) or relationship(union, union) boolean overlap = false; Set s1 = ((PlainType)t1).getPlainMemberTypes(); for (PlainType a1 : s1) { if (a1.equals(t2)) { return SUBSUMES; } int r = relationship(a1, t2); if (r == SUBSUMES || r == SAME_TYPE) { return SUBSUMES; } if (r != DISJOINT) { overlap = true; } } return (overlap ? OVERLAPS : DISJOINT); } else if (t1 instanceof AtomicType) { // relationship (atomic, union) int r = relationship(t2, t1); return inverseRelationship(r); } else { // all options exhausted throw new IllegalStateException(); } } else if (t1 instanceof NodeTest) { if (t2.isPlainType() || (t2 instanceof FunctionItemType)) { return DISJOINT; } else { // both types are NodeTests if (t1 instanceof AnyNodeTest) { if (t2 instanceof AnyNodeTest) { return SAME_TYPE; } else { return SUBSUMES; } } else if (t2 instanceof AnyNodeTest) { return SUBSUMED_BY; } else if (t1 instanceof EmptySequenceTest) { return DISJOINT; } else if (t2 instanceof EmptySequenceTest) { return DISJOINT; } else { // first find the relationship between the node kinds allowed int nodeKindRelationship; int m1 = ((NodeTest)t1).getNodeKindMask(); int m2 = ((NodeTest)t2).getNodeKindMask(); if ((m1 & m2) == 0) { return DISJOINT; } else if (m1 == m2) { nodeKindRelationship = SAME_TYPE; } else if ((m1 & m2) == m1) { nodeKindRelationship = SUBSUMED_BY; } else if ((m1 & m2) == m2) { nodeKindRelationship = SUBSUMES; } else { nodeKindRelationship = OVERLAPS; } // now find the relationship between the node names allowed. Note that although // NamespaceTest and LocalNameTest are NodeTests, they do not occur in SequenceTypes, // so we don't need to consider them. int nodeNameRelationship; IntSet n1 = ((NodeTest)t1).getRequiredNodeNames(); // null means all names allowed IntSet n2 = ((NodeTest)t2).getRequiredNodeNames(); // null means all names allowed if (n1 == null) { if (n2 == null) { nodeNameRelationship = SAME_TYPE; } else { nodeNameRelationship = SUBSUMES; } } else if (n2 == null) { nodeNameRelationship = SUBSUMED_BY; } else if (n1.containsAll(n2)) { if (n1.size() == n2.size()) { nodeNameRelationship = SAME_TYPE; } else { nodeNameRelationship = SUBSUMES; } } else if (n2.containsAll(n1)) { nodeNameRelationship = SUBSUMED_BY; } else if (IntHashSet.containsSome(n1, n2)) { nodeNameRelationship = OVERLAPS; } else { nodeNameRelationship = DISJOINT; } // now find the relationship between the content types allowed int contentRelationship; if (t1 instanceof DocumentNodeTest) { if (t2 instanceof DocumentNodeTest) { contentRelationship = relationship(((DocumentNodeTest)t1).getElementTest(), ((DocumentNodeTest)t2).getElementTest()); } else { contentRelationship = SUBSUMED_BY; } } else if (t2 instanceof DocumentNodeTest) { contentRelationship = SUBSUMES; } else { // This is changed as a result of spec bug 10065. If t2 is schema-element(e2), it is // no longer sufficient to check the content type of t1 against the declared type of e2 // (which might be xs:anyType, as in test schvalid010). Instead it must be checked against // the declared type of the element declaration corresponding to the actual name N of // the element being tested. SchemaType s1 = ((NodeTest)t1).getContentType(); SchemaType s2 = ((NodeTest)t2).getContentType(); if (t1 instanceof SchemaNodeTest && n2 != null && n2.size() == 1) { IntIterator ii2 = n2.iterator(); int name2 = (ii2.hasNext() ? ii2.next() : -1); SchemaDeclaration decl2 = config.getElementDeclaration(name2); if (decl2 != null) { s1 = decl2.getType(); } } if (t2 instanceof SchemaNodeTest && n1 != null && n1.size() == 1) { IntIterator ii1 = n1.iterator(); int name1 = (ii1.hasNext() ? ii1.next() : -1); SchemaDeclaration decl1 = config.getElementDeclaration(name1); if (decl1 != null) { s2 = decl1.getType(); } } contentRelationship = schemaTypeRelationship(s1, s2); } // now analyse the three different relationsships if (nodeKindRelationship == SAME_TYPE && nodeNameRelationship == SAME_TYPE && contentRelationship == SAME_TYPE) { return SAME_TYPE; } else if ((nodeKindRelationship == SAME_TYPE || nodeKindRelationship == SUBSUMES) && (nodeNameRelationship == SAME_TYPE || nodeNameRelationship == SUBSUMES) && (contentRelationship == SAME_TYPE || contentRelationship == SUBSUMES)) { return SUBSUMES; } else if ((nodeKindRelationship == SAME_TYPE || nodeKindRelationship == SUBSUMED_BY) && (nodeNameRelationship == SAME_TYPE || nodeNameRelationship == SUBSUMED_BY) && (contentRelationship == SAME_TYPE || contentRelationship == SUBSUMED_BY)) { return SUBSUMED_BY; } else if (nodeKindRelationship == DISJOINT || nodeNameRelationship == DISJOINT || contentRelationship == DISJOINT) { return DISJOINT; } else { return OVERLAPS; } } } } else { // t1 is a FunctionItemType if (t2 instanceof FunctionItemType) { return ((FunctionItemType)t1).relationship((FunctionItemType)t2, this); } else { return DISJOINT; } } } private int inverseRelationship(int relation) { switch (relation) { case SAME_TYPE: return SAME_TYPE; case SUBSUMES: return SUBSUMED_BY; case SUBSUMED_BY: return SUBSUMES; case OVERLAPS: return OVERLAPS; case DISJOINT: return DISJOINT; default: throw new IllegalArgumentException(); } } /** * Test whether a type annotation code represents the type xs:ID or one of its subtypes * @param typeCode the type annotation to be tested * @return true if the type annotation represents an xs:ID */ public boolean isIdCode(int typeCode) { typeCode &= NamePool.FP_MASK; if (typeCode == StandardNames.XS_ID) { return true; } else if (typeCode < 1024) { // No other built-in type is an ID return false; } else { SchemaType type = config.getSchemaType(typeCode); if (type == null) { return false; // this shouldn't happen, but there's no need to crash right here } return type.isIdType(); } } /** * Test whether a type annotation code represents the type xs:IDREF, xs:IDREFS or one of their subtypes * @param typeCode the type annotation to be tested * @return true if the type annotation represents an xs:IDREF or xs:IDREFS or a subtype thereof */ public boolean isIdrefsCode(int typeCode) { typeCode &= NamePool.FP_MASK; if (typeCode == StandardNames.XS_IDREF || typeCode == StandardNames.XS_IDREFS) { return true; } else if (typeCode < 1024) { // No other built-in type is an IDREF or IDREFS return false; } else { SchemaType type = config.getSchemaType(typeCode); if (type == null) { // shouldn't happen, but we don't need to crash right now return false; } return type.isIdRefType(); } } /** * Get the relationship of two schema types to each other * @param s1 the first type * @param s2 the second type * @return the relationship of the two types, as one of the constants * {@link net.sf.saxon.type.TypeHierarchy#SAME_TYPE}, {@link net.sf.saxon.type.TypeHierarchy#SUBSUMES}, * {@link net.sf.saxon.type.TypeHierarchy#SUBSUMED_BY}, {@link net.sf.saxon.type.TypeHierarchy#DISJOINT} */ public static int schemaTypeRelationship(/*@NotNull*/ SchemaType s1, SchemaType s2) { if (s1.isSameType(s2)) { return SAME_TYPE; } if (s1 instanceof AnyType) { return SUBSUMES; } if (s2 instanceof AnyType) { return SUBSUMED_BY; } SchemaType t1 = s1; while (true) { t1 = t1.getBaseType(); if (t1 == null) { break; } if (t1.isSameType(s2)) { return SUBSUMED_BY; } } SchemaType t2 = s2; while (true) { t2 = t2.getBaseType(); if (t2 == null) { break; } if (t2.isSameType(s1)) { return SUBSUMES; } } return DISJOINT; } private static class ItemTypePair implements Serializable { ItemType s; ItemType t; public ItemTypePair(ItemType s, ItemType t) { this.s = s; this.t = t; } /** * Returns a hash code value for the object. * @return a hash code value for this object. * @see Object#equals(Object) * @see java.util.Hashtable */ public int hashCode() { return s.hashCode() ^ t.hashCode(); } /** * Indicates whether some other object is "equal to" this one. */ public boolean equals(Object obj) { if (obj instanceof ItemTypePair) { final ItemTypePair pair = (ItemTypePair)obj; return s.equals(pair.s) && t.equals(pair.t); } else { return false; } } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/SchemaComponent.java0000644000175000017500000000547111671711573025121 0ustar mathieumathieupackage net.sf.saxon.type; import java.io.Serializable; /** * This is a marker interface that represents any "schema component" as defined in the XML Schema * specification. This may be a user-defined schema component or a built-in schema component. Since * all built-in schema components are types, every SchemaComponent in practice is either a * {@link com.saxonica.schema.UserSchemaComponent} or a {@link SchemaType} or both. */ public interface SchemaComponent extends Serializable { /** * Get the validation status of this component. * @return one of the values {@link #UNVALIDATED}, {@link #VALIDATING}, * {@link #VALIDATED}, {@link #INVALID}, {@link #INCOMPLETE} */ public int getValidationStatus(); /** * Validation status: not yet validated */ public static final int UNVALIDATED = 0; /** * Validation status: fixed up (all references to other components have been resolved) */ public static final int FIXED_UP = 1; /** * Validation status: currently being validated */ public static final int VALIDATING = 2; /** * Validation status: successfully validated */ public static final int VALIDATED = 3; /** * Validation status: validation attempted and failed with fatal errors */ public static final int INVALID = 4; /** * Validation status: validation attempted, component contains references to * other components that are not (yet) available */ public static final int INCOMPLETE = 5; /** * Get the redefinition level. This is zero for a component that has not been redefined; * for a redefinition of a level-0 component, it is 1; for a redefinition of a level-N * component, it is N+1. This concept is used to support the notion of "pervasive" redefinition: * if a component is redefined at several levels, the top level wins, but it is an error to have * two versions of the component at the same redefinition level. * @return the redefinition level */ public int getRedefinitionLevel(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/AtomicType.java0000644000175000017500000000653311671711573024114 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.value.AtomicValue; /** * Interface for atomic types (these are either built-in atomic types * or user-defined atomic types). An AtomicType is both an ItemType (a possible type * for items in a sequence) and a SchemaType (a possible type for validating and * annotating nodes). */ public interface AtomicType extends SimpleType, PlainType { /** * Validate that a primitive atomic value is a valid instance of a type derived from the * same primitive type. * @param primValue the value in the value space of the primitive type. * @param lexicalValue the value in the lexical space. If null, the string value of primValue * is used. This value is checked against the pattern facet (if any) * @param rules * @return null if the value is valid; otherwise, a ValidationFailure object indicating * the nature of the error. * @throws UnsupportedOperationException in the case of an external object type */ public ValidationFailure validate(AtomicValue primValue, CharSequence lexicalValue, ConversionRules rules); /** * Determine whether the atomic type is ordered, that is, whether less-than and greater-than comparisons * are permitted * @return true if ordering operations are permitted */ public boolean isOrdered(); /** * Determine whether the type is abstract, that is, whether it cannot have instances that are not also * instances of some concrete subtype */ public boolean isAbstract(); /** * Determine whether the atomic type is a primitive type. The primitive types are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration; * xs:untypedAtomic; and all supertypes of these (xs:anyAtomicType, xs:numeric, ...) * @return true if the type is considered primitive under the above rules */ public boolean isPrimitiveType(); /** * Determine whether the atomic type is a built-in type. The built-in atomic types are the 41 atomic types * defined in XML Schema, plus xs:dayTimeDuration and xs:yearMonthDuration, * xs:untypedAtomic, and all supertypes of these (xs:anyAtomicType, xs:numeric, ...) */ public boolean isBuiltInType(); /** * Get the name of this type as a StructuredQName, unless the type is anonymous, in which case * return null * @return the name of the atomic type, or null if the type is anonymous. */ public StructuredQName getTypeName(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/SimpleType.java0000644000175000017500000001401411671711573024122 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.value.AtomicValue; /** * This interface represents a simple type, which may be a built-in simple type, or * a user-defined simple type. */ public interface SimpleType extends SchemaType { public static final int VARIETY_ATOMIC = 10; public static final int VARIETY_LIST = 11; public static final int VARIETY_UNION = 12; public static final int VARIETY_UNSPECIFIED_SIMPLE = 13; /** * Test whether this Simple Type is an atomic type * @return true if this is an atomic type */ boolean isAtomicType(); /** * Test whether this Simple Type is a list type * @return true if this is a list type */ boolean isListType(); /** * Test whether this Simple Type is a union type * @return true if this is a union type */ boolean isUnionType(); /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects * @return true if this is an external type */ boolean isExternalType(); /** * Determine whether this is a built-in type or a user-defined type * @return true if this is a built-in type */ boolean isBuiltInType(); /** * Get the built-in type from which this type is derived by restriction * @return the built-in type from which this type is derived by restriction. This will not necessarily * be a primitive type. */ /*@Nullable*/ SchemaType getBuiltInBaseType(); /** * Get the typed value corresponding to a given string value, assuming it is * valid against this type * @param value the string value * @param resolver a namespace resolver used to resolve any namespace prefixes appearing * in the content of values. Can supply null, in which case any namespace-sensitive content * will be rejected. * @param rules the conversion rules from the configuration * @return an iterator over the atomic sequence comprising the typed value. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue}, * The next() method on the iterator throws no checked exceptions, although it is not actually * declared as an UnfailingIterator. * @throws ValidationException if the supplied value is not in the lexical space of the data type */ public SequenceIterator getTypedValue(CharSequence value, /*@Nullable*/ NamespaceResolver resolver, ConversionRules rules) throws ValidationException; /** * Check whether a given input string is valid according to this SimpleType * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param rules the conversion rules from the configuration * @return null if validation succeeds; or return a ValidationFailure describing the validation failure * if validation fails. Note that the exception is returned rather than being thrown. * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ /*@Nullable*/ ValidationFailure validateContent( /*@NotNull*/ CharSequence value, /*@Nullable*/ NamespaceResolver nsResolver, /*@NotNull*/ ConversionRules rules); /** * Test whether this type is namespace sensitive, that is, if a namespace context is needed * to translate between the lexical space and the value space. This is true for types derived * from, or containing, QNames and NOTATIONs * @return true if the type is namespace-sensitive */ boolean isNamespaceSensitive(); /** * Determine how values of this simple type are whitespace-normalized. * @return one of {@link net.sf.saxon.value.Whitespace#PRESERVE}, {@link net.sf.saxon.value.Whitespace#COLLAPSE}, * {@link net.sf.saxon.value.Whitespace#REPLACE}. */ public int getWhitespaceAction(); /** * Apply any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess * @param input the value to be preprocessed * @return the value after preprocessing * @throws ValidationException if preprocessing detects that the value is invalid */ public CharSequence preprocess(CharSequence input) throws ValidationException; /** * Reverse any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess. This is called when converting a value of this type to * a string * @param input the value to be postprocessed: this is the "ordinary" result of converting * the value to a string * @return the value after postprocessing * @throws ValidationException if postprocessing detects that the value is invalid */ public CharSequence postprocess(CharSequence input) throws ValidationException; } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/StringToDouble.java0000644000175000017500000001436611671711573024745 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.value.Whitespace; import java.io.Serializable; /** * This class converts a string to an xs:double according to the rules in XML Schema 1.0 */ public class StringToDouble implements Serializable { private static StringToDouble THE_INSTANCE = new StringToDouble(); /** * Get the singleton instance * @return the singleton instance of this class */ public static StringToDouble getInstance() { return THE_INSTANCE; } protected StringToDouble() {} /** * Convert a string to a double. * @param s the String to be converted * @return a double representing the value of the String * @throws NumberFormatException if the value cannot be converted */ public double stringToNumber(CharSequence s) throws NumberFormatException { // first try to parse simple numbers by hand (it's cheaper) int len = s.length(); boolean containsDisallowedChars = false; boolean containsWhitespace = false; if (len < 9) { boolean useJava = false; long num = 0; int dot = -1; int lastDigit = -1; boolean onlySpaceAllowed = false; for (int i=0; i lastDigit) { return (double)num; } else { int afterPoint = lastDigit - dot; return ((double)num)/powers[afterPoint]; } } } else { loop2: for (int i=0; i * If there are types derived from this type by extension, search those too. * @param fingerprint Identifies the name of the child element within this content model * @return the schema type associated with the attribute use identified by the fingerprint. * If there is no such attribute use, return null. */ public int getAttributeUseCardinality(int fingerprint) throws SchemaException { return StaticProperty.ALLOWS_ZERO_OR_ONE; } /** * Return true if this type (or any known type derived from it by extension) allows the element * to have one or more attributes. * @return true if attributes are allowed */ public boolean allowsAttributes() { return true; } /** * Get a list of all the names of elements that can appear as children of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), return null. * * @param children an integer set, initially empty, which on return will hold the fingerprints of all permitted * child elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the children, typically because of wildcards. In this case the other contents of the set should * @param ignoreWildcards */ public void gatherAllPermittedChildren(/*@NotNull*/ IntHashSet children, boolean ignoreWildcards) throws SchemaException { children.add(-1); } /** * Get a list of all the names of elements that can appear as descendants of an element having this * complex type, as integer fingerprints. If the list is unbounded (because of wildcards or the use * of xs:anyType), return null. * * @param descendants an integer set, initially empty, which on return will hold the fingerprints of all permitted * descendant elements; if the result contains the value -1, this indicates that it is not possible to enumerate * all the descendants, typically because of wildcards. In this case the other contents of the set should * be ignored. */ public void gatherAllPermittedDescendants(/*@NotNull*/ IntHashSet descendants) throws SchemaException { descendants.add(-1); } /** * Assuming an element is a permitted descendant in the content model of this type, determine * the type of the element when it appears as a descendant. If it appears with more than one type, * return xs:anyType. * @param fingerprint the name of the required descendant element * @return the type of the descendant element; null if the element cannot appear as a descendant; * anyType if it can appear with several different types */ /*@NotNull*/ public SchemaType getDescendantElementType(int fingerprint) throws SchemaException { return this; } /** * Assuming an element is a permitted descendant in the content model of this type, determine * the cardinality of the element when it appears as a descendant. * @param fingerprint the name of the required descendant element * @return the cardinality of the descendant element within this complex type */ public int getDescendantElementCardinality(int fingerprint) throws SchemaException { return StaticProperty.ALLOWS_ZERO_OR_MORE; } /** * Ask whether this type (or any known type derived from it by extension) allows the element * to have children that match a wildcard * @return true if the content model of this type, or its extensions, contains an element wildcard */ public boolean containsElementWildcard() { 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/type/ErrorType.java0000644000175000017500000003463211671711573023772 0ustar mathieumathieupackage net.sf.saxon.type; import net.sf.saxon.expr.Expression; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.iter.SingletonIterator; import net.sf.saxon.value.UntypedAtomicValue; import net.sf.saxon.value.Value; import net.sf.saxon.value.Whitespace; /** * This class has a singleton instance which represents the XML Schema 1.1 built-in type xs:error */ public final class ErrorType implements SimpleType { /*@NotNull*/ private static ErrorType theInstance = new ErrorType(); /** * Private constructor */ private ErrorType() { } /** * Get the local name of this type * * @return the local name of this type definition, if it has one. Return null in the case of an * anonymous type. */ /*@NotNull*/ public String getName() { return "error"; } /** * Get the target namespace of this type * * @return the target namespace of this type definition, if it has one. Return null in the case * of an anonymous type, and in the case of a global type defined in a no-namespace schema. */ public String getTargetNamespace() { return NamespaceConstant.SCHEMA; } /** * Return true if this is an external object type, that is, a Saxon-defined type for external * Java or .NET objects */ public boolean isExternalType() { return false; } /** * Determine whether this is a built-in type or a user-defined type */ public boolean isBuiltInType() { return true; } /** * Get the redefinition level. This is zero for a component that has not been redefined; * for a redefinition of a level-0 component, it is 1; for a redefinition of a level-N * component, it is N+1. This concept is used to support the notion of "pervasive" redefinition: * if a component is redefined at several levels, the top level wins, but it is an error to have * two versions of the component at the same redefinition level. * @return the redefinition level */ public int getRedefinitionLevel() { return 0; } /** * Get the URI of the schema document containing the definition of this type * @return null for a built-in type */ /*@Nullable*/ public String getSystemId() { return null; } /** * Get the singular instance of this class * @return the singular object representing xs:anyType */ /*@NotNull*/ public static ErrorType getInstance() { return theInstance; } /** * Get the validation status - always valid */ public int getValidationStatus() { return VALIDATED; } /** * Get the base type * @return AnyType */ /*@NotNull*/ public SchemaType getBaseType() { return AnySimpleType.getInstance(); } /** * Returns the base type that this type inherits from. This method can be used to get the * base type of a type that is known to be valid. * @return the base type. */ /*@NotNull*/ public SchemaType getKnownBaseType() throws IllegalStateException { return getBaseType(); } /** * Test whether this SchemaType is a complex type * * @return true if this SchemaType is a complex type */ public boolean isComplexType() { return false; } /** * Test whether this SchemaType is a simple type * @return true if this SchemaType is a simple type */ public boolean isSimpleType() { return true; } /** * Get the fingerprint of the name of this type * @return the fingerprint. */ public int getFingerprint() { return StandardNames.XS_ERROR; } /** * Get the namecode of the name of this type. This includes the prefix from the original * type declaration: in the case of built-in types, there may be a conventional prefix * or there may be no prefix. */ public int getNameCode() { return StandardNames.XS_ERROR; } /** * Get a description of this type for use in diagnostics * @return the string "xs:anyType" */ /*@NotNull*/ public String getDescription() { return "xs:error"; } /** * Get the display name of the type: that is, a lexical QName with an arbitrary prefix * * @return a lexical QName identifying the type */ /*@NotNull*/ public String getDisplayName() { return "xs:error"; } /** * Test whether this is the same type as another type. They are considered to be the same type * if they are derived from the same type definition in the original XML representation (which * can happen when there are multiple includes of the same file) */ public boolean isSameType(SchemaType other) { return (other instanceof ErrorType); } /** * Get the typed value of a node that is annotated with this schema type. This shouldn't happen: nodes * are never annotated as xs:error; but if it does happen, we treat it as if it were * untypedAtomic. * @param node the node whose typed value is required * @return an iterator returning a single untyped atomic value, equivalent to the string value of the node. */ /*@NotNull*/ public SequenceIterator getTypedValue(/*@NotNull*/ NodeInfo node) { return SingletonIterator.makeIterator(new UntypedAtomicValue(node.getStringValueCS())); } /** * Get the typed value of a node that is annotated with this schema type. The result of this method will always be * consistent with the method * {@link #getTypedValue}. However, this method is often more convenient and may be * more efficient, especially in the common case where the value is expected to be a singleton. * * @param node the node whose typed value is required * @return the typed value. * @since 8.5 */ /*@NotNull*/ public Value atomize(/*@NotNull*/ NodeInfo node) { return new UntypedAtomicValue(node.getStringValueCS()); } /** * Check that this type is validly derived from a given type * * @param type the type from which this type is derived * @param block the derivations that are blocked by the relevant element declaration * @throws net.sf.saxon.type.SchemaException * if the derivation is not allowed */ public void checkTypeDerivationIsOK(/*@NotNull*/ SchemaType type, int block) throws SchemaException { if (type == this || type == AnySimpleType.getInstance()) { return; } throw new SchemaException("Type xs:error is not validly derived from " + type.getDescription()); } /** * Test whether this Simple Type is an atomic type * @return false, this is not (necessarily) an atomic type */ public boolean isAtomicType() { return false; } /** * Ask whether this type is an ID type. This is defined to be any simple type * who typed value may contain atomic values of type xs:ID: that is, it includes types derived * from ID by restriction, list, or union. Note that for a node to be treated * as an ID, its typed value must be a *single* atomic value of type ID; the type of the * node, however, can still allow a list. */ public boolean isIdType() { return false; } /** * Ask whether this type is an IDREF or IDREFS type. This is defined to be any simple type * who typed value may contain atomic values of type xs:IDREF: that is, it includes types derived * from IDREF or IDREFS by restriction, list, or union */ public boolean isIdRefType() { return false; } public boolean isAnonymousType() { return false; } /** * Determine whether this is a list type * @return false (it isn't a list type) */ public boolean isListType() { return false; } /** * Determin whether this is a union type * @return true (this is a union type with no members) */ public boolean isUnionType() { return true; } /** * Get the built-in ancestor of this type in the type hierarchy * @return xs:anySimpleType */ /*@NotNull*/ public SchemaType getBuiltInBaseType() { return AnySimpleType.getInstance(); } /** * Get the typed value corresponding to a given string value, assuming it is * valid against this type * * @param value the string value * @param resolver a namespace resolver used to resolve any namespace prefixes appearing * in the content of values. Can supply null, in which case any namespace-sensitive content * will be rejected. * @param rules * @return an iterator over the atomic sequence comprising the typed value. The objects * returned by this SequenceIterator will all be of type {@link net.sf.saxon.value.AtomicValue} */ /*@NotNull*/ public SequenceIterator getTypedValue(CharSequence value, NamespaceResolver resolver, ConversionRules rules) { return SingletonIterator.makeIterator(new UntypedAtomicValue(value)); } /** * Check whether a given input string is valid according to this SimpleType * @param value the input string to be checked * @param nsResolver a namespace resolver used to resolve namespace prefixes if the type * is namespace sensitive. The value supplied may be null; in this case any namespace-sensitive * content will throw an UnsupportedOperationException. * @param rules * @return null if validation succeeds (which it never does for this implementation) * @throws UnsupportedOperationException if the type is namespace-sensitive and no namespace * resolver is supplied */ /*@NotNull*/ public ValidationFailure validateContent(/*@NotNull*/ CharSequence value, NamespaceResolver nsResolver, /*@NotNull*/ ConversionRules rules) { return new ValidationFailure("No content is ever valid against the type xs:error"); } /** * Test whether this type represents namespace-sensitive content * @return false */ public boolean isNamespaceSensitive() { return false; } /** * Returns the value of the 'block' attribute for this type, as a bit-signnificant * integer with fields such as {@link net.sf.saxon.type.SchemaType#DERIVATION_LIST} and {@link net.sf.saxon.type.SchemaType#DERIVATION_EXTENSION} * * @return the value of the 'block' attribute for this type */ public int getBlock() { return 0; } /** * Gets the integer code of the derivation method used to derive this type from its * parent. Returns zero for primitive types. * * @return a numeric code representing the derivation method, for example {@link net.sf.saxon.type.SchemaType#DERIVATION_RESTRICTION} */ public int getDerivationMethod() { return SchemaType.DERIVATION_RESTRICTION; } /** * Determines whether derivation (of a particular kind) * from this type is allowed, based on the "final" property * * @param derivation the kind of derivation, for example {@link net.sf.saxon.type.SchemaType#DERIVATION_LIST} * @return true if this kind of derivation is allowed */ public boolean allowsDerivation(int derivation) { return false; } /** * Determine how values of this simple type are whitespace-normalized. * * @return one of {@link net.sf.saxon.value.Whitespace#PRESERVE}, {@link net.sf.saxon.value.Whitespace#COLLAPSE}, * {@link net.sf.saxon.value.Whitespace#REPLACE}. */ public int getWhitespaceAction() { return Whitespace.COLLAPSE; } /** * Analyze an expression to see whether the expression is capable of delivering a value of this * type. * * @param expression the expression that delivers the content * @param kind the node kind whose content is being delivered: {@link Type#ELEMENT}, * {@link Type#ATTRIBUTE}, or {@link Type#DOCUMENT} * @param env */ public void analyzeContentExpression(Expression expression, int kind, StaticContext env) throws XPathException { throw new XPathException("No expression can ever return a value of type xs:error"); } /** * Apply any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess * @param input the value to be preprocessed * @return the value after preprocessing */ public CharSequence preprocess(CharSequence input) { return input; } /** * Reverse any pre-lexical facets, other than whitespace. At the moment the only such * facet is saxon:preprocess. This is called when converting a value of this type to * a string * @param input the value to be postprocessed: this is the "ordinary" result of converting * the value to a string * @return the value after postprocessing */ public CharSequence postprocess(CharSequence input) throws ValidationException { return input; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/0000755000175000017500000000000012213124713021307 5ustar mathieumathieusaxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/Transmitter.java0000644000175000017500000000567311671711573024516 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Source; /** * A Transmitter is a source of events sent to a Receiver. An implementation of this interface * can be used in any Saxon interface allowing a {@link Source} to be supplied, and allows * an input document to be created programmatically in the form of a stream of "push" events * send to the supplied {@link Receiver}. */ public abstract class Transmitter implements Source { private String systemId; /** * Send events to a supplied Receiver * @param receiver the Receiver to which events should be sent. * *

The pipelineConfiguration property of this Receiver is guaranteed * to be initialized, providing access to objects such as the Saxon Configuration * and NamePool.

* *

The implementation of this class does not necessarily need to construct Receiver * events directly. It can do so, for example, via the {@link StreamWriterToReceiver} * class, which translates {@link javax.xml.stream.XMLStreamWriter} events to Receiver events, * or via the {@link ReceivingContentHandler} class, which translates SAX * {@link org.xml.sax.ContentHandler} events to Receiver events.

* * @throws net.sf.saxon.trans.XPathException if any failure occurs */ public abstract void transmit(Receiver receiver) throws XPathException; /** * Set the system identifier for this Source. *

*

The system identifier is optional if the source does not * get its data from a URL, but it may still be useful to provide one. * The application can use a system identifier, for example, to resolve * relative URIs and to include in error messages and warnings.

* * @param systemId The system identifier as a URL string. */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the system identifier that was set with setSystemId. * * @return The system identifier that was set with setSystemId, or null * if setSystemId was not called. */ public String getSystemId() { return systemId; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/SequenceReceiver.java0000644000175000017500000001053611671711573025431 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; /** * SequenceReceiver: this extension of the Receiver interface is used when processing * a sequence constructor. It differs from the Receiver in allowing items (atomic values or * nodes) to be added to the sequence, not just tree-building events. */ public abstract class SequenceReceiver implements Receiver { protected boolean previousAtomic = false; /*@NotNull*/ protected PipelineConfiguration pipelineConfiguration; /*@Nullable*/ protected String systemId = null; /** * Create a SequenceReceiver * @param pipe the pipeline configuration */ public SequenceReceiver(/*@NotNull*/ PipelineConfiguration pipe) { this.pipelineConfiguration = pipe; } /*@NotNull*/ public final PipelineConfiguration getPipelineConfiguration() { return pipelineConfiguration; } public void setPipelineConfiguration(/*@NotNull*/ PipelineConfiguration pipelineConfiguration) { this.pipelineConfiguration = pipelineConfiguration; } /** * Get the Saxon Configuration * @return the Configuration */ public final Configuration getConfiguration() { return pipelineConfiguration.getConfiguration(); } /** * Set the system ID * @param systemId the URI used to identify the tree being passed across this interface */ public void setSystemId(/*@Nullable*/ String systemId) { this.systemId = systemId; } /** * Get the system ID * @return the system ID that was supplied using the setSystemId() method */ /*@Nullable*/ public String getSystemId() { return systemId; } /** * Notify an unparsed entity URI. * @param name The name of the unparsed entity * @param systemID The system identifier of the unparsed entity * @param publicID The public identifier of the unparsed entity */ public void setUnparsedEntity(String name, String systemID, String publicID) throws XPathException { } /** * Start the output process */ public void open() throws XPathException { previousAtomic = false; } /** * Append an arbitrary item (node or atomic value) to the output * @param item the item to be appended * @param locationId the location of the calling instruction, for diagnostics * @param copyNamespaces if the item is an element node, this indicates whether its namespaces * need to be copied. Values are {@link net.sf.saxon.om.NodeInfo#ALL_NAMESPACES}, * {@link net.sf.saxon.om.NodeInfo#LOCAL_NAMESPACES}, {@link net.sf.saxon.om.NodeInfo#NO_NAMESPACES} * @throws net.sf.saxon.trans.XPathException if the operation fails */ public abstract void append(Item item, int locationId, int copyNamespaces) throws XPathException; /** * Append an item (node or atomic value) to the output * @param item the item to be appended * @throws net.sf.saxon.trans.XPathException if the operation fails */ public void append(Item item) throws XPathException { append(item, -1, NodeInfo.ALL_NAMESPACES); } /** * Get the name pool * @return the Name Pool that was supplied using the setConfiguration() method */ public NamePool getNamePool() { return pipelineConfiguration.getConfiguration().getNamePool(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/NamePoolConverter.java0000644000175000017500000000626411671711573025601 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.CodedName; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NamespaceBinding; import net.sf.saxon.om.NodeName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; /** * This class is a filter that passes all Receiver events through unchanged, * except that it changes namecodes to allow for the source and the destination * using different NamePools. This is necessary when a stylesheet has been constructed * as a general document (e.g. as the result of a transformation) and is passed to * newTemplates() to be compiled as a stylesheet. * * @author Michael Kay */ public class NamePoolConverter extends ProxyReceiver { NamePool oldPool; NamePool newPool; /** * Constructor * @param next the next receiver in the pipeline * @param oldPool the old namepool * @param newPool th new namepool */ public NamePoolConverter(Receiver next, NamePool oldPool, NamePool newPool) { super(next); this.oldPool = oldPool; this.newPool = newPool; } /** * Set the underlying emitter. This call is mandatory before using the Emitter. * This version is modified from that of the parent class to avoid setting the namePool * of the destination Receiver. */ @Override public void setUnderlyingReceiver(/*@NotNull*/ Receiver receiver) { nextReceiver = receiver; } /** * Output element start tag */ public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { int nc = newPool.allocate(nameCode.getPrefix(), nameCode.getURI(), nameCode.getLocalPart()); nextReceiver.startElement(new CodedName(nc, newPool), typeCode, locationId, properties); } /** * Handle a namespace */ public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException { nextReceiver.namespace(namespaceBinding, properties); } /** * Handle an attribute */ public void attribute(NodeName nameCode, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { int nc = newPool.allocate(nameCode.getPrefix(), nameCode.getURI(), nameCode.getLocalPart()); nextReceiver.attribute(new CodedName(nc, newPool), typeCode, value, locationId, properties); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/LocationCopier.java0000644000175000017500000000607211671711573025106 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.NodeInfo; /** * A Receiver that can be inserted into an event pipeline to copy location information. * The class acts as a LocationProvider, so it supports getSystemId() and getLineNumber() methods; * the location returned can vary for each node, and is set by the class generating the events. * The class is used when it is necessary to copy a subtree along with its location information; * for example, when copying an inline schema within a stylesheet to a separate schema document. * *

Note: prior to 9.2, the LocationCopier was a ProxyReceiver that passed all events on the * pipeline unchanged. It no longer does this, instead it is found as the LocationProvider on a * pipeline, but does not itself see the pipeline events.

*/ public class LocationCopier implements CopyInformee, SourceLocationProvider { private String systemId; private int lineNumber; private boolean wholeDocument; public LocationCopier(boolean wholeDocument) { this.wholeDocument = wholeDocument; } /** * Provide information about the node being copied. This method is called immediately before * the startElement call for the element node in question. * * @param element the node being copied, which must be an element node */ public int notifyElementNode(NodeInfo element) { systemId = (wholeDocument ? element.getSystemId() : element.getBaseURI()); // The logic behind this is that if we are copying the whole document, we will be copying all // the relevant xml:base attributes; so retaining the systemId values is sufficient to enable // the base URIs of the nodes to be preserved. But if we only copy an element (for example // an xsl:import-schema element - see test schema091 - then its base URI might be affected // by xml:base attributes that aren't being copied. Ideally we would have two separate properties, // but XDM doesn't work that way. lineNumber = element.getLineNumber(); return 0; } public String getSystemId(long locationId) { return systemId; } public int getLineNumber(long locationId) { return lineNumber; } public int getColumnNumber(long locationId) { return -1; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/CopyNamespaceSensitiveException.java0000644000175000017500000000211011671711573030461 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; /** * Exception indicating that an attempt was made to copy namespace-sensitive content * without copying its associated namespaces */ public class CopyNamespaceSensitiveException extends XPathException { public CopyNamespaceSensitiveException(String message) { super(message); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/ContentHandlerProxy.java0000644000175000017500000005573611671711573026161 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.lib.SaxonOutputKeys; import net.sf.saxon.lib.TraceListener; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamespaceBinding; import net.sf.saxon.om.NodeName; import net.sf.saxon.trace.InstructionInfo; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.util.AttributeCollectionImpl; import net.sf.saxon.type.SchemaException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; import net.sf.saxon.value.Whitespace; import org.xml.sax.ContentHandler; import org.xml.sax.Locator; import org.xml.sax.SAXException; import org.xml.sax.ext.LexicalHandler; import javax.xml.transform.Result; import java.io.PrintStream; import java.util.Properties; import java.util.Stack; /** * A ContentHandlerProxy is a Receiver that converts events into the form expected by an * underlying SAX2 ContentHandler. Relevant events (notably comments) can also be * fed to a LexicalHandler. *

* Note that in general the output passed to a Receiver * corresponds to an External General Parsed Entity. A SAX2 ContentHandler only expects * to deal with well-formed XML documents, so we only pass it the contents of the first * element encountered, unless the saxon:require-well-formed output property is set to "no". *

* This ContentHandlerProxy provides no access to type information. For a ContentHandler that * makes type information available, see {@link com.saxonica.jaxp.TypedContentHandler} *

* The ContentHandlerProxy can also be nominated as a TraceListener, to receive notification * of trace events. This will be done automatically if the option setTraceListener( */ public class ContentHandlerProxy implements Receiver { private PipelineConfiguration pipe; private String systemId; protected ContentHandler handler; protected LexicalHandler lexicalHandler; private LocationProvider locationProvider; private int depth = 0; private boolean requireWellFormed = false; private boolean undeclareNamespaces = false; private Stack elementStack = new Stack(); private Stack namespaceStack = new Stack(); private ContentHandlerProxyTraceListener traceListener; protected AttributeCollectionImpl pendingAttributes; private NodeName pendingElement = null; private long currentLocationId; // MARKER is a value added to the namespace stack at the start of an element, so that we know how // far to unwind the stack on an end-element event. private static final String MARKER = "##"; /** * Set the underlying content handler. This call is mandatory before using this Receiver. * If the content handler is an instance of {@link LexicalHandler}, then it will also receive * notification of lexical events such as comments. * @param handler the SAX content handler to which all events will be directed */ public void setUnderlyingContentHandler(ContentHandler handler) { this.handler = handler; if (handler instanceof LexicalHandler) { lexicalHandler = (LexicalHandler)handler; } } /** * Get the underlying content handler * @return the SAX content handler to which all events are being directed */ public ContentHandler getUnderlyingContentHandler() { return handler; } /** * Set the Lexical Handler to be used. If called, this must be called AFTER * setUnderlyingContentHandler() * @param handler the SAX lexical handler to which lexical events (such as comments) will * be notified. */ public void setLexicalHandler(LexicalHandler handler) { lexicalHandler = handler; } /** * Set the pipeline configuration * @param pipe the pipeline configuration */ public void setPipelineConfiguration(/*@NotNull*/ PipelineConfiguration pipe) { this.pipe = pipe; locationProvider = pipe.getLocationProvider(); } /** * Get the pipeline configuration */ /*@NotNull*/ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Get the Saxon configuration * @return the Saxon configuration */ public Configuration getConfiguration() { return pipe.getConfiguration(); } /** * Set the System ID of the destination tree * @param systemId the system ID (effectively the base URI) */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the System ID of the destination tree * @return the system ID (effectively the base URI) */ public String getSystemId() { return systemId; } /** * Get the associated TraceListener that receives notification of trace events * @return the trace listener. If there is no existing trace listener, then a new one * will be created. */ public ContentHandlerProxyTraceListener getTraceListener() { if (traceListener == null) { traceListener = new ContentHandlerProxyTraceListener(); } return traceListener; } /** * Get the location provider * @return the location provider, used to map location ids to actual URIs and line numbers */ public LocationProvider getLocationProvider() { return locationProvider; } /** * Get the current location identifier * @return the location identifier of the most recent event. This can be translated to real * location information by passing it to the location provider. */ public long getCurrentLocationId() { return currentLocationId; } /** * Notify an unparsed entity URI. This implementation does nothing: the event is ignored. * * @param name The name of the unparsed entity * @param systemID The system identifier of the unparsed entity * @param publicID The public identifier of the unparsed entity */ public void setUnparsedEntity(String name, String systemID, String publicID) throws XPathException { // no-op } /** * Set the output details. * @param details the serialization properties. The only values used by this implementation are * {@link SaxonOutputKeys#REQUIRE_WELL_FORMED} and {@link net.sf.saxon.lib.SaxonOutputKeys#UNDECLARE_PREFIXES}. */ public void setOutputProperties(Properties details) throws XPathException { String prop = details.getProperty(SaxonOutputKeys.REQUIRE_WELL_FORMED); if (prop != null) { requireWellFormed = prop.equals("yes"); } prop = details.getProperty(SaxonOutputKeys.UNDECLARE_PREFIXES); if (prop != null) { undeclareNamespaces = prop.equals("yes"); } } /** * Ask whether the content handler can handle a stream of events that is merely * well-balanced, or whether it can only handle a well-formed sequence. * @return true if the content handler requires the event stream to represent a well-formed * XML document (containing exactly one top-level element node and no top-level text nodes) */ public boolean isRequireWellFormed() { return requireWellFormed; } /** * Set whether the content handler can handle a stream of events that is merely * well-balanced, or whether it can only handle a well-formed sequence. The default is false. * @param wellFormed set to true if the content handler requires the event stream to represent a well-formed * XML document (containing exactly one top-level element node and no top-level text nodes). Otherwise, * multiple top-level elements and text nodes are allowed, as in the XDM model. */ public void setRequireWellFormed(boolean wellFormed) { requireWellFormed = wellFormed; } /** * Ask whether namespace undeclaration events (for a non-null prefix) should be notified. * The default is no, because some ContentHandlers (e.g. JDOM) can't cope with them. * * @return true if namespace undeclarations (xmlns:p="") are to be output */ public boolean isUndeclareNamespaces() { return undeclareNamespaces; } /** * Set whether namespace undeclaration events (for a non-null prefix) should be notified. * The default is no, because some ContentHandlers (e.g. JDOM) can't cope with them. * * @param undeclareNamespaces true if namespace undeclarations (xmlns:p="") are to be output */ public void setUndeclareNamespaces(boolean undeclareNamespaces) { this.undeclareNamespaces = undeclareNamespaces; } /** * Notify the start of the event stream */ public void open() throws XPathException { pendingAttributes = new AttributeCollectionImpl(getPipelineConfiguration().getConfiguration()); if (handler == null) { throw new IllegalStateException("ContentHandlerProxy.open(): no underlying handler provided"); } try { locationProvider = getPipelineConfiguration().getLocationProvider(); pendingAttributes.setLocationProvider(locationProvider); Locator locator = new ContentHandlerProxyLocator(this); handler.setDocumentLocator(locator); handler.startDocument(); } catch (SAXException err) { handleSAXException(err); } depth = 0; } /** * Notify the end of the event stream */ public void close() throws XPathException { try { handler.endDocument(); } catch (SAXException err) { handleSAXException(err); } } /** * Notify the start of the document. */ public void startDocument(int properties) throws XPathException { } /** * Notify the end of the document */ public void endDocument() throws XPathException { } /** * Notify the start of an element */ public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { depth++; if (depth <= 0 && requireWellFormed) { notifyNotWellFormed(); } pendingElement = nameCode; currentLocationId = locationId; namespaceStack.push(MARKER); } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. */ public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException { String prefix = namespaceBinding.getPrefix(); if (prefix.equals("xml")) { return; } String uri = namespaceBinding.getURI(); if ((!undeclareNamespaces) && uri.length()==0 && prefix.length()!=0) { // This is a namespace undeclaration, but the ContentHandler doesn't want to know about undeclarations return; } try { handler.startPrefixMapping(prefix, uri); namespaceStack.push(prefix); } catch (SAXException err) { handleSAXException(err); } } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. */ public void attribute(NodeName nameCode, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { int index = pendingAttributes.findByNodeName(nameCode); if (index < 0) { pendingAttributes.addAttribute(nameCode, typeCode, value.toString(), locationId, properties); } else { pendingAttributes.setAttribute(index, nameCode, typeCode, value.toString(), locationId, properties); } } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { try { if (depth > 0 || !requireWellFormed) { String uri = pendingElement.getURI(); String localName = pendingElement.getLocalPart(); String qname = pendingElement.getDisplayName(); handler.startElement(uri, localName, qname, pendingAttributes); elementStack.push(uri); elementStack.push(localName); elementStack.push(qname); pendingAttributes.clear(); pendingElement = null; } } catch (SAXException err) { handleSAXException(err); } } /** * End of element */ public void endElement() throws XPathException { if (depth > 0) { try { String qname = (String)elementStack.pop(); String localName = (String)elementStack.pop(); String uri = (String)elementStack.pop(); handler.endElement(uri, localName, qname); } catch (SAXException err) { handleSAXException(err); } } while (true) { String prefix = (String)namespaceStack.pop(); if (prefix.equals(MARKER)) { break; } try { handler.endPrefixMapping(prefix); } catch (SAXException err) { handleSAXException(err); } } depth--; // if this was the outermost element, and well formed output is required // then no further elements will be processed if (requireWellFormed && depth <= 0) { depth = Integer.MIN_VALUE; // crude but effective } } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { currentLocationId = locationId; boolean disable = ((properties & ReceiverOptions.DISABLE_ESCAPING) != 0); if (disable) { setEscaping(false); } try { if (depth <= 0 && requireWellFormed) { if (Whitespace.isWhite(chars)) { // ignore top-level white space } else { notifyNotWellFormed(); } } else { handler.characters(chars.toString().toCharArray(), 0, chars.length()); } } catch (SAXException err) { handleSAXException(err); } if (disable) { setEscaping(true); } } /** * The following function is called when it is found that the output is not a well-formed document. * Unless the ContentHandler accepts "balanced content", this is a fatal error. */ protected void notifyNotWellFormed() throws XPathException { XPathException err = new XPathException("The result tree cannot be supplied to the ContentHandler because it is not well-formed XML"); err.setErrorCode(SaxonErrorCode.SXCH0002); throw err; } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { currentLocationId = locationId; try { handler.processingInstruction(target, data.toString()); } catch (SAXException err) { handleSAXException(err); } } /** * Output a comment. Passes it on to the ContentHandler provided that the ContentHandler * is also a SAX2 LexicalHandler. */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { currentLocationId = locationId; try { if (lexicalHandler != null) { lexicalHandler.comment(chars.toString().toCharArray(), 0, chars.length()); } } catch (SAXException err) { handleSAXException(err); } } /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation */ public boolean usesTypeAnnotations() { return false; } /** * Switch escaping on or off. This is called when the XSLT disable-output-escaping attribute * is used to switch escaping on or off. It is not called for other sections of output (e.g. * element names) where escaping is inappropriate. The action, as defined in JAXP 1.1, is * to notify the request to the Content Handler using a processing instruction. * @param escaping true if escaping is to be switched on, false to switch it off */ private void setEscaping(boolean escaping) { try { handler.processingInstruction( (escaping ? Result.PI_ENABLE_OUTPUT_ESCAPING : PI_DISABLE_OUTPUT_ESCAPING), ""); } catch (SAXException err) { throw new AssertionError(err); } } /** * Handle a SAXException thrown by the ContentHandler * @param err the exception to be handler * @throws XPathException always */ private void handleSAXException(SAXException err) throws XPathException { Exception nested = err.getException(); if (nested instanceof XPathException) { throw (XPathException)nested; } else if (nested instanceof SchemaException) { throw new XPathException(nested); } else { XPathException de = new XPathException(err); de.setErrorCode(SaxonErrorCode.SXCH0003); throw de; } } /** * Create a TraceListener that will collect information about the current * location in the source document. This is used to provide information * to the receiving application for diagnostic purposes. */ public static class ContentHandlerProxyTraceListener implements TraceListener { private Stack contextItemStack; public void setOutputDestination(PrintStream stream) { // no action } /** * Get the context item stack * @return the context item stack */ /*@Nullable*/ public Stack getContextItemStack() { return contextItemStack; } /** * Method called at the start of execution, that is, when the run-time transformation starts */ public void open(Controller controller) { contextItemStack = new Stack(); } /** * Method called at the end of execution, that is, when the run-time execution ends */ public void close() { contextItemStack = null; } /** * Method that is called when an instruction in the stylesheet gets processed. * * @param instruction gives information about the instruction being * executed, and about the context in which it is executed. This object is mutable, * so if information from the InstructionInfo is to be retained, it must be copied. */ public void enter(InstructionInfo instruction, XPathContext context) { // do nothing } /** * Method that is called after processing an instruction of the stylesheet, * that is, after any child instructions have been processed. * * @param instruction gives the same information that was supplied to the * enter method, though it is not necessarily the same object. Note that the * line number of the instruction is that of the start tag in the source stylesheet, * not the line number of the end tag. */ public void leave(InstructionInfo instruction) { // do nothing } /** * Method that is called by an instruction that changes the current item * in the source document: that is, xsl:for-each, xsl:apply-templates, xsl:for-each-group. * The method is called after the enter method for the relevant instruction, and is called * once for each item processed. * * @param currentItem the new current item. Item objects are not mutable; it is safe to retain * a reference to the Item for later use. */ public void startCurrentItem(Item currentItem) { if (contextItemStack == null) { contextItemStack = new Stack(); } contextItemStack.push(currentItem); } /** * Method that is called when an instruction has finished processing a new current item * and is ready to select a new current item or revert to the previous current item. * The method will be called before the leave() method for the instruction that made this * item current. * * @param currentItem the item that was current, whose processing is now complete. This will represent * the same underlying item as the corresponding startCurrentItem() call, though it will * not necessarily be the same actual object. */ public void endCurrentItem(Item currentItem) { contextItemStack.pop(); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/IDFilter.java0000644000175000017500000001470011671711573023633 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.NodeName; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.AtomicType; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; import java.util.HashSet; /** * IDFilter is a ProxyReceiver that extracts the subtree of a document rooted at the * element with a given ID value. Namespace declarations outside this subtree are * treated as if they were present on the identified element. */ public class IDFilter extends StartTagBuffer { private String requiredId; private int activeDepth = 0; private boolean matched = false; private HashSet nonIDs; public IDFilter (Receiver next, String id) { // System.err.println("IDFilter, looking for " + id); super(next); this.requiredId = id; } /** * startElement */ public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { matched = false; if (activeDepth>0) { activeDepth++; } super.startElement(nameCode, typeCode, locationId, properties); // this remembers the details } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * * * @param attName The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined, inter alia: *
DISABLE_ESCAPING
Disable escaping for this attribute
*
NO_SPECIAL_CHARACTERS
Attribute value contains no special characters
*
IS_ID
Attribute is an ID
* @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(NodeName attName, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { super.attribute(attName, typeCode, value, locationId, properties); if ((attName.equals(StandardNames.XML_ID_NAME)) || ((properties &ReceiverOptions.IS_ID) != 0)) { if (value.toString().equals(requiredId)) { matched = true; } } } /** * startContent: Test if a matching ID attribute was found; if so, start outputting. */ public void startContent() throws XPathException { if (activeDepth>0) { super.startContent(); } else if (matched) { activeDepth = 1; super.startContent(); } } protected void declareNamespacesForStartElement() throws XPathException { if (activeDepth == 1) { declareAllNamespaces(); } else { super.declareNamespacesForStartElement(); } } /** * endElement: */ public void endElement() throws XPathException { if (activeDepth > 0) { nextReceiver.endElement(); activeDepth--; } else { undeclareNamespacesForElement(); } } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (activeDepth > 0) { super.characters(chars, locationId, properties); } } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (activeDepth > 0) { super.processingInstruction(target, data, locationId, properties); } } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { if (activeDepth > 0) { super.comment(chars, locationId, properties); } } /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation */ public boolean usesTypeAnnotations() { return true; } /** * Test whether a type annotation code represents the type xs:ID or one of its subtypes * @param typeCode the fingerprint of the type name * @return true if the type is an ID type; false if it is not (or if the type code does not * resolve to a known type) */ private boolean isIDCode(SimpleType typeCode) { if (typeCode == BuiltInAtomicType.ID) { return true; } if (typeCode instanceof BuiltInAtomicType) { return false; // No other built-in type is an ID } if (nonIDs == null) { nonIDs = new HashSet(20); } if (nonIDs.contains(typeCode)) { return false; } if (typeCode.isAtomicType()) { if (getConfiguration().getTypeHierarchy().isSubType((AtomicType)typeCode, BuiltInAtomicType.ID)) { return true; } else { nonIDs.add(typeCode); return false; } } else { return false; } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/SequenceOutputter.java0000644000175000017500000001223111671711573025672 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Controller; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.Item; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.tree.iter.EmptyIterator; import net.sf.saxon.tree.iter.ListIterator; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.SequenceExtent; import java.util.ArrayList; import java.util.List; /** * 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. * *

This class is not used to build temporary trees. For that, the ComplexContentOutputter * is used.

* * * @author Michael H. Kay */ public final class SequenceOutputter extends SequenceWriter { private List list; private Controller controller; // enables the SequenceOutputter to be reused /** * Create a new SequenceOutputter * @param pipe the pipeline configuration */ public SequenceOutputter(/*@NotNull*/ PipelineConfiguration pipe) { super(pipe); this.list = new ArrayList(50); } public SequenceOutputter(PipelineConfiguration pipe, Controller controller, int estimatedSize) { super(pipe); this.list = new ArrayList(estimatedSize); this.controller = controller; } public SequenceOutputter(PipelineConfiguration pipe, Controller controller) { super(pipe); this.list = new ArrayList(50); this.controller = controller; } /** * Allocate a SequenceOutputter. Used from generated bytecode. * @param context dynamic XPath context * @param hostLang host language (XSLT/XQuery) * @return the allocated SequenceOutputter * @see com.saxonica.bytecode.util.CompilerService */ /*@Nullable*/ public static SequenceOutputter allocateSequenceOutputter(XPathContext context, int hostLang){ Controller controller = context.getController(); SequenceOutputter seq = controller.allocateSequenceOutputter(20); seq.getPipelineConfiguration().setHostLanguage(hostLang); return seq; } /** * Clear the contents of the SequenceOutputter and make it available for reuse */ public void reset() { list = new ArrayList(Math.min(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 * @return the value (sequence of items) that have been written to this SequenceOutputter */ public ValueRepresentation getSequence() { switch (list.size()) { case 0: return EmptySequence.getInstance(); case 1: return list.get(0); default: return new SequenceExtent(list); } } /** * Get an iterator over the sequence of items that has been constructed * @return an iterator over the items that have been written to this SequenceOutputter */ public SequenceIterator iterate() { if (list.isEmpty()) { return EmptyIterator.emptyIterator(); } else { return new ListIterator(list); } } /** * Get the list containing the sequence of items * @return the list of items that have been written to this SequenceOutputter */ public List getList() { return list; } /** * Get the first item in the sequence that has been built * @return the first item in the list of items that have been written to this SequenceOutputter; * or null if the list is empty. */ public Item getFirstItem() { if (list.isEmpty()) { return null; } else { return list.get(0); } } /** * Get the last item in the sequence that has been built, and remove it * @return the last item written */ public Item popLastItem() { if (list.isEmpty()) { return null; } else { return list.remove(list.size()-1); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/NamespaceReducer.java0000644000175000017500000002544611671711573025410 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.NamespaceBinding; import net.sf.saxon.om.NamespaceResolver; import net.sf.saxon.om.NodeName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * NamespaceReducer is a ProxyReceiver responsible for removing duplicate namespace * declarations. It also ensures that an xmlns="" undeclaration is output when * necessary. Used on its own, the NamespaceReducer simply eliminates unwanted * namespace declarations. It can also be subclassed, in which case the subclass * can use the services of the NamespaceReducer to resolve QNames. *

* The NamespaceReducer also validates namespace-sensitive content. */ public class NamespaceReducer extends ProxyReceiver implements NamespaceResolver { // We keep track of namespaces to avoid outputting duplicate declarations. The namespaces // array holds a list of all namespaces currently declared (organised as pairs of entries, // prefix followed by URI). The countStack contains an entry for each element currently open; the // value on the stack is an integer giving the number of namespaces added to the main // namespace stack by that element. private NamespaceBinding[] namespaces = new NamespaceBinding[50]; // all namespace codes currently declared private int namespacesSize = 0; // all namespaces currently declared private int[] countStack = new int[50]; private int depth = 0; // Creating an element does not automatically inherit the namespaces of the containing element. // When the DISINHERIT property is set on startElement(), this indicates that the namespaces // on that element are not to be automatically inherited by its children. So startElement() // stacks a boolean flag indicating whether the children are to disinherit the parent's namespaces. private boolean[] disinheritStack = new boolean[50]; // When a child element does not inherit the namespaces of its parent, it acquires undeclarations // to indicate this fact. This array keeps track of the undeclarations that need to be added to the // current child element. private NamespaceBinding[] pendingUndeclarations = null; /** * Create a NamespaceReducer * @param next the Receiver to which events will be passed after namespace reduction */ public NamespaceReducer(Receiver next) { super(next); } /** * startElement. This call removes redundant namespace declarations, and * possibly adds an xmlns="" undeclaration. */ public void startElement(NodeName elemName, SchemaType typeCode, int locationId, int properties) throws XPathException { nextReceiver.startElement(elemName, typeCode, locationId, properties); // If the parent element specified inherit=no, keep a list of namespaces that need to be // undeclared if (depth>0 && disinheritStack[depth-1]) { pendingUndeclarations = new NamespaceBinding[namespacesSize]; System.arraycopy(namespaces, 0, pendingUndeclarations, 0, namespacesSize); } else { pendingUndeclarations = null; } // Record the current height of the namespace list so it can be reset at endElement time countStack[depth] = 0; disinheritStack[depth] = (properties & ReceiverOptions.DISINHERIT_NAMESPACES) != 0; if (++depth >= countStack.length) { int[] newstack = new int[depth*2]; System.arraycopy(countStack, 0, newstack, 0, depth); boolean[] disStack2 = new boolean[depth*2]; System.arraycopy(disinheritStack, 0, disStack2, 0, depth); countStack = newstack; disinheritStack = disStack2; } // Ensure that the element namespace is output, unless this is done // automatically by the caller (which is true, for example, for a literal // result element). if ((properties & ReceiverOptions.NAMESPACE_OK) == 0) { namespace(elemName.getNamespaceBinding(), 0); } } /** * Output a namespace node (binding) * @param namespaceBinding the prefix/uri pair to be output * @param properties the properties of the namespace binding * @throws XPathException if any downstream error occurs */ public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException { // Keep the namespace only if it is actually needed if (isNeeded(namespaceBinding)) { addToStack(namespaceBinding); countStack[depth - 1]++; nextReceiver.namespace(namespaceBinding, properties); } } /** * Determine whether a namespace declaration is needed * @param nsBinding the namespace binding * @return true if the namespace is needed: that is, if it not the XML namespace, is not a duplicate, * and is not a redundant xmlns="". */ private boolean isNeeded(NamespaceBinding nsBinding) { if (nsBinding.isXmlNamespace()) { // Ignore the XML namespace return false; } // First cancel any pending undeclaration of this namespace prefix (there may be more than one) String prefix = nsBinding.getPrefix(); if (pendingUndeclarations != null) { for (int p=0; p=0; i--) { if (namespaces[i].equals(nsBinding)) { // it's a duplicate so we don't need it return false; } if ((namespaces[i].getPrefix().equals(nsBinding.getPrefix()))) { // same prefix, different URI. return true; } } // we need it unless it's a redundant xmlns="" return (!nsBinding.isDefaultUndeclaration()); } /** * Add a namespace declaration to the stack * @param nsBinding the namespace code to be added */ private void addToStack(NamespaceBinding nsBinding) { // expand the stack if necessary if (namespacesSize+1 >= namespaces.length) { NamespaceBinding[] newlist = new NamespaceBinding[namespacesSize*2]; System.arraycopy(namespaces, 0, newlist, 0, namespacesSize); namespaces = newlist; } namespaces[namespacesSize++] = nsBinding; } /** * startContent: Add any namespace undeclarations needed to stop * namespaces being inherited from parent elements */ public void startContent() throws XPathException { if (pendingUndeclarations != null) { for (NamespaceBinding ns : pendingUndeclarations) { if (ns != null) { namespace(new NamespaceBinding(ns.getPrefix(), ""), 0); // relies on the namespace() method to prevent duplicate undeclarations } } } pendingUndeclarations = null; nextReceiver.startContent(); } /** * endElement: Discard the namespaces declared on this element. */ public void endElement () throws XPathException { if (depth-- == 0) { throw new IllegalStateException("Attempt to output end tag with no matching start tag"); } namespacesSize -= countStack[depth]; nextReceiver.endElement(); } /** * Get the URI code corresponding to a given prefix code, by searching the * in-scope namespaces. This is a service provided to subclasses. * @param prefixCode the 16-bit prefix code required * @return the 16-bit URI code, or -1 if the prefix is not found */ // protected short getURICode(short prefixCode) { // for (int i=namespacesSize-1; i>=0; i--) { // if ((namespaces[i]>>16) == (prefixCode)) { // return (short)(namespaces[i]&0xffff); // } // } // if (prefixCode == 0) { // return 0; // by default, no prefix means no namespace URI // } else { // return -1; // } // } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. * * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope */ /*@Nullable*/ public String getURIForPrefix(String prefix, boolean useDefault) { if ((prefix.length()==0) && !useDefault) { return NamespaceConstant.NULL; } else if ("xml".equals(prefix)) { return NamespaceConstant.XML; } else { for (int i=namespacesSize-1; i>=0; i--) { if ((namespaces[i].getPrefix().equals(prefix))) { return namespaces[i].getURI(); } } } return (prefix.length()==0 ? NamespaceConstant.NULL : null); } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { List prefixes = new ArrayList(namespacesSize); for (int i=namespacesSize-1; i>=0; i--) { String prefix = namespaces[i].getPrefix(); if (!prefixes.contains(prefix)) { prefixes.add(prefix); } } prefixes.add("xml"); return prefixes.iterator(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/LocationProvider.java0000644000175000017500000000550611671711573025460 0ustar mathieumathieupackage net.sf.saxon.event; /** * LocationProvider: this interface represents an object that * provides the location of elements in a source document or instructions in a stylesheet * or query. A locationProvider may be passed down the Receiver pipeline as part of the * PipelineConfiguration object; on the input pipeline, this will be a {@link SaxonLocator} object, * on the output pipeline, it will be a {@link net.sf.saxon.expr.instruct.LocationMap} *

* A LocationProvider that represents locations in the source document from which the events * are derived (as distinct from locations in a query or stylesheet of the instructions causing the * events) will also implement the marker interface {@link net.sf.saxon.event.SourceLocationProvider} */ public interface LocationProvider { /** * Get the URI of the document, entity, or module containing a particular location * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the URI of the document, XML entity or module. For a SourceLocationProvider this will * be the URI of the document or entity (the URI that would be the base URI if there were no * xml:base attributes). In other cases it may identify the query or stylesheet module currently * being executed. */ public String getSystemId(long locationId); /** * Get the line number within the document, entity or module containing a particular location * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the line number within the document, entity or module, or -1 if no information is available. */ public int getLineNumber(long locationId); /** * Get the column number within the document, entity, or module containing a particular location * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the column number within the document, entity, or module, or -1 if this is not available */ public int getColumnNumber(long locationId); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/Sender.java0000644000175000017500000006521111671711573023414 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.evpull.EventIterator; import net.sf.saxon.evpull.EventIteratorToReceiver; import net.sf.saxon.evpull.PullEventSource; import net.sf.saxon.expr.number.Numberer_en; import net.sf.saxon.lib.*; import net.sf.saxon.om.*; import net.sf.saxon.pull.PullProvider; import net.sf.saxon.pull.PullPushCopier; import net.sf.saxon.pull.PullSource; import net.sf.saxon.pull.StaxBridge; import net.sf.saxon.trans.SaxonErrorCode; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.Type; import net.sf.saxon.value.Whitespace; import org.xml.sax.*; import javax.xml.stream.XMLStreamReader; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamSource; import java.lang.reflect.Method; import java.util.List; /** * Sender is a helper class that sends events to a Receiver from any kind of Source object */ public abstract class Sender { // Converted to an abstract static class in Saxon 9.3 private static Class[] EMPTY_CLASS_ARRAY = new Class[0]; private static Class staxSourceClass; static { try { staxSourceClass = Class.forName("javax.xml.transform.stax.StAXSource"); } catch (Exception err) { // no action; if StAXSource isn't available then we don't use it. } } private Sender() {} /** * Send the contents of a Source to a Receiver. * @param source the source to be copied. Note that if the Source contains an InputStream * or Reader then it will be left open, unless it is an AugmentedSource with the pleaseCloseAfterUse * flag set. On the other hand, if it contains a URI that needs to be dereferenced to obtain * an InputStream, then the InputStream will be closed after use. * @param receiver the destination to which it is to be copied. The pipelineConfiguration * of this receiver must have been initialized. * @param options Parse options. If source is an AugmentedSource, any options set in the * AugmentedSource are used in preference to those set in options. If neither specifies * a particular option, the defaults from the Configuration are used. If null is supplied, * the parse options from the PipelineConfiguration of the receiver are used. * @throws net.sf.saxon.trans.XPathException if any error occurs */ public static void send(Source source, Receiver receiver, /*@Nullable*/ ParseOptions options) throws XPathException { PipelineConfiguration pipe = receiver.getPipelineConfiguration(); if (options == null) { options = new ParseOptions(pipe.getParseOptions()); } else { options = new ParseOptions(options); } boolean isFinal = options.isContinueAfterValidationErrors(); if (source instanceof AugmentedSource) { options.merge(((AugmentedSource)source).getParseOptions()); source = ((AugmentedSource)source).getContainedSource(); } Configuration config = pipe.getConfiguration(); options.applyDefaults(config); //receiver.setPipelineConfiguration(pipe); receiver.setSystemId(source.getSystemId()); Receiver next = receiver; int schemaValidation = options.getSchemaValidationMode(); if (isFinal) { // this ensures that the Validate command produces multiple error messages schemaValidation |= Validation.VALIDATE_OUTPUT; } SchemaType topLevelType = options.getTopLevelType(); List filters = options.getFilters(); if (filters != null) { for (int i=filters.size()-1; i>=0; i--) { ProxyReceiver filter = filters.get(i).makeFilter(next); filter.setSystemId(source.getSystemId()); next = filter; } } if (options.getStripSpace() == Whitespace.ALL) { next = new Stripper(AllElementsSpaceStrippingRule.getInstance(), receiver); } else if (options.getStripSpace() == Whitespace.XSLT) { Controller controller = pipe.getController(); if (controller != null) { next = controller.makeStripper(next); } } if (source instanceof NodeInfo) { NodeInfo ns = (NodeInfo)source; String baseURI = ns.getBaseURI(); int val = schemaValidation & Validation.VALIDATION_MODE_MASK; if (val != Validation.PRESERVE) { StructuredQName topLevelName = options.getTopLevelElement(); int topLevelNameCode = -1; if (topLevelName != null) { topLevelNameCode = config.getNamePool().allocate( topLevelName.getPrefix(), topLevelName.getURI(), topLevelName.getLocalPart()); } next = config.getDocumentValidator( next, baseURI, val, options.getStripSpace(), topLevelType, topLevelNameCode); } int kind = ns.getNodeKind(); if (kind != Type.DOCUMENT && kind != Type.ELEMENT) { throw new IllegalArgumentException("Sender can only handle document or element nodes"); } next.setSystemId(baseURI); sendDocumentInfo(ns, next); return; } else if (source instanceof PullSource) { sendPullSource((PullSource)source, next, options); return; } else if (source instanceof PullEventSource) { sendPullEventSource((PullEventSource)source, next, options); return; } else if (source instanceof EventSource) { ((EventSource)source).send(next); return; } else if (source instanceof Transmitter) { ((Transmitter)source).transmit(next); return; } else if (source instanceof SAXSource) { sendSAXSource((SAXSource)source, next, options); return; } else if (source instanceof StreamSource) { StreamSource ss = (StreamSource)source; // Following code allows the .NET platform to use a Pull parser boolean dtdValidation = options.getDTDValidationMode() == Validation.STRICT; Source ps = Configuration.getPlatform().getParserSource( pipe, ss, schemaValidation, dtdValidation, options.getStripSpace()); if (ps == ss) { String url = source.getSystemId(); InputSource is = new InputSource(url); is.setCharacterStream(ss.getReader()); is.setByteStream(ss.getInputStream()); boolean reuseParser = false; XMLReader parser = options.getXMLReader(); if (parser == null) { parser = config.getSourceParser(); if (options.getEntityResolver() != null && parser.getEntityResolver() == null) { parser.setEntityResolver(options.getEntityResolver()); } reuseParser = true; } //System.err.println("Using parser: " + parser.getClass().getName()); SAXSource sax = new SAXSource(parser, is); sax.setSystemId(source.getSystemId()); sendSAXSource(sax, next, options); if (reuseParser) { config.reuseSourceParser(parser); } } else { // the Platform substituted a different kind of source // On .NET with a default URIResolver we can expect an AugnmentedSource wrapping a PullSource send(ps, next, options); } return; } else if (staxSourceClass != null && staxSourceClass.isAssignableFrom(source.getClass())) { // Test for a StAXSource // Use reflection to avoid problems if JAXP 1.4 not installed XMLStreamReader reader = null; try { Method getReaderMethod = staxSourceClass.getMethod("getXMLStreamReader", EMPTY_CLASS_ARRAY); reader = (XMLStreamReader)getReaderMethod.invoke(source); } catch (Exception e) { // no action } //XMLStreamReader reader = ((StAXSource)source).getXMLStreamReader(); if (reader == null) { throw new XPathException("Saxon can only handle a StAXSource that wraps an XMLStreamReader"); } StaxBridge bridge = new StaxBridge(); bridge.setXMLStreamReader(reader); sendPullSource(new PullSource(bridge), next, options); return; } else { next = makeValidator(next, source.getSystemId(), options); // See if there is a registered SourceResolver than can handle it Source newSource = config.getSourceResolver().resolveSource(source, config); if (newSource instanceof StreamSource || newSource instanceof SAXSource || newSource instanceof Transmitter || newSource instanceof NodeInfo || newSource instanceof PullSource || newSource instanceof AugmentedSource || newSource instanceof EventSource) { send(newSource, next, options); } // See if there is a registered external object model that knows about this kind of source // (Note, this should pick up the platform-specific DOM model) List externalObjectModels = config.getExternalObjectModels(); for (Object externalObjectModel : externalObjectModels) { ExternalObjectModel model = (ExternalObjectModel) externalObjectModel; boolean done = model.sendSource(source, next); if (done) { return; } } } throw new XPathException("A source of type " + source.getClass().getName() + " is not supported in this environment"); } /** * Send a copy of a Saxon NodeInfo representing a document or element node to a receiver * @param top the root of the subtree to be send. Despite the method name, this can be a document * node or an element node * @param receiver the destination to receive the events * @throws XPathException if any error occurs */ private static void sendDocumentInfo(NodeInfo top, Receiver receiver) throws XPathException { PipelineConfiguration pipe = receiver.getPipelineConfiguration(); NamePool targetNamePool = pipe.getConfiguration().getNamePool(); if (top.getNamePool() != targetNamePool) { // This code allows a document in one Configuration to be copied to another, changing // namecodes as necessary receiver = new NamePoolConverter(receiver, top.getNamePool(), targetNamePool); } LocationCopier copier = new LocationCopier(top instanceof DocumentInfo); pipe.setComponent(CopyInformee.class.getName(), copier); pipe.setLocationProvider(copier); // start event stream receiver.open(); // copy the contents of the document receiver.startDocument(0); top.copy(receiver, (CopyOptions.ALL_NAMESPACES | CopyOptions.TYPE_ANNOTATIONS), 0); receiver.endDocument(); // end event stream receiver.close(); } /** * Send the contents of a SAXSource to a given Receiver * @param source the SAXSource * @param receiver the destination Receiver * @param options options for parsing the SAXSource * @throws XPathException if any failure occurs processing the Source object */ private static void sendSAXSource(SAXSource source, Receiver receiver, ParseOptions options) throws XPathException { PipelineConfiguration pipe = receiver.getPipelineConfiguration(); XMLReader parser = source.getXMLReader(); boolean reuseParser = false; final Configuration config = pipe.getConfiguration(); ErrorListener listener = options.getErrorListener(); if (listener == null) { listener = pipe.getErrorListener(); } ErrorHandler errorHandler = options.getErrorHandler(); if (errorHandler == null) { errorHandler = new StandardErrorHandler(listener); } if (parser==null) { parser = options.getXMLReader(); } if (parser==null) { SAXSource ss = new SAXSource(); ss.setInputSource(source.getInputSource()); ss.setSystemId(source.getSystemId()); parser = config.getSourceParser(); parser.setErrorHandler(errorHandler); if (options.getEntityResolver() != null && parser.getEntityResolver() == null) { parser.setEntityResolver(options.getEntityResolver()); } ss.setXMLReader(parser); source = ss; reuseParser = true; } else { // user-supplied parser: ensure that it meets the namespace requirements configureParser(parser); if (parser.getErrorHandler() == null) { parser.setErrorHandler(errorHandler); } } if (!pipe.isExpandAttributeDefaults()) { //TODO: put this in ParseOptions try { parser.setFeature("http://xml.org/sax/features/use-attributes2", true); } catch (SAXNotRecognizedException err) { // ignore the failure, we did our best (Xerces gives us an Attribute2 even though it // doesn't recognize this request!) } catch (SAXNotSupportedException err) { // ignore the failure, we did our best } } boolean dtdValidation = (options.getDTDValidationMode() == Validation.STRICT || options.getDTDValidationMode() == Validation.LAX); boolean dtdRecover = options.getDTDValidationMode() == Validation.LAX; try { parser.setFeature("http://xml.org/sax/features/validation", dtdValidation); } catch (SAXNotRecognizedException err) { if (dtdValidation) { throw new XPathException("XML Parser does not recognize request for DTD validation", err); } } catch (SAXNotSupportedException err) { if (dtdValidation) { throw new XPathException("XML Parser does not support DTD validation", err); } } boolean xInclude = options.isXIncludeAware(); if (xInclude) { boolean tryAgain = false; try { // This feature name is supported in the version of Xerces bundled with JDK 1.5 parser.setFeature("http://apache.org/xml/features/xinclude-aware", true); } catch (SAXNotRecognizedException err) { tryAgain = true; } catch (SAXNotSupportedException err) { tryAgain = true; } if (tryAgain) { try { // This feature name is supported in Xerces 2.9.0 parser.setFeature("http://apache.org/xml/features/xinclude", true); } catch (SAXNotRecognizedException err) { throw new XPathException("Selected XML parser " + parser.getClass().getName() + " does not recognize request for XInclude processing", err); } catch (SAXNotSupportedException err) { throw new XPathException("Selected XML parser " + parser.getClass().getName() + " does not support XInclude processing", err); } } } // if (config.isTiming()) { // System.err.println("Using SAX parser " + parser); // } receiver = makeValidator(receiver, source.getSystemId(), options); // Reuse the previous ReceivingContentHandler if possible (it contains a useful cache of names) ReceivingContentHandler ce; final ContentHandler ch = parser.getContentHandler(); if (ch instanceof ReceivingContentHandler && config.isCompatible(((ReceivingContentHandler)ch).getConfiguration())) { ce = (ReceivingContentHandler)ch; ce.reset(); } else { ce = new ReceivingContentHandler(); parser.setContentHandler(ce); parser.setDTDHandler(ce); try { parser.setProperty("http://xml.org/sax/properties/lexical-handler", ce); } catch (SAXNotSupportedException err) { // this just means we won't see the comments // ignore the error } catch (SAXNotRecognizedException err) { // ignore the error } } // TracingFilter tf = new TracingFilter(); // tf.setUnderlyingReceiver(receiver); // tf.setPipelineConfiguration(pipe); // receiver = tf; ce.setReceiver(receiver); ce.setPipelineConfiguration(pipe); try { parser.parse(source.getInputSource()); } catch (SAXException err) { Exception nested = err.getException(); if (nested instanceof XPathException) { throw (XPathException)nested; } else if (nested instanceof RuntimeException) { throw (RuntimeException)nested; } else { if (errorHandler instanceof StandardErrorHandler && ((StandardErrorHandler)errorHandler).getFatalErrorCount() == 0) { // The built-in parser for JDK 1.6 has a nasty habit of not notifying errors to the ErrorHandler XPathException de = new XPathException("Error reported by XML parser processing " + source.getSystemId() + ": " + err.getMessage(), err); try { listener.fatalError(de); de.setHasBeenReported(true); } catch (TransformerException e) { // } throw de; } else { XPathException de = new XPathException(err); de.setErrorCode(SaxonErrorCode.SXXP0003); de.setHasBeenReported(true); throw de; } } } catch (java.io.IOException err) { throw new XPathException("I/O error reported by XML parser processing " + source.getSystemId() + ": " + err.getMessage(), err); } if (errorHandler instanceof StandardErrorHandler) { int errs = ((StandardErrorHandler)errorHandler).getFatalErrorCount(); if (errs > 0) { throw new XPathException("The XML parser reported " + errs + (errs == 1 ? " error" : " errors")); } errs = ((StandardErrorHandler)errorHandler).getErrorCount(); if (errs > 0) { String message = ("The XML parser reported " + new Numberer_en().toWords(errs).toLowerCase() + " validation error" + (errs == 1 ? "" : "s")); if (dtdRecover) { message += ". Processing continues, because recovery from validation errors was requested"; try { listener.warning(new XPathException(message)); } catch (TransformerException e) { // } } else { throw new XPathException(message); } } } if (reuseParser) { config.reuseSourceParser(parser); } } private static Receiver makeValidator(Receiver receiver, String systemId, ParseOptions options) throws XPathException { PipelineConfiguration pipe = receiver.getPipelineConfiguration(); Configuration config = pipe.getConfiguration(); int schemaValidation = options.getSchemaValidationMode(); int sv = schemaValidation & Validation.VALIDATION_MODE_MASK; if (sv != Validation.PRESERVE && sv != Validation.DEFAULT) { Controller controller = pipe.getController(); if (controller != null && !controller.getExecutable().isSchemaAware() && (schemaValidation & Validation.VALIDATION_MODE_MASK) != Validation.STRIP) { throw new XPathException("Cannot use schema-validated input documents when the query/stylesheet is not schema-aware"); } // Add a document validator to the pipeline int stripSpace = options.getStripSpace(); SchemaType topLevelType = options.getTopLevelType(); StructuredQName topLevelElement = options.getTopLevelElement(); int topLevelElementCode = -1; if (topLevelElement != null) { topLevelElementCode = config.getNamePool().allocate( topLevelElement.getPrefix(), topLevelElement.getURI(), topLevelElement.getLocalPart()); } receiver = config.getDocumentValidator( receiver, systemId, schemaValidation, stripSpace, topLevelType, topLevelElementCode); } return receiver; } /** * Copy data from a pull source to a push destination * @param source the pull source * @param receiver the push destination * @param options provides options for schema validation * @throws XPathException if any error occurs */ private static void sendPullSource(PullSource source, Receiver receiver, ParseOptions options) throws XPathException { PipelineConfiguration pipe = receiver.getPipelineConfiguration(); boolean xInclude = options.isXIncludeAware(); if (xInclude) { throw new XPathException("XInclude processing is not supported with a pull parser"); } receiver = makeValidator(receiver, source.getSystemId(), options); PullProvider provider = source.getPullProvider(); if (provider instanceof LocationProvider) { pipe.setLocationProvider((LocationProvider)provider); } provider.setPipelineConfiguration(pipe); receiver.setPipelineConfiguration(pipe); PullPushCopier copier = new PullPushCopier(provider, receiver); try { copier.copy(); } finally { if (options.isPleaseCloseAfterUse()) { provider.close(); } } } private static void sendPullEventSource(PullEventSource source, Receiver receiver, ParseOptions options) throws XPathException { PipelineConfiguration pipe = receiver.getPipelineConfiguration(); boolean xInclude = options.isXIncludeAware(); if (xInclude) { throw new XPathException("XInclude processing is not supported with a pull parser"); } receiver = makeValidator(receiver, source.getSystemId(), options); receiver.open(); EventIterator provider = source.getEventIterator(); if (provider instanceof LocationProvider) { pipe.setLocationProvider((LocationProvider)provider); } receiver.setPipelineConfiguration(pipe); SequenceReceiver out = receiver instanceof SequenceReceiver ? ((SequenceReceiver)receiver) : new TreeReceiver(receiver); EventIteratorToReceiver.copy(provider, out); receiver.close(); } /** * Configure a SAX parser to ensure it has the correct namesapce properties set * @param parser the parser to be configured * @throws net.sf.saxon.trans.XPathException if the parser cannot be configured to the * required settings (namespaces=true, namespace-prefixes=false). Note that the SAX * specification requires every XMLReader to support these settings, so this error implies * that the XMLReader is non-conformant; this is not uncommon in cases where the XMLReader * is user-written. */ public static void configureParser(XMLReader parser) throws XPathException { try { parser.setFeature("http://xml.org/sax/features/namespaces", true); } catch (SAXNotSupportedException err) { // SAX2 parsers MUST support this feature! throw new XPathException( "The SAX2 parser " + parser.getClass().getName() + " does not recognize the 'namespaces' feature", err); } catch (SAXNotRecognizedException err) { throw new XPathException( "The SAX2 parser " + parser.getClass().getName() + " does not support setting the 'namespaces' feature to true", err); } try { parser.setFeature("http://xml.org/sax/features/namespace-prefixes", false); } catch (SAXNotSupportedException err) { // SAX2 parsers MUST support this feature! throw new XPathException( "The SAX2 parser "+ parser.getClass().getName() + " does not recognize the 'namespace-prefixes' feature", err); } catch (SAXNotRecognizedException err) { throw new XPathException( "The SAX2 parser " + parser.getClass().getName() + " does not support setting the 'namespace-prefixes' feature to false", err); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/SequenceWriter.java0000644000175000017500000003337711671711573025151 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.om.*; import net.sf.saxon.trans.Err; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.linked.LinkedTreeBuilder; import net.sf.saxon.tree.tiny.TinyBuilder; import net.sf.saxon.tree.tiny.TinyTree; import net.sf.saxon.tree.util.Orphan; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; /** * This outputter is used when writing a sequence of atomic values and nodes, for * example, when xsl:variable is used with content and an "as" attribute. The outputter * builds the sequence; the concrete subclass is responsible for deciding what to do with the * resulting items. * *

This class is not used to build temporary trees. For that, the ComplexContentOutputter * is used.

* * * @author Michael H. Kay */ public abstract class SequenceWriter extends SequenceReceiver { private Receiver outputter = null; private Builder builder = null; private int level = 0; private boolean inStartTag = false; public SequenceWriter(/*@NotNull*/ PipelineConfiguration pipe) { super(pipe); //System.err.println("SequenceWriter init"); } /** * Abstract method to be supplied by subclasses: output one item in the sequence. * @param item the item to be written to the sequence * @throws net.sf.saxon.trans.XPathException if any failure occurs while writing the item */ public abstract void write(Item item) throws XPathException; /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { if (outputter==null) { createTree(((properties & ReceiverOptions.MUTABLE_TREE) != 0)); } if (level++ == 0) { outputter.startDocument(properties); } } /** * Create a (skeletal) tree to hold a document or element node. * @param mutable set to true if the tree is required to support in-situ updates (other that the initial * sequential writing of nodes to construct the tree) * @throws net.sf.saxon.trans.XPathException if any error occurs while creating the tree */ private void createTree(boolean mutable) throws XPathException { PipelineConfiguration pipe = getPipelineConfiguration(); if (mutable) { TreeModel model = pipe.getController().getModel(); if (model.isMutable()) { builder = pipe.getController().makeBuilder(); } else { builder = new LinkedTreeBuilder(pipe); } } else { builder = pipe.getController().makeBuilder(); } builder.setPipelineConfiguration(pipe); builder.setSystemId(getSystemId()); builder.setTiming(false); NamespaceReducer reducer = new NamespaceReducer(builder); ComplexContentOutputter cco = new ComplexContentOutputter(pipe); cco.setHostLanguage(pipe.getHostLanguage()); 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() { if (builder instanceof TinyBuilder) { TinyTree tree = ((TinyBuilder)builder).getTree(); return tree != null && tree.getNumberOfNodes() < 20000; } else { return false; } } /** * 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, 0, NodeInfo.ALL_NAMESPACES); } previousAtomic = false; } /** * Output an element start tag. * @param elemName The element name code - a code held in the Name Pool * @param typeCode Integer code identifying the type of this element. Zero identifies the default * type, that is xs:anyType * @param properties bit-significant flags indicating any special information */ public void startElement(NodeName elemName, SchemaType typeCode, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } if (outputter==null) { createTree(((properties & ReceiverOptions.MUTABLE_TREE) != 0)); } //System.err.println("SEQUENCE_WRITER startElement " + this); outputter.startElement(elemName, typeCode, locationId, properties); level++; inStartTag = true; previousAtomic = false; } /** * Output an element end tag. */ public void endElement() throws XPathException { if (inStartTag) { startContent(); } //System.err.println("SEQUENCE_WRITER endElement " + this); outputter.endElement(); if (--level == 0) { outputter.close(); NodeInfo element = builder.getCurrentRoot(); append(element, 0, NodeInfo.ALL_NAMESPACES); } previousAtomic = false; } /** * Output a namespace declaration.
* 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 namespaceBinding The namespace binding * @param properties Allows special properties to be passed if required * @throws net.sf.saxon.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 namespaceBinding, int properties) throws XPathException { if (level == 0) { Orphan o = new Orphan(getConfiguration()); o.setNodeKind(Type.NAMESPACE); o.setNodeName(new NoNamespaceName(namespaceBinding.getPrefix())); o.setStringValue(namespaceBinding.getURI()); append(o, 0, NodeInfo.ALL_NAMESPACES); } else { outputter.namespace(namespaceBinding, properties); } previousAtomic = false; } /** * Output an attribute value.
* * * @param attName An integer code representing the name of the attribute, as held in the Name Pool * @param typeCode Integer code identifying the type annotation of the attribute; zero represents * the default type (xs:untypedAtomic) * @param value The value of the attribute * @param properties Bit significant flags for passing extra information to the serializer, e.g. * to disable escaping * @throws net.sf.saxon.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(NodeName attName, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (level == 0) { Orphan o = new Orphan(getConfiguration()); o.setNodeKind(Type.ATTRIBUTE); o.setNodeName(attName); o.setStringValue(value); o.setTypeAnnotation(typeCode); append(o, locationId, NodeInfo.ALL_NAMESPACES); } else { outputter.attribute(attName, typeCode, value, locationId, properties); } 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 net.sf.saxon.trans.XPathException for any failure */ public void startContent() throws XPathException { inStartTag = false; outputter.startContent(); previousAtomic = false; } /** * Produce text content output.
* @param s The String to be output * @param properties bit-significant flags for extra information, e.g. disable-output-escaping * @throws net.sf.saxon.trans.XPathException for any failure */ public void characters(CharSequence s, int locationId, int properties) throws XPathException { if (level == 0) { Orphan o = new Orphan(getConfiguration()); o.setNodeKind(Type.TEXT); o.setStringValue(s.toString()); append(o, locationId, NodeInfo.ALL_NAMESPACES); } else { if (s.length() > 0) { if (inStartTag) { startContent(); } outputter.characters(s, locationId, properties); } } previousAtomic = false; } /** * Write a comment. */ public void comment(CharSequence comment, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } if (level == 0) { Orphan o = new Orphan(getConfiguration()); o.setNodeKind(Type.COMMENT); o.setStringValue(comment); append(o, locationId, NodeInfo.ALL_NAMESPACES); } else { outputter.comment(comment, locationId, properties); } previousAtomic = false; } /** * Write a processing instruction * No-op in this implementation */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } if (level == 0) { Orphan o = new Orphan(getConfiguration()); o.setNodeName(new NoNamespaceName(target)); o.setNodeKind(Type.PROCESSING_INSTRUCTION); o.setStringValue(data); append(o, locationId, NodeInfo.ALL_NAMESPACES); } else { outputter.processingInstruction(target, data, locationId, properties); } 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(/*@Nullable*/ Item item, int locationId, 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(" ", 0, 0); } outputter.characters(item.getStringValueCS(), 0, 0); previousAtomic = true; } else if (item instanceof FunctionItem) { XPathException err = new XPathException("Cannot write a function item to an XML tree", "XPTY0004"); err.setLocator(getPipelineConfiguration().getSourceLocation(locationId)); throw err; } else { NodeInfo node = (NodeInfo)item; if (node.getNodeKind() == Type.ATTRIBUTE && ((SimpleType)node.getSchemaType()).isNamespaceSensitive()) { XPathException err = new XPathException("Cannot copy attributes whose type is namespace-sensitive (QName or NOTATION): " + Err.wrap(node.getDisplayName(), Err.ATTRIBUTE)); err.setErrorCode((getPipelineConfiguration().getHostLanguage() == Configuration.XSLT ? "XTTE0950" : "XQTY0086")); throw err; } ((NodeInfo)item).copy(outputter, (CopyOptions.ALL_NAMESPACES | CopyOptions.TYPE_ANNOTATIONS), locationId); previousAtomic = false; } } } /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation */ public boolean usesTypeAnnotations() { return outputter == null || outputter.usesTypeAnnotations(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/PIGrabber.java0000644000175000017500000001362311671711573023771 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.lib.StandardURIResolver; import net.sf.saxon.om.NodeName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.util.ProcInstParser; import net.sf.saxon.type.SchemaType; import javax.xml.transform.Source; import javax.xml.transform.TransformerException; import javax.xml.transform.URIResolver; import javax.xml.transform.sax.SAXSource; import java.util.ArrayList; import java.util.List; /** * The PIGrabber class is a Receiver that looks for xml-stylesheet processing * instructions and tests whether they match specified criteria; for those that do, it creates * an InputSource object referring to the relevant stylesheet * @author Michael H. Kay */ public class PIGrabber extends ProxyReceiver { private Configuration config = null; private String reqMedia = null; private String reqTitle = null; private String baseURI = null; private URIResolver uriResolver = null; private List stylesheets = new ArrayList(); private boolean terminated = false; public PIGrabber(Receiver next) { super(next); } public void setFactory(Configuration config) { this.config = config; } public void setCriteria(String media, String title) { this.reqMedia = media; this.reqTitle = title; } /** * Set the base URI * @param uri the base URI */ public void setBaseURI(String uri) { baseURI = uri; } /** * Set the URI resolver to be used for the href attribute * @param resolver the URI resolver */ public void setURIResolver(URIResolver resolver) { uriResolver = resolver; } /** * Abort the parse when the first start element tag is found */ public void startElement (NodeName namecode, SchemaType typecode, int locationId, int properties) throws XPathException { terminated = true; // abort the parse when the first start element tag is found throw new XPathException("#start#"); } /** * Determine whether the parse terminated because the first start element tag was found * @return true if the parse was terminated when the document element was encountered (as distinct * from being terminated because of some exception condition, for example a parse error) */ public boolean isTerminated() { return terminated; } /** * Handle xml-stylesheet PI */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (target.equals("xml-stylesheet")) { String value = data.toString(); String piMedia = ProcInstParser.getPseudoAttribute(value, "media"); String piTitle = ProcInstParser.getPseudoAttribute(value, "title"); String piType = ProcInstParser.getPseudoAttribute(value, "type"); String piAlternate = ProcInstParser.getPseudoAttribute(value, "alternate"); if (piType==null) return; // System.err.println("Found xml-stylesheet media=" + piMedia + " title=" + piTitle); if ( (piType.equals("text/xml") || piType.equals("application/xml") || piType.equals("text/xsl") || piType.equals("applicaton/xsl") || piType.equals("application/xml+xslt")) && (reqMedia==null || piMedia==null || reqMedia.equals(piMedia)) && ( ( piTitle==null && (piAlternate==null || piAlternate.equals("no"))) || ( reqTitle==null ) || ( piTitle!=null && piTitle.equals(reqTitle) ) ) ) { String href = ProcInstParser.getPseudoAttribute(value, "href"); if (href==null) { throw new XPathException("xml-stylesheet PI has no href attribute"); } // System.err.println("Adding " + href); if (piTitle==null && (piAlternate==null || piAlternate.equals("no"))) { stylesheets.add(0, href); } else { stylesheets.add(href); } } else { //System.err.println("No match on required media=" + reqMedia + " title=" + reqTitle ); } } } /** * Return list of stylesheets that matched, as an array of Source objects * @return null if there were no matching stylesheets. * @throws net.sf.saxon.trans.XPathException if a URI cannot be resolved */ /*@Nullable*/ public Source[] getAssociatedStylesheets() throws TransformerException { if (stylesheets.size()==0) { return null; } if (uriResolver==null) { uriResolver = new StandardURIResolver(config); } Source[] result = new Source[stylesheets.size()]; for (int i=0; i path = new Stack(); private Stack> siblingCounters = new Stack>(); public PathMaintainer(/*@NotNull*/ Receiver next) { super(next); siblingCounters.push(new HashMap()); } public void startElement (NodeName elemName, SchemaType type, int locationId, int properties) throws XPathException { // System.err.println("startElement " + nameCode); nextReceiver.startElement(elemName, type, locationId, properties); HashMap counters = siblingCounters.peek(); int index = 1; Integer preceding = counters.get(elemName); if (preceding != null) { index = preceding + 1; counters.put(elemName, index); } else { counters.put(elemName, 1); } path.push(new PathElement(elemName, index)); siblingCounters.push(new HashMap()); } /** * Handle an end-of-element event */ public void endElement () throws XPathException { nextReceiver.endElement(); siblingCounters.pop(); path.pop(); } /** * Get the path to the current location in the stream * @param useURIs set to true if namespace URIs are to appear in the path; * false if prefixes are to be used instead. The prefix will be the one * that is used in the source document, and is potentially ambiguous. * @return the path to the current location, as a string. */ public String getPath(boolean useURIs) { FastStringBuffer fsb = new FastStringBuffer(FastStringBuffer.MEDIUM); for (PathElement pe : path) { fsb.append('/'); if (useURIs) { String uri = pe.name.getURI(); if (uri.length()!=0) { fsb.append('"'); fsb.append(uri); fsb.append('"'); } } else { String prefix = pe.name.getPrefix(); if (prefix.length()!=0) { fsb.append(prefix); fsb.append(':'); } } fsb.append(pe.name.getLocalPart()); fsb.append('['); fsb.append(pe.index+""); fsb.append(']'); } return fsb.toString(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/SaxonLocator.java0000644000175000017500000000221211671711573024600 0ustar mathieumathieupackage net.sf.saxon.event; import org.xml.sax.Locator; import javax.xml.transform.SourceLocator; /** * SaxonLocator: this interface exists to unify the SAX Locator and JAXP SourceLocator interfaces, * which are identical. It extends both interfaces. Therefore, anything * that implements SaxonLocator can be used both in SAX and in JAXP interfaces. */ public interface SaxonLocator extends Locator, SourceLocator, LocationProvider {} // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/TracingFilter.java0000644000175000017500000002220111671711573024721 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamespaceBinding; import net.sf.saxon.om.NodeName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.util.FastStringBuffer; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; import net.sf.saxon.value.Whitespace; import java.io.PrintStream; /** * A filter that can be inserted into a Receiver pipeline to trace the events that pass through. * This class is not normally used in Saxon, but is available for diagnostics when needed. */ public class TracingFilter extends ProxyReceiver { private static int nextid = 0; private int id; private String indent = ""; private PrintStream out = System.err; /** * Create a TracingFilter and allocate a unique Id. * @param nextReceiver the underlying receiver to which the events will be sent */ public TracingFilter(Receiver nextReceiver) { super(nextReceiver); id = nextid++; } /** * Create a TracingFilter, allocate a unique Id, and supply the destination for diagnostic * trace messages * @param nextReceiver the underlying receiver to which the events will be sent * @param diagnosticOutput the destination for diagnostic trace messages */ public TracingFilter(Receiver nextReceiver, PrintStream diagnosticOutput) { super(nextReceiver); id = nextid++; out = diagnosticOutput; } /** * Get the unique id that was allocated to this TracingFilter * @return the unique id (which is included in all diagnostic messages) */ public int getId() { return id; } /** * Append an arbitrary item (node or atomic value) to the output * * @param item the item to be appended * @param locationId the location of the calling instruction, for diagnostics * @param copyNamespaces if the item is an element node, this indicates whether its namespaces * need to be copied. Values are {@link net.sf.saxon.om.NodeInfo#ALL_NAMESPACES}, * {@link net.sf.saxon.om.NodeInfo#LOCAL_NAMESPACES}, {@link net.sf.saxon.om.NodeInfo#NO_NAMESPACES} */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { out.println("RCVR " + id + indent + " APPEND " + item.getClass().getName()); if (nextReceiver instanceof SequenceReceiver) { ((SequenceReceiver)nextReceiver).append(item, locationId, copyNamespaces); } else { super.append(item, locationId, copyNamespaces); } } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
DISABLE_ESCAPING
Disable escaping for this attribute
*
NO_SPECIAL_CHARACTERS
Attribute value contains no special characters
* @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(NodeName nameCode, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { out.println("RCVR " + id + indent + " ATTRIBUTE " + nameCode.getDisplayName()); nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { out.println("RCVR " + id + indent + " CHARACTERS " + (Whitespace.isWhite(chars) ? "(whitespace)" : "")); FastStringBuffer sb = new FastStringBuffer(chars.length() * 3); for (int i=0; iafter
the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceBinding the namespace (prefix, uri) pair to be notified * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException { out.println("RCVR " + id + indent + " NAMESPACE " + namespaceBinding.getPrefix() + "=" + namespaceBinding.getURI()); nextReceiver.namespace(namespaceBinding, properties); } /** * Start of event stream */ public void open() throws XPathException { out.println("RCVR " + id + indent + " OPEN"); nextReceiver.open(); } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { out.println("RCVR " + id + indent + " PROCESSING INSTRUCTION"); nextReceiver.processingInstruction(target, data, locationId, properties); } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { out.println("RCVR " + id + indent + " START CONTENT"); nextReceiver.startContent(); } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { out.println("RCVR " + id + indent + " START DOCUMENT"); nextReceiver.startDocument(properties); } /** * Notify the start of an element * * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties properties of the element node */ public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { out.println("RCVR " + id + indent + " START ELEMENT " + nameCode.getDisplayName()); // out.println("RCVR " + id + indent + // " (Loc: sysId=" + // getPipelineConfiguration().getLocationProvider().getSystemId(locationId) + // " line=" + // getPipelineConfiguration().getLocationProvider().getLineNumber(locationId) + ")"); indent = indent + " "; nextReceiver.startElement(nameCode, typeCode, locationId, properties); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/SequenceCopier.java0000644000175000017500000000264211671711573025105 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; /** * Copies a sequence, supplied as a SequenceIterator, to a push pipeline, represented by * a SequenceReceiver */ public class SequenceCopier { private SequenceCopier() { } public static void copySequence(SequenceIterator in, SequenceReceiver out) throws XPathException { out.open(); while (true) { Item item = in.next(); if (item == null) { break; } out.append(item, 0, NodeInfo.ALL_NAMESPACES); } out.close(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/StartTagBuffer.java0000644000175000017500000004075511671711573025065 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.util.AttributeCollectionImpl; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; import net.sf.saxon.type.Type; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * StartTagBuffer is a ProxyReceiver that buffers attributes and namespace events within a start tag. * It maintains details of the namespace context, and a full set of attribute information, on behalf * of other filters that need access to namespace information or need to process attributes in arbitrary * order. * *

StartTagBuffer also implements namespace fixup (the process of creating namespace nodes|bindings on behalf * of constructed element and attribute nodes). Although this would be done anyway, further down the pipeline, * it has to be done early in the case of a validating pipeline, because the namespace bindings must be created * before any namespace-sensitive attribute content is validated.

* *

The StartTagBuffer also allows error conditions to be buffered. This is because the XSIAttributeHandler * validates attributes such as xsi:type and xsi:nil before attempting to match its parent element against * a particle of its containing type. It is possible that the parent element will match a wildcard particle * with processContents="skip", in which case an invalid xsi:type or xsi:nil attribute is not an error.

*/ public class StartTagBuffer extends ProxyReceiver implements NamespaceResolver { public StartTagBuffer(Receiver next) { super(next); } // Details of the pending element event protected NodeName elementNameCode; protected SchemaType elementTypeCode; protected int elementLocationId; protected int elementProperties; // Details of pending attribute events protected AttributeCollectionImpl bufferedAttributes; private boolean acceptAttributes; private boolean inDocument; // We keep track of namespaces. The namespaces // array holds a list of all namespaces currently declared (organised as pairs of entries, // prefix followed by URI). The stack contains an entry for each element currently open; the // value on the stack is an Integer giving the number of namespaces added to the main // namespace stack by that element. protected NamespaceBinding[] namespaces = new NamespaceBinding[50]; // all namespaces currently declared protected int namespacesSize = 0; // all namespaces currently declared private int[] countStack = new int[50]; private int depth = 0; private int attCount = 0; /** * Set the pipeline configuration * @param pipe the pipeline configuration */ public void setPipelineConfiguration(/*@NotNull*/ PipelineConfiguration pipe) { super.setPipelineConfiguration(pipe); bufferedAttributes = new AttributeCollectionImpl(pipe.getConfiguration()); } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { // a document node in the content sequence of an element is ignored. However, we need // to stop attributes being created within the document node. if (depth == 0) { depth++; super.startDocument(properties); } acceptAttributes = false; inDocument = true; // we ought to clear this on endDocument, but it only affects diagnostics } /** * Notify the end of a document node */ public void endDocument() throws XPathException { if (depth == 1) { depth--; super.endDocument(); } } /** * startElement */ public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { elementNameCode = nameCode; elementTypeCode = typeCode; elementLocationId = locationId; elementProperties = properties; bufferedAttributes.clear(); // Record the current height of the namespace list so it can be reset at endElement time countStack[depth] = 0; if (++depth >= countStack.length) { int[] newstack = new int[depth*2]; System.arraycopy(countStack, 0, newstack, 0, depth); countStack = newstack; } // Ensure that the element namespace is output, unless this is done // automatically by the caller (which is true, for example, for a literal // result element). acceptAttributes = true; inDocument = false; if ((properties & ReceiverOptions.NAMESPACE_OK) == 0) { namespace(nameCode.getNamespaceBinding(), 0); } attCount = 0; } public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException { if (!acceptAttributes) { throw NoOpenStartTagException.makeNoOpenStartTagException( Type.NAMESPACE, namespaceBinding.getPrefix(), getPipelineConfiguration().getHostLanguage(), inDocument, false, null, -1); } // avoid duplicates for (int n=0; nDISABLE_ESCAPING
Disable escaping for this attribute
*
NO_SPECIAL_CHARACTERS
Attribute value contains no special characters
* @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(NodeName attName, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (!acceptAttributes) { throw NoOpenStartTagException.makeNoOpenStartTagException( Type.ATTRIBUTE, attName.getDisplayName(), getPipelineConfiguration().getHostLanguage(), inDocument, false, null, -1); } // Perform namespace fixup for the attribute if (((properties & ReceiverOptions.NAMESPACE_OK) == 0) && !attName.isInNamespace("")) { // non-null prefix attName = checkProposedPrefix(attName, attCount++); } bufferedAttributes.addAttribute(attName, typeCode, value.toString(), locationId, properties); // Note: we're relying on the fact that AttributeCollection can hold two attributes of the same name // and maintain their order, because the check for duplicate attributes is not done until later in the // pipeline. We validate both the attributes (see Bugzilla #4600 which legitimizes this.) } /** * Add a namespace declaration (or undeclaration) to the stack * @param binding the namespace binding for the declaration */ private void addToStack(NamespaceBinding binding) { // expand the stack if necessary if (namespacesSize+1 >= namespaces.length) { NamespaceBinding[] newlist = new NamespaceBinding[namespacesSize*2]; System.arraycopy(namespaces, 0, newlist, 0, namespacesSize); namespaces = newlist; } namespaces[namespacesSize++] = binding; } /** * startContent: Add any namespace undeclarations needed to stop * namespaces being inherited from parent elements */ public void startContent() throws XPathException { nextReceiver.startElement(elementNameCode, elementTypeCode, elementLocationId, elementProperties | ReceiverOptions.NAMESPACE_OK); declareNamespacesForStartElement(); final int length = bufferedAttributes.getLength(); for (int i=0; i 0; } /** * Get the value of the current attribute with a given nameCode * @param nameCode the name of the required attribute * @return the attribute value, or null if the attribute is not present */ public String getAttribute(int nameCode) { return bufferedAttributes.getValueByFingerprint(nameCode & 0xfffff); } /** * Get all the attributes on the current element start tag * @return an AttributeCollection containing all the attributes */ public AttributeCollection getAllAttributes() { return bufferedAttributes; } /** * Get the namespace URI corresponding to a given prefix. Return null * if the prefix is not in scope. f * * @param prefix the namespace prefix * @param useDefault true if the default namespace is to be used when the * prefix is "" * @return the uri for the namespace, or null if the prefix is not in scope */ /*@Nullable*/ public String getURIForPrefix(String prefix, boolean useDefault) { if (prefix.length()==0 && !useDefault) { return NamespaceConstant.NULL; } else if ("xml".equals(prefix)) { return NamespaceConstant.XML; } else { for (int i=namespacesSize-1; i>=0; i--) { if (namespaces[i].getPrefix().equals(prefix)) { String uri = namespaces[i].getURI(); if (uri.length()==0) { // // we've found a namespace undeclaration, so it's as if the prefix weren't there at all } else { return uri; } } } } return (prefix.length()==0 ? NamespaceConstant.NULL : null); } /** * Get an iterator over all the prefixes declared in this namespace context. This will include * the default namespace (prefix="") and the XML namespace where appropriate */ public Iterator iteratePrefixes() { List prefixes = new ArrayList(namespacesSize); for (int i=namespacesSize-1; i>=0; i--) { String prefix = namespaces[i].getPrefix(); if (!prefixes.contains(prefix)) { prefixes.add(prefix); } } prefixes.add("xml"); return prefixes.iterator(); } /** * Check that the prefix for an element or attribute is acceptable, allocating a substitute * prefix if not. The prefix is acceptable unless a namespace declaration has been * written that assignes this prefix to a different namespace URI. This method * also checks that the element or attribute namespace has been declared, and declares it * if not. * @param nameCode the proposed element or attribute name * @param seq sequence number of attribute, used for generating distinctive prefixes * @return the actual allocated name, which may be different. * @throws net.sf.saxon.trans.XPathException if any error occurs writing the new namespace binding */ private NodeName checkProposedPrefix(NodeName nameCode, int seq) throws XPathException { NamespaceBinding binding = nameCode.getNamespaceBinding(); String prefix = binding.getPrefix(); String existingURI = getURIForPrefix(prefix, true); if (existingURI == null) { // prefix has not been declared: declare it now (namespace fixup) namespace(binding, 0); return nameCode; } else { if (binding.getURI().equals(existingURI)) { // prefix is already bound to this URI return nameCode; // all is well } else { // conflict: prefix is currently bound to a different URI prefix = getSubstitutePrefix(binding, seq); NodeName newCode = new FingerprintedQName( prefix, nameCode.getURI(), nameCode.getLocalPart()); namespace(newCode.getNamespaceBinding(), 0); return newCode; } } } /** * It is possible for a single output element to use the same prefix to refer to different * namespaces. In this case we have to generate an alternative prefix for uniqueness. The * one we generate is based on the sequential position of the element/attribute: this is * designed to ensure both uniqueness (with a high probability) and repeatability * @param binding the namespace binding of the proposed element or attribute name * @param seq sequence number of attribute, used for generating distinctive prefixes * @return the actual allocated name, which may be different. */ private String getSubstitutePrefix(NamespaceBinding binding, int seq) { String prefix = binding.getPrefix(); return prefix + '_' + seq; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): // saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/Sink.java0000644000175000017500000001413111671711573023073 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamespaceBinding; import net.sf.saxon.om.NodeName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; /** * A Sink is an Receiver that discards all information passed to it */ public class Sink extends SequenceReceiver { public Sink(PipelineConfiguration pipe) { super(pipe); } /** * Start of event stream */ public void open() throws XPathException { } /** * End of event stream */ public void close() throws XPathException { } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { } /** * Notify the end of a document node */ public void endDocument() throws XPathException { } /** * Notify the start of an element * * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties for future use. Should be set to zero. */ public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceBinding the prefix/uri pair representing the namespace binding to be written * @throws java.lang.IllegalStateException: * attempt to output a namespace when there is no open element * start tag */ public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException { } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
DISABLE_ESCAPING
Disable escaping for this attribute
*
NO_SPECIAL_CHARACTERS
Attribute value contains no special characters
* @throws java.lang.IllegalStateException: * attempt to output an attribute when there is no open element * start tag */ public void attribute(NodeName nameCode, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { } /** * End of element */ public void endElement() throws XPathException { } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { } /** * Append an arbitrary item (node or atomic value) to the output * * @param item the item to be appended * @param locationId the location of the calling instruction, for diagnostics * @param copyNamespaces if the item is an element node, this indicates whether its namespaces * need to be copied. Values are {@link net.sf.saxon.om.NodeInfo#ALL_NAMESPACES}, * {@link net.sf.saxon.om.NodeInfo#LOCAL_NAMESPACES}, {@link net.sf.saxon.om.NodeInfo#NO_NAMESPACES} */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { } /** * Set the URI for an unparsed entity in the document. */ public void setUnparsedEntity(String name, String uri, String publicId) throws XPathException { } /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation */ public boolean usesTypeAnnotations() { return false; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/ReceiverOptions.java0000644000175000017500000001014311671711573025306 0ustar mathieumathieupackage net.sf.saxon.event; /** * ReceiverOptions defines a set of constants, which can be used in * calls to methods on the Receiver interface. The values are * bit-significant. * * @author Michael H. Kay */ public class ReceiverOptions { /** * Flag to disable output escaping */ public static final int DISABLE_ESCAPING = 1; /** * Flag to disable use of character maps */ public static final int DISABLE_CHARACTER_MAPS = 2; /** * Flag indicating that the value contains no special characters * that need to be escaped */ public static final int NO_SPECIAL_CHARS = 4; /** * Flag indicating that an attribute value was added by the schema processor * because a default value was specified */ public static final int DEFAULTED_ATTRIBUTE = 8; /** * Flag used with character content that has been validated against a nillable element * declaration. Needed because of a peculiar rule for validating xs:key values */ public static final int NILLED_ELEMENT = 16; /** * Flag indicating that duplicate values should be rejected */ public static final int REJECT_DUPLICATES = 32; /** * Flag indicating that the namespace (of an element or attribute name) * has already been declared; it does not need to be generated by the namespace * fixup process. */ public static final int NAMESPACE_OK = 64; /** * Flag passed on startElement indicating that the element does not inherit * the namespaces of its ancestors. */ public static final int DISINHERIT_NAMESPACES = 128; /** * Flag used when an attribute value or text node contains null characters * before and after strings generated by character mapping; these strings * are to be output without escaping */ public static final int USE_NULL_MARKERS = 256; /** * Flag used with character content that has been validated against a nillable element * declaration. Needed because of a peculiar rule for validating xs:key values */ public static final int NILLABLE_ELEMENT = 512; /** * Flag used with the characters() event to indicate that the event represents an entire * text node, that is, the text node has not been fragmented over several characters() events */ public static final int WHOLE_TEXT_NODE = 1024; /** * Flag indicating an element or attribute that has the is-id property */ public static final int IS_ID = 2048; /** * Flag indicating an element or attribute that has the is-idref property (indicating that it is an IDREF * or IDREFS attribute) */ public static final int IS_IDREF = 4096; /** * Flag indicating that the ID/IDREF properties have been set if applicable: if this bit is set, * then the absence of the IS_ID bit means the node is not an ID, and similarly for IS_IDREF */ public static final int ID_IDREF_CHECKED = 8192; /** * Flag set on startDocument() in relation to an xsl:message call with terminate="yes" */ public static final int TERMINATE = 16384; /** * Flag set on startDocument() to indicate that the constructed document must be updateable */ public static final int MUTABLE_TREE = 32768; } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/NoOpenStartTagException.java0000644000175000017500000001131511671711573026717 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.lib.StandardErrorListener; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.Type; /** * Exception indicating that an attribute or namespace node has been written when * there is no open element to write it to */ public class NoOpenStartTagException extends XPathException { /** * Static factory method to create the exception * @param nodeKind the kind of node being created (attribute or namespace) * @param name the name of the node being created * @param hostLanguage XSLT or XQuery (error codes are different in the two cases) * @param parentIsDocument true if the nodes are being added to a document node (rather than an element) * @param isSerializing true if the document is being created in the process of serialization * @param locationProvider Object to provide location information for diagnostics * @param startElementLocationId integer that can be passed to the location provider to get the location * of the offending instruction that created the element node * @return the constructed exception object */ public static NoOpenStartTagException makeNoOpenStartTagException( int nodeKind, String name, int hostLanguage, boolean parentIsDocument, boolean isSerializing, /*@Nullable*/ final LocationProvider locationProvider, int startElementLocationId) { String message; String errorCode; if (parentIsDocument) { if (isSerializing) { String kind = (nodeKind == Type.ATTRIBUTE ? "attribute" : "namespace"); message = "Cannot serialize a free-standing " + kind + " node (" + name + ')'; errorCode = "SENR0001"; } else { String kind = (nodeKind == Type.ATTRIBUTE ? "an attribute" : "a namespace"); message = "Cannot create " + kind + " node (" + name + ") whose parent is a document node"; errorCode = (hostLanguage == Configuration.XSLT ? "XTDE0420" : "XPTY0004"); } } else { String kind = (nodeKind == Type.ATTRIBUTE ? "An attribute" : "A namespace"); message = kind + " node (" + name + ") cannot be created after a child of the containing element"; errorCode = (hostLanguage == Configuration.XSLT ? "XTDE0410" : "XQTY0024"); } if (locationProvider != null && startElementLocationId > 0) { message += ". Most recent element start tag was output at line " + locationProvider.getLineNumber(startElementLocationId) + " of module " + StandardErrorListener.abbreviatePath(locationProvider.getSystemId(startElementLocationId)); } NoOpenStartTagException err = new NoOpenStartTagException(message); err.setErrorCode(errorCode); return err; } public NoOpenStartTagException(String message) { super(message); } // public NoOpenStartTagException(int nodeKind, String name, int hostLanguage, boolean topLevel, boolean isSerializing) { // // The contorted conditional here is because super() has to be at the start of the method // super((topLevel ? // (isSerializing ? // "Cannot serialize ") // ("Cannot create " + // (nodeKind==Type.ATTRIBUTE ? "an attribute" : "a namespace") + // " node (" + name + ") whose parent is a document node") // : // (nodeKind==net.sf.saxon.type.Type.ATTRIBUTE ? "An attribute" : "A namespace") + // " node (" + name + ") cannot be created after the children of the containing element" // )); // if (hostLanguage == Configuration.XSLT) { // setErrorCode(topLevel ? "XTDE0420" : "XTDE0410"); // } else { // setErrorCode(topLevel ? "XPTY0004" : "XQTY0024"); // } // } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/TreeReceiver.java0000644000175000017500000003120511671711573024554 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; /** * A TreeReceiver acts as a bridge between a SequenceReceiver, which can receive * events for constructing any kind of sequence, and an ordinary Receiver, which * only handles events relating to the building of trees. To do this, it has to * process any items added to the sequence using the append() interface; all other * events are passed through unchanged. * *

If atomic items are appended to the sequence, then adjacent atomic items are * turned in to a text node by converting them to strings and adding a single space * as a separator.

* *

If a document node is appended to the sequence, then the document node is ignored * and its children are appended to the sequence.

* *

If any other node is appended to the sequence, then it is pushed to the result * as a sequence of Receiver events, which may involve walking recursively through the * contents of a tree.

*/ public class TreeReceiver extends SequenceReceiver { private Receiver nextReceiver; private int level = 0; private boolean[] isDocumentLevel = new boolean[20]; // The sequence of events can include startElement/endElement pairs or startDocument/endDocument // pairs at any level. A startDocument/endDocument pair is essentially ignored except at the // outermost level, except that a namespace or attribute node cannot be sent when we're at a // document level. See for example schema90963-err.xsl private boolean inStartTag = false; /** * Create a TreeReceiver * @param nextInChain the receiver to which events will be directed, after * expanding append events into more primitive tree-based events */ public TreeReceiver(/*@NotNull*/ Receiver nextInChain) { super(nextInChain.getPipelineConfiguration()); nextReceiver = nextInChain; previousAtomic = false; setPipelineConfiguration(nextInChain.getPipelineConfiguration()); } public void setSystemId(String systemId) { if (systemId != null && !systemId.equals(this.systemId)) { this.systemId = systemId; if (nextReceiver != null) { nextReceiver.setSystemId(systemId); } } } public void setPipelineConfiguration(/*@NotNull*/ PipelineConfiguration pipe) { if (pipelineConfiguration != pipe) { pipelineConfiguration = pipe; if (nextReceiver != null) { nextReceiver.setPipelineConfiguration(pipe); } } } /** * Get the underlying Receiver (that is, the next one in the pipeline) * @return the underlying Receiver */ public Receiver getUnderlyingReceiver() { return nextReceiver; } /** * Start of event sequence */ public void open() throws XPathException { if (nextReceiver == null) { throw new IllegalStateException("TreeReceiver.open(): no underlying receiver provided"); } nextReceiver.open(); previousAtomic = false; } /** * End of event sequence */ public void close() throws XPathException { if (nextReceiver != null) { nextReceiver.close(); } previousAtomic = false; } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { if (level == 0) { nextReceiver.startDocument(properties); } if (isDocumentLevel.length - 1 < level) { boolean[] d2 = new boolean[level*2]; System.arraycopy(isDocumentLevel, 0, d2, 0, level); isDocumentLevel = d2; } isDocumentLevel[level++] = true; } /** * Notify the end of a document node */ public void endDocument() throws XPathException { level--; if (level == 0) { nextReceiver.endDocument(); } } /** * Notify the start of an element * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties bit-significant properties of the element node */ public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } inStartTag = true; nextReceiver.startElement(nameCode, typeCode, locationId, properties); previousAtomic = false; if (isDocumentLevel.length - 1 < level) { boolean[] d2 = new boolean[level*2]; System.arraycopy(isDocumentLevel, 0, d2, 0, level); isDocumentLevel = d2; } isDocumentLevel[level++] = false; } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * @param namespaceBinding the prefix/uri pair * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException { boolean documentLevel = level==0 || isDocumentLevel[level-1]; if (documentLevel || !inStartTag) { throw NoOpenStartTagException.makeNoOpenStartTagException( Type.NAMESPACE, namespaceBinding.getPrefix(), getPipelineConfiguration().getHostLanguage(), documentLevel, getPipelineConfiguration().isSerializing(), null, -1); } nextReceiver.namespace(namespaceBinding, properties); previousAtomic = false; } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
DISABLE_ESCAPING
Disable escaping for this attribute
*
NO_SPECIAL_CHARACTERS
Attribute value contains no special characters
* @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(NodeName nameCode, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { boolean documentLevel = level==0 || isDocumentLevel[level-1]; if (documentLevel || !inStartTag) { throw NoOpenStartTagException.makeNoOpenStartTagException( Type.ATTRIBUTE, nameCode.getDisplayName(), getPipelineConfiguration().getHostLanguage(), documentLevel, getPipelineConfiguration().isSerializing(), null, -1); } nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); previousAtomic = false; } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { inStartTag = false; nextReceiver.startContent(); previousAtomic = false; } /** * End of element */ public void endElement() throws XPathException { if (inStartTag) { startContent(); } nextReceiver.endElement(); previousAtomic = false; level--; } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (chars.length() > 0) { if (inStartTag) { startContent(); } nextReceiver.characters(chars, locationId, properties); } previousAtomic = false; } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } nextReceiver.processingInstruction(target, data, locationId, properties); previousAtomic = false; } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { if (inStartTag) { startContent(); } nextReceiver.comment(chars, locationId, properties); previousAtomic = false; } /** * Set the URI for an unparsed entity in the document. */ public void setUnparsedEntity(String name, String uri, String publicId) throws XPathException { nextReceiver.setUnparsedEntity(name, uri, publicId); } /** * Append an arbitrary item (node or atomic value) to the output */ public void append(/*@Nullable*/ Item item, int locationId, int copyNamespaces) throws XPathException { if (item != null) { if (item instanceof AtomicValue) { if (previousAtomic) { characters(" ", locationId, 0); } characters(item.getStringValueCS(), locationId, 0); previousAtomic = true; } else if (item instanceof FunctionItem) { throw new XPathException("Cannot add a function item to a tree"); } else if (((NodeInfo)item).getNodeKind() == Type.DOCUMENT) { startDocument(0); // needed to ensure that illegal namespaces or attributes in the content are caught SequenceIterator iter = ((NodeInfo)item).iterateAxis(Axis.CHILD); while (true) { Item it = iter.next(); if (it == null) break; append(it, locationId, copyNamespaces); } previousAtomic = false; endDocument(); } else { int copyOptions = CopyOptions.TYPE_ANNOTATIONS; if (copyNamespaces == NodeInfo.LOCAL_NAMESPACES) { copyOptions |= CopyOptions.LOCAL_NAMESPACES; } else if (copyNamespaces == NodeInfo.ALL_NAMESPACES) { copyOptions |= CopyOptions.ALL_NAMESPACES; } ((NodeInfo)item).copy(this, copyOptions, locationId); previousAtomic = false; } } } /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation */ public boolean usesTypeAnnotations() { return nextReceiver.usesTypeAnnotations(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/PipelineConfiguration.java0000644000175000017500000003117611777633456026506 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.expr.parser.ExpressionLocation; import net.sf.saxon.lib.ParseOptions; import net.sf.saxon.lib.SchemaURIResolver; import javax.xml.transform.ErrorListener; import javax.xml.transform.SourceLocator; import javax.xml.transform.URIResolver; import java.util.HashMap; import java.util.Map; /** * A PipelineConfiguration sets options that apply to all the operations in a pipeline. * Unlike the global Configuration, these options are always local to a process. */ public class PipelineConfiguration { /*@NotNull*/ private Configuration config; private LocationProvider locationProvider; private URIResolver uriResolver; private SchemaURIResolver schemaURIResolver; private Controller controller; private ParseOptions parseOptions; private boolean isSerializing; private int hostLanguage = Configuration.XSLT; private Map components; //private CopyInformee copyInformee = null; /** * Create a PipelineConfiguration. Note: the normal way to create * a PipelineConfiguration is via the factory methods in the Controller and * Configuration classes * * @param config the Saxon configuration * @see Configuration#makePipelineConfiguration * @see Controller#makePipelineConfiguration */ public PipelineConfiguration(/*@NotNull*/ Configuration config) { this.config = config; parseOptions = new ParseOptions(); } /** * Create a PipelineConfiguration as a copy of an existing * PipelineConfiguration * * @param p the existing PipelineConfiguration */ public PipelineConfiguration(PipelineConfiguration p) { config = p.config; locationProvider = p.locationProvider; uriResolver = p.uriResolver; schemaURIResolver = p.schemaURIResolver; controller = p.controller; isSerializing = p.isSerializing; parseOptions = new ParseOptions(p.parseOptions); hostLanguage = p.hostLanguage; if (p.components != null) { components = new HashMap(p.components); } } /** * Get the Saxon Configuration object * * @return the Saxon Configuration */ /*@NotNull*/ public Configuration getConfiguration() { return config; } /** * Set the Saxon Configuration object * * @param config the Saxon Configuration */ public void setConfiguration(/*@NotNull*/ Configuration config) { this.config = config; } /** * Get the LocationProvider for interpreting location ids passed down this pipeline * * @return the appropriate LocationProvider */ public LocationProvider getLocationProvider() { if (locationProvider == null) { locationProvider = DummyLocationProvider.THE_INSTANCE; } return locationProvider; } /** * Set the LocationProvider for interpreting location ids passed down this pipeline * * @param locationProvider the LocationProvider */ public void setLocationProvider(LocationProvider locationProvider) { this.locationProvider = locationProvider; } /** * Get a SourceLocator for a given locationId, using this location provider * * @param locationId an integer identifier for a source location * @return an object holding location information */ public SourceLocator getSourceLocation(long locationId) { return new ExpressionLocation(locationProvider, locationId); } /** * Get the ErrorListener set as a property of this pipeline * * @return the ErrorListener; null if none has been set. */ public ErrorListener getLocalErrorListener() { return parseOptions.getErrorListener(); } /** * Get an ErrorListener for reporting errors in processing this pipeline; this * will be the ErrorListener set locally in the PipelineConfiguration if there is one, * or the ErrorListener from the Configuration otherwise. * * @return the ErrorListener to be used; never null */ public ErrorListener getErrorListener() { ErrorListener listener = parseOptions.getErrorListener(); if (listener == null) { listener = config.getErrorListener(); } return listener; } /** * Set the ErrorListener used for reporting errors in processing this pipeline * * @param errorListener the ErrorListener */ public void setErrorListener(ErrorListener errorListener) { parseOptions.setErrorListener(errorListener); } /** * Get the URIResolver used for processing URIs encountered on this pipeline * * @return the URIResolver */ public URIResolver getURIResolver() { return uriResolver; } /** * Set the URIResolver used for processing URIs encountered on this pipeline * * @param uriResolver the URIResolver */ public void setURIResolver(URIResolver uriResolver) { this.uriResolver = uriResolver; } /** * Get the user-defined SchemaURIResolver for resolving URIs used in "import schema" * declarations; returns null if none has been explicitly set. * * @return the SchemaURIResolver */ public SchemaURIResolver getSchemaURIResolver() { return schemaURIResolver; } /** * Set the document parsing and building options to be used on this pipeline * * @param options the options to be used */ public void setParseOptions(ParseOptions options) { parseOptions = options; } /** * Get the document parsing and building options to be used on this pipeline * return the options to be used * * @return the parser options for this pipeline */ public ParseOptions getParseOptions() { return parseOptions; } /** * Say whether xsi:schemaLocation and xsi:noNamespaceSchemaLocation attributes * should be recognized while validating an instance document * * @param recognize true if these attributes should be recognized */ public void setUseXsiSchemaLocation(boolean recognize) { parseOptions.setUseXsiSchemaLocation(recognize); } /** * Say whether validation errors encountered on this pipeline should be treated as fatal * or as recoverable. *

Note this is a shortcut for getParseOptions().setContinueAfterValidationErrors(), retained * for backwards compatibility.

* * @param recover set to true if validation errors are to be treated as recoverable. If this option is set to true, * such errors will be reported to the ErrorListener using the error() method, and validation will continue. * If it is set to false, errors will be reported using the fatalError() method, and validation will * be abandoned. The default depends on the circumstances: typically during standalone instance validation * the default is true, but during XSLT and XQuery processing it is false. */ public void setRecoverFromValidationErrors(boolean recover) { parseOptions.setContinueAfterValidationErrors(recover); } /** * Ask if this pipeline recovers from validation errors *

Note this is a shortcut for getParseOptions().isContinueAfterValidationErrors(), retained * for backwards compatibility.

* * @return true if validation errors on this pipeline are treated as recoverable; false if they are treated * as fatal */ public boolean isRecoverFromValidationErrors() { return parseOptions.isContinueAfterValidationErrors(); } /** * Set a user-defined SchemaURIResolver for resolving URIs used in "import schema" * declarations. * * @param resolver the SchemaURIResolver */ public void setSchemaURIResolver(SchemaURIResolver resolver) { schemaURIResolver = resolver; } /** * Get the controller associated with this pipelineConfiguration * * @return the controller if it is known; otherwise null. */ public Controller getController() { return controller; } /** * Set the Controller associated with this pipelineConfiguration * * @param controller the Controller */ public void setController(Controller controller) { this.controller = controller; } /** * Get the host language in use * * @return for example {@link Configuration#XSLT} or {@link Configuration#XQUERY} */ public int getHostLanguage() { return hostLanguage; } /** * Set the host language in use * * @param language for example {@link Configuration#XSLT} or {@link Configuration#XQUERY} */ public void setHostLanguage(int language) { hostLanguage = language; } /** * Ask whether this pipeline is a serializing pipeline * * @return true if this pipeline is producing serialized output */ public boolean isSerializing() { return isSerializing; } /** * Set whether this pipeline is a serializing pipeline * * @param isSerializing true if this pipeline is producing serialized output */ public void setSerializing(boolean isSerializing) { this.isSerializing = isSerializing; } /** * Set whether attribute defaults defined in a schema or DTD are to be expanded or not * (by default, fixed and default attribute values are expanded, that is, they are inserted * into the document during validation as if they were present in the instance being validated) * * @param expand true if defaults are to be expanded, false if not */ public void setExpandAttributeDefaults(boolean expand) { parseOptions.setExpandAttributeDefaults(expand); } /** * Ask whether attribute defaults defined in a schema or DTD are to be expanded or not * (by default, fixed and default attribute values are expanded, that is, they are inserted * into the document during validation as if they were present in the instance being validated) * * @return true if defaults are to be expanded, false if not */ public boolean isExpandAttributeDefaults() { return parseOptions.isExpandAttributeDefaults(); } /** * Set a named component of the pipeline * * @param name string the component name * @param value the component value */ public void setComponent(String name, Object value) { if (components == null) { components = new HashMap(); } components.put(name, value); } /** * Get a named component of the pipeline * * @param name string the component name * @return the component value, or null if absent */ public Object getComponent(String name) { if (components == null) { return null; } else { return components.get(name); } } private static class DummyLocationProvider implements LocationProvider { public final static DummyLocationProvider THE_INSTANCE = new DummyLocationProvider(); public String getSystemId(long locationId) { return null; } public int getLineNumber(long locationId) { return -1; } public int getColumnNumber(long locationId) { return -1; } } } // // 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 // // Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved. // // Contributor(s): none. // saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/Stripper.java0000644000175000017500000001704311671711573024004 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.FingerprintedQName; import net.sf.saxon.om.NodeName; import net.sf.saxon.om.SpaceStrippingRule; import net.sf.saxon.om.StandardNames; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.RuleTarget; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ComplexType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; import net.sf.saxon.type.Untyped; import net.sf.saxon.value.Whitespace; import java.io.Serializable; /** * The RuleBasedStripper class performs whitespace stripping according to the rules of * the xsl:strip-space and xsl:preserve-space instructions. * It maintains details of which elements need to be stripped. * The code is written to act as a SAX-like filter to do the stripping. * @author Michael H. Kay */ public class Stripper extends ProxyReceiver { public final static StripRuleTarget STRIP = new StripRuleTarget(){}; public final static StripRuleTarget PRESERVE = new StripRuleTarget(){}; protected SpaceStrippingRule rule; public Stripper(/*@NotNull*/ SpaceStrippingRule rule, /*@NotNull*/ Receiver next) { super(next); this.rule = rule; } // stripStack is used to hold information used while stripping nodes. We avoid allocating // space on the tree itself to keep the size of nodes down. Each entry on the stack is two // booleans, one indicates the current value of xml-space is "preserve", the other indicates // that we are in a space-preserving element. // We implement our own stack to avoid the overhead of allocating objects. The two booleans // are held as the leas-significant bits of a byte. private byte[] stripStack = new byte[100]; private int top = 0; /** * Get a clean copy of this stripper. The new copy shares the same PipelineConfiguration * as the original, but the underlying receiver (that is, the destination for post-stripping * events) is changed. * @param next the next receiver in the pipeline for the new Stripper * @return a dublicate of this Stripper, with the output sent to "next". */ public Stripper getAnother(Receiver next) { return new Stripper(rule, next); } /** * Decide whether an element is in the set of white-space preserving element types * * * @param name Identifies the name of the element whose whitespace is to * be preserved * @return ALWAYS_PRESERVE if the element is in the set of white-space preserving * element types, ALWAYS_STRIP if the element is to be stripped regardless of the * xml:space setting, and STRIP_DEFAULT otherwise * @throws XPathException if the rules are ambiguous and ambiguities are to be * reported as errors */ public final byte isSpacePreserving(NodeName name) throws XPathException { return rule.isSpacePreserving(name); } public static final byte ALWAYS_PRESERVE = 0x01; // whitespace always preserved (e.g. xsl:text) public static final byte ALWAYS_STRIP = 0x02; // whitespace always stripped (e.g. xsl:choose) public static final byte STRIP_DEFAULT = 0x00; // no special action public static final byte PRESERVE_PARENT = 0x04; // parent element specifies xml:space="preserve" public static final byte CANNOT_STRIP = 0x08; // type annotation indicates simple typed content /** * Callback interface for SAX: not for application use */ public void open () throws XPathException { // System.err.println("Stripper#startDocument()"); top = 0; stripStack[top] = ALWAYS_PRESERVE; // {xml:preserve = false, preserve this element = true} super.open(); } public void startElement (NodeName elemName, SchemaType type, int locationId, int properties) throws XPathException { // System.err.println("startElement " + nameCode); nextReceiver.startElement(elemName, type, locationId, properties); byte preserveParent = stripStack[top]; byte preserve = (byte)(preserveParent & PRESERVE_PARENT); byte elementStrip = isSpacePreserving(elemName); if (elementStrip == ALWAYS_PRESERVE) { preserve |= ALWAYS_PRESERVE; } else if (elementStrip == ALWAYS_STRIP) { preserve |= ALWAYS_STRIP; } if (preserve == 0 && type != Untyped.getInstance()) { // if the element has simple content, whitespace stripping is disabled if (type.isSimpleType() || ((ComplexType)type).isSimpleContent()) { preserve |= CANNOT_STRIP; } } // put "preserve" value on top of stack top++; if (top >= stripStack.length) { byte[] newStack = new byte[top*2]; System.arraycopy(stripStack, 0, newStack, 0, top); stripStack = newStack; } stripStack[top] = preserve; } public void attribute(NodeName nameCode, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { // test for xml:space="preserve" | "default" if (nameCode.equals(XML_SPACE)) { if (Whitespace.normalizeWhitespace(value).equals("preserve")) { stripStack[top] |= PRESERVE_PARENT; } else { stripStack[top] &= ~PRESERVE_PARENT; } } nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } private static NodeName XML_SPACE = new FingerprintedQName("xml", NamespaceConstant.XML, "space", StandardNames.XML_SPACE); /** * Handle an end-of-element event */ public void endElement () throws XPathException { nextReceiver.endElement(); top--; } /** * Handle a text node */ public void characters (CharSequence chars, int locationId, int properties) throws XPathException { // assume adjacent chunks of text are already concatenated if (((((stripStack[top] & (ALWAYS_PRESERVE | PRESERVE_PARENT | CANNOT_STRIP)) != 0) && (stripStack[top] & ALWAYS_STRIP) == 0) || !Whitespace.isWhite(chars)) && chars.length() > 0) { nextReceiver.characters(chars, locationId, properties); } } /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation */ public boolean usesTypeAnnotations() { return true; } public static class StripRuleTarget implements RuleTarget, Serializable { public void explain(ExpressionPresenter presenter) { // no-op } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/BuilderMonitor.java0000644000175000017500000000352511671711573025132 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.NodeInfo; /** * A BuilderMonitor can be inserted into a pipeline immediately in front of a Builder. During tree construction, * the method markNextNode() can be called to request that the next node to be created is treated specially by * remembering the current position on the tree; on completion of the tree construction, the method getMarkedNode() * can be called to return the NodeInfo that was created immediately after calling markNextNode(). */ public abstract class BuilderMonitor extends ProxyReceiver { public BuilderMonitor(Receiver next) { super(next); } /** * Indicate that the next node to be created will be of a given type, and request the monitor to remember * the identity of this node. * @param nodeKind the kind of node that will be created next */ public abstract void markNextNode(int nodeKind); /** * On completion of tree building, get the node that was marked using markNextNode(). * @return the marked node, or null if none was marked */ public abstract NodeInfo getMarkedNode(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/TeeOutputter.java0000644000175000017500000002617011671711573024646 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamespaceBinding; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.NodeName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; /** * TeeOutputter: a SequenceReceiver that duplicates received events to two different destinations */ public class TeeOutputter extends SequenceReceiver { Receiver seq1; Receiver seq2; public TeeOutputter(Receiver seq1, Receiver seq2) { super(seq1.getPipelineConfiguration()); this.seq1 = seq1; this.seq2 = seq2; // if (seq1 instanceof SequenceReceiver) { // this.seq1 = (SequenceReceiver)seq1; // } else { // this.seq1 = new TreeReceiver(seq1); // } // if (seq2 instanceof SequenceReceiver) { // this.seq2 = (SequenceReceiver)seq2; // } else { // this.seq2 = new TreeReceiver(seq2); // } } /** * Set the first destination * @param seq1 the first output destination */ protected void setFirstDestination(Receiver seq1) { this.seq1 = seq1; } /** * Set the second destination * @param seq2 the second output destination */ protected void setSecondDestination(Receiver seq2) { this.seq2 = seq2; } /** * Get the first destination * @return the first output destination */ protected Receiver getFirstDestination() { return seq1; } /** * Get the second destination * @return the second output destination */ protected Receiver getSecondDestination() { return seq2; } /** * Output an item (atomic value or node) to the sequence */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (seq1 instanceof SequenceReceiver) { ((SequenceReceiver)seq1).append(item, locationId, NodeInfo.ALL_NAMESPACES); } else { throw new UnsupportedOperationException("append() not supported"); } if (seq2 instanceof SequenceReceiver) { ((SequenceReceiver)seq2).append(item, locationId, NodeInfo.ALL_NAMESPACES); } else { throw new UnsupportedOperationException("append() not supported"); } } @Override public void open() throws XPathException { super.open(); seq1.open(); seq2.open(); } /** * Notify the start of a document node */ public void startDocument(int properties) throws XPathException { seq1.startDocument(properties); seq2.startDocument(properties); } /** * Notify the end of a document node */ public void endDocument() throws XPathException { seq1.endDocument(); seq2.endDocument(); } /** * Notify the start of an element * * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. The value -1 * indicates the default type, xs:untyped. * @param locationId an integer which can be interpreted using a LocationMap to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties bit-significant properties of the element node. If there are no revelant */ public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { seq1.startElement(nameCode, typeCode, locationId, properties); seq2.startElement(nameCode, typeCode, locationId, properties); } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceBinding the prefix/uri pair * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException { seq1.namespace(namespaceBinding, properties); seq2.namespace(namespaceBinding, properties); } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param locationId an integer which can be interpreted using a LocationMap to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Bit significant value. The following bits are defined: *
DISABLE_ESCAPING
Disable escaping for this attribute
*
NO_SPECIAL_CHARACTERS
Attribute value contains no special characters
* @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(NodeName nameCode, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { seq1.attribute(nameCode, typeCode, value, locationId, properties); seq2.attribute(nameCode, typeCode, value, locationId, properties); } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { seq1.startContent(); seq2.startContent(); } /** * Notify the end of an element. The receiver must maintain a stack if it needs to know which * element is ending. */ public void endElement() throws XPathException { seq1.endElement(); seq2.endElement(); } /** * Notify character data. Note that some receivers may require the character data to be * sent in a single event, but in general this is not a requirement. * * @param chars The characters * @param locationId an integer which can be interpreted using a LocationMap to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Bit significant value. The following bits are defined: *
DISABLE_ESCAPING
Disable escaping for this text node
*
USE_CDATA
Output as a CDATA section
*/ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { seq1.characters(chars, locationId, properties); seq2.characters(chars, locationId, properties); } /** * Output a processing instruction * * @param name The PI name. This must be a legal name (it will not be checked). * @param data The data portion of the processing instruction * @param locationId an integer which can be interpreted using a LocationMap to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Additional information about the PI. The following bits are * defined: *
CHECKED
Data is known to be legal (e.g. doesn't contain "?>")
* @throws IllegalArgumentException: the content is invalid for an XML processing instruction */ public void processingInstruction(String name, CharSequence data, int locationId, int properties) throws XPathException { seq1.processingInstruction(name, data, locationId, properties); seq2.processingInstruction(name, data, locationId, properties); } /** * Notify a comment. Comments are only notified if they are outside the DTD. * * @param content The content of the comment * @param locationId an integer which can be interpreted using a LocationMap to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Additional information about the comment. The following bits are * defined: *
CHECKED
Comment is known to be legal (e.g. doesn't contain "--")
* @throws IllegalArgumentException: the content is invalid for an XML comment */ public void comment(CharSequence content, int locationId, int properties) throws XPathException { seq1.comment(content, locationId, properties); seq2.comment(content, locationId, properties); } /** * Notify the end of the event stream */ public void close() throws XPathException { seq1.close(); seq2.close(); } /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation */ public boolean usesTypeAnnotations() { return seq1.usesTypeAnnotations() || seq2.usesTypeAnnotations(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/ProxyReceiver.java0000644000175000017500000002255311671711573025004 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NamespaceBinding; import net.sf.saxon.om.NodeName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; /** * A ProxyReceiver is an Receiver that filters data before passing it to another * underlying Receiver. */ public abstract class ProxyReceiver extends SequenceReceiver { /*@NotNull*/ protected Receiver nextReceiver; public ProxyReceiver(/*@NotNull*/ Receiver nextReceiver) { super(nextReceiver.getPipelineConfiguration()); setUnderlyingReceiver(nextReceiver); setPipelineConfiguration(nextReceiver.getPipelineConfiguration()); } public void setSystemId(String systemId) { //noinspection StringEquality if (systemId != this.systemId) { // use of == rather than equals() is deliberate, since this is only an optimization this.systemId = systemId; nextReceiver.setSystemId(systemId); } } /** * Set the underlying receiver. This call is mandatory before using the Receiver. * @param receiver the underlying receiver, the one that is to receive events after processing * by this filter. */ public void setUnderlyingReceiver(/*@NotNull*/ Receiver receiver) { if (receiver != nextReceiver) { nextReceiver = receiver; } } /** * Get the underlying Receiver (that is, the next one in the pipeline) * @return the underlying Receiver (that is, the next one in the pipeline) */ /*@Nullable*/ public Receiver getUnderlyingReceiver() { return nextReceiver; } public void setPipelineConfiguration(/*@NotNull*/ PipelineConfiguration pipe) { if (pipelineConfiguration != pipe) { pipelineConfiguration = pipe; if (nextReceiver.getPipelineConfiguration() != pipe) { nextReceiver.setPipelineConfiguration(pipe); } } } /** * Get the namepool for this configuration */ public NamePool getNamePool() { return pipelineConfiguration.getConfiguration().getNamePool(); } /** * Start of event stream */ public void open() throws XPathException { nextReceiver.open(); } /** * End of output. Note that closing this receiver also closes the rest of the * pipeline. */ public void close() throws XPathException { // Note: It's wrong to assume that because we've finished writing to this // receiver, then we've also finished writing to other receivers in the pipe. // In the case where the rest of the pipe is to stay open, the caller should // either avoid doing the close(), or should first set the underlying receiver // to null. nextReceiver.close(); } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { nextReceiver.startDocument(properties); } /** * Notify the end of a document node */ public void endDocument() throws XPathException { nextReceiver.endDocument(); } /** * Notify the start of an element * * @param elemName integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties properties of the element node */ public void startElement(NodeName elemName, SchemaType typeCode, int locationId, int properties) throws XPathException { nextReceiver.startElement(elemName, typeCode, locationId, properties); } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceBinding the prefix/uri pair representing the namespace binding * @param properties any special properties to be passed on this call * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException { nextReceiver.namespace(namespaceBinding, properties); } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *
DISABLE_ESCAPING
Disable escaping for this attribute
*
NO_SPECIAL_CHARACTERS
Attribute value contains no special characters
* @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(NodeName nameCode, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. */ public void startContent() throws XPathException { nextReceiver.startContent(); } /** * End of element */ public void endElement() throws XPathException { nextReceiver.endElement(); } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { nextReceiver.characters(chars, locationId, properties); } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { nextReceiver.processingInstruction(target, data, locationId, properties); } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { nextReceiver.comment(chars, locationId, properties); } /** * Set the URI for an unparsed entity in the document. */ public void setUnparsedEntity(String name, String uri, String publicId) throws XPathException { nextReceiver.setUnparsedEntity(name, uri, publicId); } /** * Append an arbitrary item (node or atomic value) to the output * * @param item the item to be appended * @param locationId the location of the calling instruction, for diagnostics * @param copyNamespaces if the item is an element node, this indicates whether its namespaces * need to be copied. Values are {@link net.sf.saxon.om.NodeInfo#ALL_NAMESPACES}, * {@link net.sf.saxon.om.NodeInfo#LOCAL_NAMESPACES}, {@link net.sf.saxon.om.NodeInfo#NO_NAMESPACES} */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (nextReceiver instanceof SequenceReceiver) { ((SequenceReceiver)nextReceiver).append(item, locationId, copyNamespaces); } else { throw new UnsupportedOperationException("append() method is not supported in this class"); } } /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation */ public boolean usesTypeAnnotations() { return nextReceiver.usesTypeAnnotations(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/package.html0000644000175000017500000000652111671711573023611 0ustar mathieumathieu Package overview for net.sf.saxon.event

This package provides classes that feed SAX-like events from one tree to another. Some of these classes are associated with serializing the output of a stylesheet, but there are also classes for building a tree from a stream of events, for stripping whitespace, and so on.

The {@link net.sf.saxon.event.Receiver} interface defines a class that accepts a stream of events, with one method defined for each kind of event. The events are modelled on the design of SAX, but adapted to the XPath data model and to the use of Saxon's NamePool. Attributes and namespaces are notified individually after the start of the relevant element. Many of the classes in this package are implementations of the Receiver interface.

The immediate output of node constructors in a query or stylesheet goes to a {@link net.sf.saxon.event.SequenceReceiver}. This is a subclass of Receiver that can handle an arbitrary sequence, containing atomic values as well as nodes. When constructing the content of an element, a {@link net.sf.saxon.event.ComplexContentOutputter} is used; when constructing the content of a node such as a text node or attribute, a SequenceOutputter is used instead.

The final destination of the push pipeline is sometimes a serializer, and sometimes a tree builder. The final serialization classes are subclasses of Emitter, but some of the serialization work (such as indentation or application of character maps) is done by other classes on the pipeline. These are generally constructed by extending the ProxyReceiver class.

The Emitter is an abstract implementation of the Receiver interface. As well as supporting the Receiver interface, it provides methods for controlling the destination of serialized output (a Writer or OutputStream) and for setting serialization properties (in a Properties object). In practice nearly all the implementations of Receiver are currently subclasses of Emitter, but this may change in the future.

The package includes emitters for the standard output methods xml, html, and text, and proxy emitters to allow a sequence of filters to be applied to the output.

,

The class ContentHandlerProxy allows events to be converted into standard SAX events and sent to a SAX2 ContentHandler. Similarly, the class ProxyReceiver acts as a ContentHandler, accepting SAX2 events and feeding them into a Receiver pipeline.

The class Builder is a Receiver that constructs a tree representation of the document in memory. There are two subclasses for Saxon's two native tree models. Other classes such as a Stripper and a NamespaceReducer are used to modify the document by adding filters to the pipeline.

Saxon's schema validator and serializer are both implemented using this push pipeline model. The classes that perform schema validation are part of package: {@link com.saxonica.validate}, while the serialization classes are in {@link net.sf.saxon.serialize}.


Michael H. Kay
Saxonica Limited
30 July 2010

saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/TypeCheckingFilter.java0000644000175000017500000003056411671711573025722 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.expr.parser.ExpressionLocation; import net.sf.saxon.expr.parser.RoleLocator; import net.sf.saxon.expr.parser.Token; import net.sf.saxon.om.Item; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NamespaceBinding; import net.sf.saxon.om.NodeName; import net.sf.saxon.pattern.CombinedNodeTest; import net.sf.saxon.pattern.ContentTypeTest; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.pattern.NodeKindTest; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ItemType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; import net.sf.saxon.type.Type; import net.sf.saxon.value.Cardinality; import net.sf.saxon.value.Value; import javax.xml.transform.SourceLocator; import java.util.HashSet; /** * A filter on the push pipeline that performs type checking, both of the item type and the * cardinality. *

* Note that the TypeCheckingFilter cannot currently check document node tests of the form * document-node(element(X,Y)), so it is not invoked in such cases. This isn't a big problem, because most * instructions that return document nodes materialize them anyway. */ public class TypeCheckingFilter extends ProxyReceiver { private ItemType itemType; private int cardinality; private RoleLocator role; private SourceLocator locator; private int count = 0; private int level = 0; private HashSet checkedElements = new HashSet(10); // used to avoid repeated checking when a template creates large numbers of elements of the same type // The key is a (namecode, typecode) pair, packed into a single long public TypeCheckingFilter(Receiver next) { super(next); } public void setRequiredType(ItemType type, int cardinality, RoleLocator role, SourceLocator locator) { itemType = type; this.cardinality = cardinality; this.role = role; this.locator = locator; } /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * * * @param nameCode The name of the attribute, as held in the name pool * @param typeCode The type of the attribute, as held in the name pool * @param properties Bit significant value. The following bits are defined: *

DISABLE_ESCAPING
Disable escaping for this attribute
*
NO_SPECIAL_CHARACTERS
Attribute value contains no special characters
* @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag */ public void attribute(NodeName nameCode, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(locationId); } ItemType type = new CombinedNodeTest( new NameTest(Type.ATTRIBUTE, nameCode, getNamePool()), Token.INTERSECT, new ContentTypeTest(Type.ATTRIBUTE, typeCode, getConfiguration())); checkItemType(type, locationId); } nextReceiver.attribute(nameCode, typeCode, value, locationId, properties); } /** * Character data */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(locationId); } ItemType type = NodeKindTest.TEXT; checkItemType(type, locationId); } nextReceiver.characters(chars, locationId, properties); } /** * Output a comment */ public void comment(CharSequence chars, int locationId, int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(locationId); } ItemType type = NodeKindTest.COMMENT; checkItemType(type, locationId); } nextReceiver.comment(chars, locationId, properties); //To change body of overridden methods use File | Settings | File Templates. } /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element; however, duplicates may be reported. * A namespace must not conflict with any namespaces already used for element or attribute names. * * @param namespaceBinding the prefix/uri pair * @throws IllegalStateException: attempt to output a namespace when there is no open element * start tag */ public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(0); } ItemType type = NodeKindTest.NAMESPACE; checkItemType(type, 0); } nextReceiver.namespace(namespaceBinding, properties); //To change body of overridden methods use File | Settings | File Templates. } /** * Processing Instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(locationId); } ItemType type = NodeKindTest.PROCESSING_INSTRUCTION; checkItemType(type, locationId); } nextReceiver.processingInstruction(target, data, locationId, properties); } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(0); } ItemType type = NodeKindTest.DOCUMENT; checkItemType(type, 0); } level++; nextReceiver.startDocument(properties); } /** * Notify the start of an element * * @param nameCode integer code identifying the name of the element within the name pool. * @param typeCode integer code identifying the element's type within the name pool. * @param properties properties of the element node */ public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { if (level == 0) { if (++count == 1) { // don't bother with any caching on the first item, it will often be the only one ItemType type = new CombinedNodeTest( new NameTest(Type.ELEMENT, nameCode, getNamePool()), Token.INTERSECT, new ContentTypeTest(Type.ELEMENT, typeCode, getConfiguration())); checkItemType(type, locationId); } else { if (count == 2) { checkAllowsMany(locationId); } long key = ((long) (nameCode.allocateNameCode(getNamePool()) & NamePool.FP_MASK)) << 32 | (long) (typeCode.getFingerprint()); if (!checkedElements.contains(key)) { ItemType type = new CombinedNodeTest( new NameTest(Type.ELEMENT, nameCode, getNamePool()), Token.INTERSECT, new ContentTypeTest(Type.ELEMENT, typeCode, getConfiguration())); checkItemType(type, locationId); checkedElements.add(key); } } } level++; nextReceiver.startElement(nameCode, typeCode, locationId, properties); } /** * Notify the end of a document node */ public void endDocument() throws XPathException { level--; nextReceiver.endDocument(); } /** * End of element */ public void endElement() throws XPathException { level--; nextReceiver.endElement(); } /** * End of event stream */ public void close() throws XPathException { if (count == 0 && !Cardinality.allowsZero(cardinality)) { XPathException err = new XPathException("An empty sequence is not allowed as the " + role.getMessage()); String errorCode = role.getErrorCode(); err.setErrorCode(errorCode); if (!"XPDY0050".equals(errorCode)) { err.setIsTypeError(true); } throw err; } // don't pass on the close event } /** * Output an item (atomic value or node) to the sequence */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (level == 0) { if (++count == 2) { checkAllowsMany(locationId); } checkItemType(Value.asValue(item).getItemType(getConfiguration().getTypeHierarchy()), locationId); } if (nextReceiver instanceof SequenceReceiver) { ((SequenceReceiver)nextReceiver).append(item, locationId, copyNamespaces); } else { super.append(item, locationId, copyNamespaces); } } /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation */ public boolean usesTypeAnnotations() { return true; } private void checkItemType(ItemType type, long locationId) throws XPathException { if (!getConfiguration().getTypeHierarchy().isSubType(type, itemType)) { String message = role.composeErrorMessage(itemType, type, getNamePool()); String errorCode = role.getErrorCode(); XPathException err = new XPathException(message); err.setErrorCode(errorCode); if (!"XPDY0050".equals(errorCode)) { err.setIsTypeError(true); } if (locationId == 0) { err.setLocator(locator); } else { err.setLocator(ExpressionLocation.getSourceLocator(locationId, getPipelineConfiguration().getLocationProvider())); } throw err; } } private void checkAllowsMany(long locationId) throws XPathException { if (!Cardinality.allowsMany(cardinality)) { XPathException err = new XPathException("A sequence of more than one item is not allowed as the " + role.getMessage()); String errorCode = role.getErrorCode(); err.setErrorCode(errorCode); if (!"XPDY0050".equals(errorCode)) { err.setIsTypeError(true); } if (locationId == 0) { err.setLocator(locator); } else { err.setLocator(ExpressionLocation.getSourceLocator(locationId, getPipelineConfiguration().getLocationProvider())); } throw err; } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/ComplexContentOutputter.java0000644000175000017500000006063511671711573027077 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.expr.parser.ExpressionLocation; import net.sf.saxon.om.*; import net.sf.saxon.trans.Err; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.SchemaType; import net.sf.saxon.type.SimpleType; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; /** * This class is used for generating complex content, that is, the content of an * element or document node. It enforces the rules on the order of events within * complex content (attributes and namespaces must come first), and it implements * part of the namespace fixup rules, in particular, it ensures that there is a * namespace node for the namespace used in the element name and in each attribute * name. * *

The same ComplexContentOutputter may be used for generating an entire XML * document; it is not necessary to create a new outputter for each element node.

* * @author Michael H. Kay */ public final class ComplexContentOutputter extends SequenceReceiver { private Receiver nextReceiver; // the next receiver in the output pipeline private int pendingStartTagDepth = -2; // -2 means we are at the top level, or immediately within a document node // -1 means we are in the content of an element node whose start tag is complete private NodeName pendingStartTag = null; private int level = -1; // records the number of startDocument or startElement events // that have not yet been closed. Note that startDocument and startElement // events may be arbitrarily nested; startDocument and endDocument // are ignored unless they occur at the outermost level, except that they // still change the level number private boolean[] currentLevelIsDocument = new boolean[20]; private Boolean elementIsInNullNamespace; private NodeName[] pendingAttCode = new NodeName[20]; private SimpleType[] pendingAttType = new SimpleType[20]; private String[] pendingAttValue = new String[20]; private int[] pendingAttLocation = new int[20]; private int[] pendingAttProp = new int[20]; private int pendingAttListSize = 0; private NamespaceBinding[] pendingNSList = new NamespaceBinding[20]; private int pendingNSListSize = 0; private SchemaType currentSimpleType = null; // any other value means we are currently writing an // element of a particular simple type private int startElementProperties; private int startElementLocationId = -1; private boolean declaresDefaultNamespace; private int hostLanguage = Configuration.XSLT; private boolean started = false; /** * Create a ComplexContentOutputter * @param pipe the pipeline configuration */ public ComplexContentOutputter(/*@NotNull*/ PipelineConfiguration pipe) { super(pipe); //System.err.println("ComplexContentOutputter init"); } public void setPipelineConfiguration(/*@NotNull*/ PipelineConfiguration pipe) { if (pipelineConfiguration != pipe) { pipelineConfiguration = pipe; if (nextReceiver != null) { nextReceiver.setPipelineConfiguration(pipe); } } } /** * Set the host language * @param language the host language, for example {@link Configuration#XQUERY} */ public void setHostLanguage(int language) { hostLanguage = language; } /** * Set the receiver (to handle the next stage in the pipeline) directly * @param receiver the receiver to handle the next stage in the pipeline */ public void setReceiver(Receiver receiver) { this.nextReceiver = receiver; } /** * Test whether any content has been written to this ComplexContentOutputter * @return true if content has been written */ public boolean contentHasBeenWritten() { return started; } /** * Start the output process */ public void open() throws XPathException { nextReceiver.open(); previousAtomic = false; } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { level++; if (level == 0) { nextReceiver.startDocument(properties); } else if (pendingStartTagDepth >= 0) { startContent(); pendingStartTagDepth = -2; } previousAtomic = false; if (currentLevelIsDocument.length < level+1) { boolean[] b2 = new boolean[level*2]; System.arraycopy(currentLevelIsDocument, 0, b2, 0, level); currentLevelIsDocument = b2; } currentLevelIsDocument[level] = true; } /** * Notify the end of a document node */ public void endDocument() throws XPathException { if (level == 0) { nextReceiver.endDocument(); } previousAtomic = false; level--; } /** * Produce text content output.
* Special characters are escaped using XML/HTML conventions if the output format * requires it. * @param s The String to be output * @exception XPathException for any failure */ public void characters(CharSequence s, int locationId, int properties) throws XPathException { previousAtomic = false; if (s==null) return; int len = s.length(); if (len==0) return; if (pendingStartTagDepth >= 0) { startContent(); } nextReceiver.characters(s, locationId, properties); } /** * Output an element start tag.
* The actual output of the tag is deferred until all attributes have been output * using attribute(). * @param elemName The element name */ public void startElement(NodeName elemName, SchemaType typeCode, int locationId, int properties) throws XPathException { //System.err.println("CCO " + this + "StartElement " + nameCode); level++; started = true; if (pendingStartTagDepth >= 0) { startContent(); } startElementProperties = properties; startElementLocationId = locationId; pendingAttListSize = 0; pendingNSListSize = 0; pendingStartTag = elemName; pendingStartTagDepth = 1; elementIsInNullNamespace = null; // meaning not yet computed declaresDefaultNamespace = false; currentSimpleType = typeCode; previousAtomic = false; if (currentLevelIsDocument.length < level+1) { boolean[] b2 = new boolean[level*2]; System.arraycopy(currentLevelIsDocument, 0, b2, 0, level); currentLevelIsDocument = b2; } currentLevelIsDocument[level] = false; } /** * Output a namespace declaration.
* 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, unless the REJECT_DUPLICATES flag is set, in which case this is an error. * Note that unlike SAX2 startPrefixMapping(), this call is made AFTER writing the start tag. * @param nsBinding The namespace binding * @throws 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 { // System.err.println("Write namespace prefix=" + (nscode>>16) + " uri=" + (nscode&0xffff)); if (pendingStartTagDepth < 0) { LocationProvider lp = getPipelineConfiguration().getLocationProvider(); throw NoOpenStartTagException.makeNoOpenStartTagException( Type.NAMESPACE, nsBinding.getPrefix(), hostLanguage, pendingStartTagDepth == -2, getPipelineConfiguration().isSerializing(), lp, startElementLocationId); } // elimination of namespaces already present on an outer element of the // result tree is done by the NamespaceReducer. // Handle declarations whose prefix is duplicated for this element. boolean rejectDuplicates = (properties & ReceiverOptions.REJECT_DUPLICATES) != 0; for (int i=0; i pendingNSList.length) { NamespaceBinding[] newlist = new NamespaceBinding[pendingNSListSize * 2]; System.arraycopy(pendingNSList, 0, newlist, 0, pendingNSListSize); pendingNSList = newlist; } pendingNSList[pendingNSListSize++] = nsBinding; previousAtomic = false; } /** * Output an attribute value.
* This is added to a list of pending attributes for the current start tag, overwriting * any previous attribute with the same name.
* This method should NOT be used to output namespace declarations.
* * * @param attName The name of the attribute * @param value The value of the attribute * @param properties Bit fields containing properties of the attribute to be written * @throws 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(NodeName attName, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException { //System.err.println("Write attribute " + nameCode + "=" + value + " to Outputter " + this); if (pendingStartTagDepth < 0) { // The complexity here is in identifying the right error message and error code LocationProvider lp = getPipelineConfiguration().getLocationProvider(); XPathException err = NoOpenStartTagException.makeNoOpenStartTagException( Type.ATTRIBUTE, attName.getDisplayName(), hostLanguage, level < 0 || currentLevelIsDocument[level], getPipelineConfiguration().isSerializing(), lp, startElementLocationId); if (lp != null) { err.setLocator(new ExpressionLocation(lp, locationId)); } throw err; } // if this is a duplicate attribute, overwrite the original, unless // the REJECT_DUPLICATES option is set. for (int a=0; a= pendingAttCode.length) { NodeName[] attCode2 = new NodeName[pendingAttListSize*2]; SimpleType[] attType2 = new SimpleType[pendingAttListSize*2]; String[] attValue2 = new String[pendingAttListSize*2]; int[] attLoc2 = new int[pendingAttListSize*2]; int[] attProp2 = new int[pendingAttListSize*2]; System.arraycopy(pendingAttCode, 0, attCode2, 0, pendingAttListSize); System.arraycopy(pendingAttType, 0, attType2, 0, pendingAttListSize); System.arraycopy(pendingAttValue, 0, attValue2, 0, pendingAttListSize); System.arraycopy(pendingAttLocation, 0, attLoc2, 0, pendingAttListSize); System.arraycopy(pendingAttProp, 0, attProp2, 0, pendingAttListSize); pendingAttCode = attCode2; pendingAttType = attType2; pendingAttValue = attValue2; pendingAttLocation = attLoc2; pendingAttProp = attProp2; } pendingAttCode[pendingAttListSize] = attName; pendingAttType[pendingAttListSize] = typeCode; pendingAttValue[pendingAttListSize] = value.toString(); pendingAttLocation[pendingAttListSize] = locationId; pendingAttProp[pendingAttListSize] = properties; pendingAttListSize++; previousAtomic = false; } /** * Check that the prefix for an element or attribute is acceptable, allocating a substitute * prefix if not. The prefix is acceptable unless a namespace declaration has been * written that assignes this prefix to a different namespace URI. This method * also checks that the element or attribute namespace has been declared, and declares it * if not. * @param nodeName the proposed name, including proposed prefix * @param seq sequence number, used for generating a substitute prefix when necessary * @return a nameCode to use in place of the proposed nameCode (or the original nameCode * if no change is needed) * @throws net.sf.saxon.trans.XPathException if an error occurs writing the new * namespace node */ private NodeName checkProposedPrefix(NodeName nodeName, int seq) throws XPathException { NamespaceBinding binding = nodeName.getNamespaceBinding(); String nsprefix = binding.getPrefix(); for (int i=0; i= 0) { startContent(); } else { pendingStartTagDepth = -2; pendingStartTag = null; } // write the end tag nextReceiver.endElement(); level--; previousAtomic = false; } /** * Write a comment */ public void comment(CharSequence comment, int locationId, int properties) throws XPathException { if (pendingStartTagDepth >= 0) { startContent(); } nextReceiver.comment(comment, locationId, properties); previousAtomic = false; } /** * Write a processing instruction */ public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (pendingStartTagDepth >= 0) { startContent(); } nextReceiver.processingInstruction(target, data, locationId, properties); previousAtomic = false; } /** * Append an arbitrary item (node or atomic value) to the output * @param item the item to be appended * @param locationId the location of the calling instruction, for diagnostics * @param copyNamespaces if the item is an element node, this indicates whether its namespaces * need to be copied. Values are {@link net.sf.saxon.om.NodeInfo#ALL_NAMESPACES}, * {@link net.sf.saxon.om.NodeInfo#LOCAL_NAMESPACES}, {@link net.sf.saxon.om.NodeInfo#NO_NAMESPACES} */ public void append(/*@Nullable*/ Item item, int locationId, int copyNamespaces) throws XPathException { if (item == null) { //return; } else if (item instanceof AtomicValue) { if (previousAtomic) { characters(" ", locationId, 0); } characters(item.getStringValueCS(), locationId, 0); previousAtomic = true; } else if (item instanceof FunctionItem) { throw new XPathException("Cannot add a function item to a node tree"); } else if (((NodeInfo)item).getNodeKind() == Type.DOCUMENT) { startDocument(0); SequenceIterator iter = ((NodeInfo)item).iterateAxis(Axis.CHILD); while (true) { Item it = iter.next(); if (it == null) break; append(it, locationId, copyNamespaces); } endDocument(); previousAtomic = false; } else { int copyOptions = CopyOptions.TYPE_ANNOTATIONS; if (copyNamespaces == NodeInfo.LOCAL_NAMESPACES) { copyOptions |= CopyOptions.LOCAL_NAMESPACES; } else if (copyNamespaces == NodeInfo.ALL_NAMESPACES) { copyOptions |= CopyOptions.ALL_NAMESPACES; } ((NodeInfo)item).copy(this, copyOptions, locationId); previousAtomic = false; } } /** * Close the output */ public void close() throws XPathException { // System.err.println("Close " + this + " using emitter " + emitter.getClass()); nextReceiver.close(); previousAtomic = false; } /** * Flush out a pending start tag */ public void startContent() throws XPathException { if (pendingStartTagDepth < 0) { // this can happen if the method is called from outside, // e.g. from a SequenceOutputter earlier in the pipeline return; } started = true; int props = startElementProperties; NodeName elcode = pendingStartTag; if (declaresDefaultNamespace || pendingStartTag.getPrefix().length()!=0) { // skip this check if the element is unprefixed and no xmlns="abc" declaration has been encountered elcode = checkProposedPrefix(pendingStartTag, 0); props = startElementProperties | ReceiverOptions.NAMESPACE_OK; } nextReceiver.startElement(elcode, currentSimpleType, startElementLocationId, props); for (int a=0; a * The Receiver interface is an important internal interface within Saxon, and provides a powerful * mechanism for integrating Saxon with other applications. It has been designed with extensibility * and stability in mind. However, it should be considered as an interface designed primarily for * internal use, and not as a completely stable part of the public Saxon API. *

* @author Michael H. Kay */ public interface Receiver extends Result { /** * Set the pipeline configuration * @param pipe the pipeline configuration */ public void setPipelineConfiguration(/*@NotNull*/ PipelineConfiguration pipe); /** * Get the pipeline configuration * @return the pipeline configuration */ /*@NotNull*/ public PipelineConfiguration getPipelineConfiguration(); /** * Set the System ID of the tree represented by this event stream * @param systemId the system ID (which is used as the base URI of the nodes * if there is no xml:base attribute) */ public void setSystemId(String systemId); /** * Notify the start of the event stream * @throws XPathException if an error occurs */ public void open() throws XPathException; /** * Notify the start of a document node * @param properties bit-significant integer indicating properties of the document node. * The definitions of the bits are in class {@link ReceiverOptions} * @throws XPathException if an error occurs */ public void startDocument(int properties) throws XPathException; /** * Notify the end of a document node * @throws XPathException if an error occurs */ public void endDocument() throws XPathException; /** * Notify an unparsed entity URI. * @param name The name of the unparsed entity * @param systemID The system identifier of the unparsed entity * @param publicID The public identifier of the unparsed entity * @throws XPathException if an error occurs */ public void setUnparsedEntity(String name, String systemID, String publicID) throws XPathException; /** * Notify the start of an element * * @param elemName the name of the element. * @param typeCode the type annotation of the element. * @param locationId an integer which can be interpreted using a {@link LocationProvider} to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties bit-significant properties of the element node. If there are no revelant * properties, zero is supplied. The definitions of the bits are in class {@link ReceiverOptions} * @throws XPathException if an error occurs */ public void startElement(NodeName elemName, SchemaType typeCode, int locationId, int properties) throws XPathException; /** * Notify a namespace. Namespaces are notified after the startElement event, and before * any children for the element. The namespaces that are reported are only required * to include those that are different from the parent element. The events represent namespace * declarations and undeclarations rather than in-scope namespace nodes: an undeclaration is represented * by a namespace code of zero. If the sequence of namespace events contains two * A namespace must not conflict with any namespaces already used for element or attribute names. * @param namespaceBinding contains the namespace prefix and namespace URI * @param properties The most important property is REJECT_DUPLICATES. If this property is set, the * namespace declaration will be rejected if it conflicts with a previous declaration of the same * prefix. If the property is not set, the namespace declaration will be ignored if it conflicts * with a previous declaration. This reflects the fact that when copying a tree, namespaces for child * elements are emitted before the namespaces of their parent element. Unfortunately this conflicts * with the XSLT rule for complex content construction, where the recovery action in the event of * conflicts is to take the namespace that comes last. XSLT therefore doesn't recover from this error: * @throws XPathException if an error occurs */ public void namespace(NamespaceBinding namespaceBinding, int properties) throws XPathException; /** * Notify an attribute. Attributes are notified after the startElement event, and before any * children. Namespaces and attributes may be intermingled. * * * @param attName The name of the attribute * @param typeCode The type of the attribute, as held in the name pool. The additional bit * NodeInfo.IS_DTD_TYPE may be set to indicate a DTD-derived type. * @param value the string value of the attribute * @param locationId an integer which can be interpreted using a {@link net.sf.saxon.event.LocationProvider} to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Bit significant value. The following bits are defined: *

DISABLE_ESCAPING
Disable escaping for this attribute
*
NO_SPECIAL_CHARACTERS
Attribute value contains no special characters
* @throws IllegalStateException: attempt to output an attribute when there is no open element * start tag * @throws XPathException if an error occurs */ public void attribute(NodeName attName, SimpleType typeCode, CharSequence value, int locationId, int properties) throws XPathException; /** * Notify the start of the content, that is, the completion of all attributes and namespaces. * Note that the initial receiver of output from XSLT instructions will not receive this event, * it has to detect it itself. Note that this event is reported for every element even if it has * no attributes, no namespaces, and no content. * @throws XPathException if an error occurs */ public void startContent() throws XPathException; /** * Notify the end of an element. The receiver must maintain a stack if it needs to know which * element is ending. * @throws XPathException if an error occurs */ public void endElement() throws XPathException; /** * Notify character data. Note that some receivers may require the character data to be * sent in a single event, but in general this is not a requirement. * @param chars The characters * @param locationId an integer which can be interpreted using a {@link net.sf.saxon.event.LocationProvider} * to return information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Bit significant value. The following bits are defined: *
DISABLE_ESCAPING
Disable escaping for this text node
*
USE_CDATA
Output as a CDATA section
* @throws XPathException if an error occurs */ public void characters(CharSequence chars, int locationId, int properties) throws XPathException; /** * Output a processing instruction * @param name The PI name. This must be a legal name (it will not be checked). * @param data The data portion of the processing instruction * @param locationId an integer which can be interpreted using a {@link LocationProvider} to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Additional information about the PI. * @throws IllegalArgumentException: the content is invalid for an XML processing instruction * @throws XPathException if an error occurs */ public void processingInstruction(String name, CharSequence data, int locationId, int properties) throws XPathException; /** * Notify a comment. Comments are only notified if they are outside the DTD. * @param content The content of the comment * @param locationId an integer which can be interpreted using a {@link LocationProvider} to return * information such as line number and system ID. If no location information is available, * the value zero is supplied. * @param properties Additional information about the comment. * @throws IllegalArgumentException: the content is invalid for an XML comment * @throws XPathException if an error occurs */ public void comment(CharSequence content, int locationId, int properties) throws XPathException; /** * Notify the end of the event stream * @throws XPathException if an error occurs */ public void close() throws XPathException; /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation (or conversely, it may * avoid stripping unwanted type annotations) */ public boolean usesTypeAnnotations(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/ReceivingContentHandler.java0000644000175000017500000006356211671711573026747 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.expr.parser.ExpressionLocation; import net.sf.saxon.lib.FeatureKeys; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.tiny.CharSlice; import net.sf.saxon.tree.tiny.CompressedWhitespace; import net.sf.saxon.type.*; import net.sf.saxon.value.Whitespace; import org.xml.sax.*; import org.xml.sax.ext.Attributes2; import org.xml.sax.ext.LexicalHandler; import javax.xml.transform.Result; import javax.xml.transform.TransformerException; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; /** * ReceivingContentHandler is a glue class that provides a standard SAX ContentHandler * interface to a Saxon Receiver. To achieve this it needs to map names supplied * as strings to numeric name codes, for which purpose it needs access to a name * pool. The class also performs the function of assembling adjacent text nodes. *

The class was previously named ContentEmitter.

*

If the input stream contains the processing instructions assigned by JAXP to switch * disable-output-escaping on or off, these will be reflected in properties set in the corresponding * characters events. In this case adjacent text nodes will not be combined. * @author Michael H. Kay */ public class ReceivingContentHandler implements ContentHandler, LexicalHandler, DTDHandler //, SaxonLocator, SourceLocationProvider { private PipelineConfiguration pipe; private Receiver receiver; private boolean inDTD = false; // true while processing the DTD private Locator locator; // a SAX Locator private LocalLocator localLocator = new LocalLocator(); // buffer for accumulating character data, until the next markup event is received private char[] buffer = new char[512]; private int charsUsed = 0; private CharSlice slice = new CharSlice(buffer, 0, 0); // array for accumulating namespace information private NamespaceBinding[] namespaces = new NamespaceBinding[20]; private int namespacesUsed = 0; // determine whether ignorable whitespace is ignored private boolean ignoreIgnorable = false; // determine whether DTD attribute types are retained private boolean retainDTDAttributeTypes = false; // determine whether DTD attribute value defaults should be suppressed private boolean suppressDTDAttributeDefaults = false; // indicate that escaping is allowed to be disabled using the JAXP-defined processing instructions private boolean allowDisableOutputEscaping = false; // indicate that escaping is disabled private boolean escapingDisabled = false; // flag to indicate whether the last tag was a start tag or an end tag private boolean afterStartTag = true; /** * A local cache is used to avoid allocating namecodes for the same name more than once. * This reduces contention on the NamePool. This is a two-level hashmap: the first level * has the namespace URI as its key, and returns a HashMap which maps lexical QNames to integer * namecodes. */ private HashMap> nameCache = new HashMap>(10); private HashMap noNamespaceNameCache = new HashMap(10); // private static Class attributes2class; // private static Method isSpecifiedMethod; /** * Create a ReceivingContentHandler and initialise variables */ public ReceivingContentHandler() { } /** * Set the ReceivingContentHandler to its initial state, except for the local name cache, * which is retained */ public void reset() { pipe = null; receiver = null; ignoreIgnorable = false; retainDTDAttributeTypes = false; charsUsed = 0; slice.setLength(0); namespacesUsed = 0; locator = null; allowDisableOutputEscaping = false; escapingDisabled = false; } /** * Set the receiver to which events are passed. ReceivingContentHandler is essentially a translator * that takes SAX events as input and produces Saxon Receiver events as output; these Receiver events * are passed to the supplied Receiver * @param receiver the Receiver of events */ public void setReceiver(Receiver receiver) { this.receiver = receiver; //receiver = new TracingFilter(receiver); } /** * Get the receiver to which events are passed. * @return the underlying Receiver */ public Receiver getReceiver() { return receiver; } /** * Set the pipeline configuration * @param pipe the pipeline configuration. This holds a reference to the Saxon configuration, as well as * information that can vary from one pipeline to another, for example the LocationProvider which resolves * the location of events in a source document */ public void setPipelineConfiguration(PipelineConfiguration pipe) { this.pipe = pipe; pipe.setLocationProvider(localLocator); Configuration config = pipe.getConfiguration(); ignoreIgnorable = pipe.getParseOptions().getStripSpace() != Whitespace.NONE; retainDTDAttributeTypes = config.isRetainDTDAttributeTypes(); suppressDTDAttributeDefaults = !pipe.isExpandAttributeDefaults(); allowDisableOutputEscaping = (Boolean)config.getConfigurationProperty(FeatureKeys.USE_PI_DISABLE_OUTPUT_ESCAPING); } /** * Get the pipeline configuration * @return the pipeline configuration as supplied to {@link #setPipelineConfiguration(PipelineConfiguration)} */ public PipelineConfiguration getPipelineConfiguration() { return pipe; } /** * Get the Configuration object * @return the Saxon configuration */ public Configuration getConfiguration() { return pipe.getConfiguration(); } /** * Set whether "ignorable whitespace" should be ignored. This method is effective only * if called after setPipelineConfiguration, since the default value is taken from the * configuration. * @param ignore true if ignorable whitespace (whitespace in element content that is notified * via the {@link #ignorableWhitespace(char[], int, int)} method) should be ignored, false if * it should be treated as ordinary text. */ public void setIgnoreIgnorableWhitespace(boolean ignore) { ignoreIgnorable = ignore; } /** * Determine whether "ignorable whitespace" is ignored. This returns the value that was set * using {@link #setIgnoreIgnorableWhitespace} if that has been called; otherwise the value * from the configuration. * @return true if ignorable whitespace is being ignored */ public boolean isIgnoringIgnorableWhitespace() { return ignoreIgnorable; } /** * Receive notification of the beginning of a document. */ public void startDocument () throws SAXException { // System.err.println("ReceivingContentHandler#startDocument"); try { charsUsed = 0; namespacesUsed = 0; pipe.setLocationProvider(localLocator); receiver.setPipelineConfiguration(pipe); receiver.open(); receiver.startDocument(0); } catch (XPathException err) { throw new SAXException(err); } } /** * Receive notification of the end of a document */ public void endDocument () throws SAXException { // System.err.println("RCH: end document"); try { flush(true); receiver.endDocument(); receiver.close(); } catch (ValidationException err) { err.setLocator(locator); throw new SAXException(err); } catch (XPathException err) { throw new SAXException(err); } } /** * Supply a locator that can be called to give information about location in the source document * being parsed. */ public void setDocumentLocator (Locator locator) { this.locator = locator; } /** * Notify a namespace prefix to URI binding */ public void startPrefixMapping(String prefix, String uri) throws SAXException { //System.err.println("StartPrefixMapping " + prefix + "=" + uri); if (prefix.equals("xmlns")) { // the binding xmlns:xmlns="http://www.w3.org/2000/xmlns/" // should never be reported, but it's been known to happen return; } if (namespacesUsed >= namespaces.length) { NamespaceBinding[] n2 = new NamespaceBinding[namespacesUsed * 2]; System.arraycopy(namespaces, 0, n2, 0, namespacesUsed); namespaces = n2; } namespaces[namespacesUsed++] = new NamespaceBinding(prefix, uri); } /** * Notify that a namespace binding is going out of scope */ public void endPrefixMapping(String prefix) throws SAXException {} /** * Notify an element start event, including all the associated attributes */ public void startElement (String uri, String localname, String rawname, Attributes atts) throws SAXException { // System.err.println("ReceivingContentHandler#startElement " + // uri + "," + localname + "," + rawname + // " at line " + locator.getLineNumber() + " of " + locator.getSystemId()); //for (int a=0; a map2 = (uri.length() == 0 ? noNamespaceNameCache : nameCache.get(uri)); if (map2 == null) { map2 = new HashMap(50); nameCache.put(uri, map2); if (uri.length() == 0) { noNamespaceNameCache = map2; } } NodeName n = map2.get(rawname); // we use the rawname (qname) rather than the local name because we want a namecode rather than // a fingerprint - that is, the prefix matters. if (n == null) { if (uri.length()==0) { NoNamespaceName qn = new NoNamespaceName(localname); map2.put(rawname, qn); return qn; } else { String prefix = NameChecker.getPrefix(rawname); FingerprintedQName qn = new FingerprintedQName(prefix, uri, localname); map2.put(rawname, qn); return qn; } } else { return n; } } /** * Report the end of an element (the close tag) */ public void endElement (String uri, String localname, String rawname) throws SAXException { //System.err.println("ReceivingContentHandler#End element " + rawname); try { // don't attempt whitespace compression if this end tag follows a start tag flush(!afterStartTag); receiver.endElement(); } catch (ValidationException err) { err.maybeSetLocation(ExpressionLocation.makeFromSax(locator)); if (!err.hasBeenReported()) { try { pipe.getErrorListener().fatalError(err); } catch (TransformerException e) { // } } err.setHasBeenReported(true); throw new SAXException(err); } catch (XPathException err) { throw new SAXException(err); } afterStartTag = false; } /** * Report character data. Note that contiguous character data may be reported as a sequence of * calls on this method, with arbitrary boundaries */ public void characters (char ch[], int start, int length) throws SAXException { // System.err.println("characters (" + length + ")"); // need to concatenate chunks of text before we can decide whether a node is all-white while (charsUsed + length > buffer.length) { char[] newbuffer = new char[buffer.length*2]; System.arraycopy(buffer, 0, newbuffer, 0, charsUsed); buffer = newbuffer; slice = new CharSlice(buffer, 0, 0); } System.arraycopy(ch, start, buffer, charsUsed, length); charsUsed += length; } /** * Report character data classified as "Ignorable whitespace", that is, whitespace text nodes * appearing as children of elements with an element-only content model */ public void ignorableWhitespace (char ch[], int start, int length) throws SAXException { if (!ignoreIgnorable) { characters(ch, start, length); } } /** * Notify the existence of a processing instruction */ public void processingInstruction (String name, String remainder) throws SAXException { try { flush(true); if (!inDTD) { if (name==null) { // trick used by the old James Clark xp parser to notify a comment comment(remainder.toCharArray(), 0, remainder.length()); } else { // some parsers allow through PI names containing colons if (!getConfiguration().getNameChecker().isValidNCName(name)) { throw new SAXException("Invalid processing instruction name (" + name + ')'); } if (allowDisableOutputEscaping) { if (name.equals(Result.PI_DISABLE_OUTPUT_ESCAPING)) { //flush(); escapingDisabled = true; return; } else if (name.equals(Result.PI_ENABLE_OUTPUT_ESCAPING)) { //flush(); escapingDisabled = false; return; } } receiver.processingInstruction(name, Whitespace.removeLeadingWhitespace(remainder), 0, 0); } } } catch (XPathException err) { throw new SAXException(err); } } /** * Notify the existence of a comment. Note that in SAX this is part of LexicalHandler interface * rather than the ContentHandler interface. */ public void comment (char ch[], int start, int length) throws SAXException { try { flush(true); if (!inDTD) { receiver.comment(new CharSlice(ch, start, length), 0, 0); } } catch (XPathException err) { throw new SAXException(err); } } /** * Flush buffer for accumulated character data * @param compress true if compression of whitespace should be attempted. This is an expensive * operation, so we avoid doing it when we hit an end tag that follows after a start tag, as * it's not likely to succeed in that situation. * @throws XPathException if flushing the character data fails */ private void flush(boolean compress) throws XPathException { if (charsUsed > 0) { slice.setLength(charsUsed); CharSequence cs = (compress ? CompressedWhitespace.compress(slice) : slice); receiver.characters(cs, 0, escapingDisabled ? ReceiverOptions.DISABLE_ESCAPING : ReceiverOptions.WHOLE_TEXT_NODE); charsUsed = 0; escapingDisabled = false; } } /** * Notify a skipped entity. Saxon ignores this event */ public void skippedEntity(String name) throws SAXException {} // No-op methods to satisfy lexical handler interface /** * Register the start of the DTD. Saxon ignores the DTD; however, it needs to know when the DTD starts and * ends so that it can ignore comments in the DTD, which are reported like any other comment, but which * are skipped because they are not part of the XPath data model */ public void startDTD (String name, String publicId, String systemId) throws SAXException { inDTD = true; } /** * Register the end of the DTD. Comments in the DTD are skipped because they * are not part of the XPath data model */ public void endDTD () throws SAXException { inDTD = false; } public void startEntity (String name) throws SAXException {} public void endEntity (String name) throws SAXException {} public void startCDATA () throws SAXException {} public void endCDATA () throws SAXException {} ////////////////////////////////////////////////////////////////////////////// // Implement DTDHandler interface ////////////////////////////////////////////////////////////////////////////// public void notationDecl( String name, String publicId, String systemId) throws SAXException {} public void unparsedEntityDecl( String name, String publicId, String systemId, String notationName) throws SAXException { // Some (non-conformant) SAX parsers report the systemId as written. // We need to turn it into an absolute URL. String uri = systemId; if (locator != null) { try { URI suppliedURI = new URI(systemId); if (!suppliedURI.isAbsolute()) { String baseURI = locator.getSystemId(); if (baseURI != null) { // See bug 2167979 URI absoluteURI = new URI(baseURI).resolve(systemId); uri = absoluteURI.toString(); } } } catch (URISyntaxException err) { uri = systemId; // fallback } } try { receiver.setUnparsedEntity(name, uri, publicId); } catch (XPathException err) { throw new SAXException(err); } } private class LocalLocator implements SaxonLocator, SourceLocationProvider { // This class is needed to bridge a SAX Locator to a JAXP SourceLocator /** * Return the system identifier for the current document event. * @return A string containing the system identifier, or * null if none is available. */ public String getSystemId() { return (locator == null ? null : locator.getSystemId()); } /** * Return the public identifier for the current document event. * @return A string containing the public identifier, or * null if none is available. */ public String getPublicId() { return (locator==null ? null : locator.getPublicId()); } /** * Return the line number where the current document event ends. * @return The line number, or -1 if none is available. */ public int getLineNumber() { return (locator==null ? -1 : locator.getLineNumber()); } /** * Return the character position where the current document event ends. * @return The column number, or -1 if none is available. */ public int getColumnNumber() { return (locator==null ? -1 : locator.getColumnNumber()); } /** * Get the line number within the document or module containing a particular location * * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the line number within the document or module. */ public int getLineNumber(long locationId) { return (locator==null ? -1 : locator.getLineNumber()); } public int getColumnNumber(long locationId) { return (locator==null ? -1 : locator.getColumnNumber()); } /** * Get the URI of the document or module containing a particular location * * @param locationId identifier of the location in question (as passed down the Receiver pipeline) * @return the URI of the document or module. */ /*@Nullable*/ public String getSystemId(long locationId) { return (locator == null ? null : locator.getSystemId()); } } } // end of class ReceivingContentHandler // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/TransformerReceiver.java0000644000175000017500000000762611671711573026171 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Controller; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; /** * TransformerReceiver is similar in concept to the JAXP TransformerHandler, * except that it implements Saxon's Receiver interface rather than the standard * SAX2 interface. This means that it allows nodes with type annotations to be * passed down a pipeline from one transformation to another. */ public class TransformerReceiver extends ProxyReceiver { Controller controller; Builder builder; Result result; /** * Create a TransformerReceiver and initialise variables. * @param controller the Controller (Saxon's implementation of the JAXP {@link javax.xml.transform.Transformer}) */ public TransformerReceiver(Controller controller) { super(controller.makeBuilder()); this.controller = controller; this.builder = (Builder)getUnderlyingReceiver(); } /** * Start of event stream */ public void open() throws XPathException { builder.setSystemId(systemId); Receiver stripper = controller.makeStripper(builder); if (controller.getExecutable().stripsInputTypeAnnotations()) { stripper = controller.getConfiguration().getAnnotationStripper(stripper); } setUnderlyingReceiver(stripper); nextReceiver.open(); } /** * Get the Transformer used for this transformation * @return the transformer (which will always be an instance of {@link net.sf.saxon.Controller}) */ public Transformer getTransformer() { return controller; } /** * Set the SystemId of the document */ public void setSystemId(String systemId) { super.setSystemId(systemId); controller.setBaseOutputURI(systemId); } /** * Set the output destination of the transformation. This method must be called before * the transformation can proceed. * @param result the destination to which the transformation output will be written */ public void setResult(Result result) { this.result = result; } /** * Get the output destination of the transformation * @return the output destination. May be null if no destination has been set. */ /*@Nullable*/ public Result getResult() { return result; } /** * Override the behaviour of close() in ProxyReceiver, so that it fires off * the transformation of the constructed document */ public void close() throws XPathException { nextReceiver.close(); DocumentInfo doc = (DocumentInfo)builder.getCurrentRoot(); builder.reset(); builder = null; if (doc==null) { throw new XPathException("No source document has been built"); } if (result==null) { throw new XPathException("No output destination has been supplied"); } try { controller.transformDocument(doc, result); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/EventSource.java0000644000175000017500000000445111671711573024435 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.trans.XPathException; import javax.xml.transform.Source; /** * An implementation of the JAXP Source class that supplies a document in the form of a stream * of push events sent to a Receiver * @since 9.1 */ public abstract class EventSource implements Source { private String systemId; /** * Set the system identifier for this Source. *

*

The system identifier is optional if the source does not * get its data from a URL, but it may still be useful to provide one. * The application can use a system identifier, for example, to resolve * relative URIs and to include in error messages and warnings.

* @param systemId The system identifier as a URL string. */ public void setSystemId(String systemId) { this.systemId = systemId; } /** * Get the system identifier that was set with setSystemId. * @return The system identifier that was set with setSystemId, or null * if setSystemId was not called. */ public String getSystemId() { return systemId; } /** * Supply events to a Receiver. * @param out the Receiver to which events will be sent. It is the caller's responsibility * to initialize the receiver with a PipelineConfiguration, and to call the open() and close() * methods on the receiver before and after calling this send() method. * @throws net.sf.saxon.trans.XPathException if any error occurs */ public abstract void send(Receiver out) throws XPathException; } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/StreamWriterToReceiver.java0000644000175000017500000005171311671711573026616 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.lib.StandardURIChecker; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.BuiltInAtomicType; import net.sf.saxon.type.Untyped; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamWriter; import java.util.HashMap; import java.util.Map; /** * This class implements the XmlStreamWriter interface, translating the events into Saxon * Receiver events. The Receiver can be anything: a serializer, a schema validator, a tree builder. * *

The class will attempt to generate namespace prefixes where none have been supplied, unless the * inventPrefixes option is set to false. The preferred mode of use is to call the versions * of writeStartElement and writeAttribute that supply the prefix, URI, and * local name in full. If the prefix is omitted, the class attempts to invent a prefix. If the URI is * omitted, the name is assumed to be in no namespace. The writeNamespace

method should be * called only if there is a need to declare a namespace prefix that is not used on any element or * attribute name.

* *

The class will check all names, URIs, and character content for conformance against XML well-formedness * rules unless the checkValues option is set to false.

* * @since 9.3 */ public class StreamWriterToReceiver implements XMLStreamWriter { /** * The receiver to which events will be passed */ private Receiver receiver; /** * The Saxon NamePool */ private NamePool namePool; /** * The Name Checker */ private NameChecker nameChecker; /** * Flag to indicate whether names etc are to be checked for well-formedness */ private boolean isChecking = false; /** * The current depth of element nesting. -1 indicates outside startDocument/endDocument; non-negative * values indicate the number of open start element tags */ private int depth = -1; /** * The namespace context used to determine the namespace-prefix mappings * in scope. */ //protected NamespaceContext namespaceContext; /** * Flag set to true during processing of a start tag. */ private boolean inStartTag; /** * Flag indicating that an empty element has been requested. */ private boolean isEmptyElement; /** * Flag indicating that default prefixes should be allocated if the user does not declare them explicitly */ private boolean inventPrefixes = true; /** * inScopeNamespaces represents namespaces that have been declared in the XML stream */ private NamespaceReducer inScopeNamespaces; /** * declaredNamespaces represents prefix-to-uri bindings that have been set using setPrefix. These * do not necessarily correspond to namespace declarations appearing in the XML stream. Note that * this is a map from URIs to prefixes, not the other way around! */ private Map declaredNamespaces = new HashMap(10); /** * rootNamespaceContext is the namespace context supplied at the start, is the final fallback * for allocating a prefix to a URI */ private javax.xml.namespace.NamespaceContext rootNamespaceContext = null; /** * Constructor. Creates a StreamWriter as a front-end to a given Receiver. * @param receiver the Receiver that is to receive the events generated * by this StreamWriter. */ public StreamWriterToReceiver(Receiver receiver) { // Events are passed through a NamespaceReducer which maintains the namespace context // It also eliminates duplicate namespace declarations, and creates extra namespace declarations // where needed to support prefix-uri mappings used on elements and attributes PipelineConfiguration pipe = receiver.getPipelineConfiguration(); this.inScopeNamespaces = new NamespaceReducer(receiver); this.receiver = inScopeNamespaces; this.nameChecker = pipe.getConfiguration().getNameChecker(); this.namePool = pipe.getConfiguration().getNamePool(); } /** * Say whether prefixes are to be invented when none is specified by the user * @param invent true if prefixes are to be invented. Default is true; */ public void setInventPrefixes(boolean invent) { this.inventPrefixes = invent; } /** * Ask whether prefixes are to be invented when none is specified by the user * @return true if prefixes are to be invented. Default is true; */ public boolean isInventPrefixes() { return this.inventPrefixes; } /** * Say whether names and values are to be checked for conformance with XML rules * @param check true if names and values are to be checked. Default is true; */ public void setCheckValues(boolean check) { this.isChecking = check; } /** * Ask whether names and values are to be checked for conformance with XML rules * @return true if names and values are to be checked. Default is true; */ public boolean isCheckValues() { return this.isChecking; } public void writeStartElement(/*@NotNull*/ String localName) throws XMLStreamException { String uri = inScopeNamespaces.getURIForPrefix("", true); assert uri != null; writeStartElement("", localName, uri); } public void writeStartElement(String namespaceURI, String localName) throws XMLStreamException { String prefix = getPrefix(namespaceURI); boolean isDeclared = (prefix != null); if (!isDeclared) { if (inventPrefixes) { prefix = inventPrefix(namespaceURI); } else { throw new XMLStreamException("namespace " + namespaceURI + " has not been declared"); } } writeStartElement(prefix, localName, namespaceURI); } public void writeStartElement(/*@NotNull*/ String prefix, /*@NotNull*/ String localName, /*@NotNull*/ String namespaceURI) throws XMLStreamException { if (depth == -1) { writeStartDocument(); } try { if (!isValidURI(namespaceURI)) { throw new IllegalArgumentException("Invalid namespace URI: " + namespaceURI); } if (!isValidNCName(prefix)) { throw new IllegalArgumentException("Invalid prefix: " + prefix); } if (!isValidNCName(localName)) { throw new IllegalArgumentException("Invalid local name: " + localName); } startContent(); inStartTag = true; depth++; NodeName nc; if (namespaceURI.length()==0) { nc = new NoNamespaceName(localName); } else { nc = new FingerprintedQName(prefix, namespaceURI, localName); } receiver.startElement(nc, Untyped.getInstance(), 0, 0); inStartTag = true; } catch (XPathException err) { throw new XMLStreamException(err); } } /** * Creates a prefix that is not currently in use. * @param uri the URI for which a prefix is required * @return the chosen prefix */ private String inventPrefix(String uri) { String prefix = getPrefix(uri); if (prefix != null) { return prefix; } prefix = namePool.suggestPrefixForURI(uri); if (prefix != null) { return prefix; } int count = 0; while (true) { prefix = "ns" + count; if (inScopeNamespaces.getURIForPrefix(prefix, false) == null) { setPrefix(prefix, uri); return prefix; } count++; } } public void writeEmptyElement(String namespaceURI, String localName) throws XMLStreamException { writeStartElement(namespaceURI, localName); isEmptyElement = true; } public void writeEmptyElement(String prefix, String localName, String namespaceURI) throws XMLStreamException { writeStartElement(prefix, localName, namespaceURI); isEmptyElement = true; } public void writeEmptyElement(String localName) throws XMLStreamException { writeStartElement(localName); isEmptyElement = true; } /** * Indicate the end of a start tag if one is open (no action otherwise). * This will also write an end tag if the element was opened as an empty element. * @throws javax.xml.stream.XMLStreamException if an error occurs writing to the output stream */ private void startContent() throws XMLStreamException { if (inStartTag) { try { receiver.startContent(); } catch (XPathException err) { throw new XMLStreamException(err); } inStartTag = false; if (isEmptyElement) { isEmptyElement = false; writeEndElement(); } } } public void writeEndElement() throws XMLStreamException { if (depth <= 0) { throw new IllegalStateException("writeEndElement with no matching writeStartElement"); } // if (isEmptyElement) { // throw new IllegalStateException("writeEndElement called for an empty element"); // } try { startContent(); receiver.endElement(); depth--; } catch (XPathException err) { throw new XMLStreamException(err); } } public void writeEndDocument() throws XMLStreamException { if (depth == -1) { throw new IllegalStateException("writeEndDocument with no matching writeStartDocument"); } try { if (isEmptyElement) { startContent(); // which also ends the element and decrements depth } while (depth > 0) { writeEndElement(); } receiver.endDocument(); depth = -1; } catch (XPathException err) { throw new XMLStreamException(err); } } public void close() throws XMLStreamException { if (depth >= 0) { writeEndDocument(); } try { receiver.close(); } catch (XPathException err) { throw new XMLStreamException(err); } } public void flush() throws XMLStreamException { // no action } public void writeAttribute(String localName, String value) throws XMLStreamException { writeAttribute("", "", localName, value); } public void writeAttribute(/*@Nullable*/ String prefix, /*@Nullable*/ String namespaceURI, String localName, String value) throws XMLStreamException { if (!inStartTag) { throw new IllegalStateException("Cannot write attribute when not in a start tag"); } if (prefix == null) { prefix = ""; } if (namespaceURI == null) { namespaceURI = ""; } if (namespaceURI.length() != 0 && !isValidURI(namespaceURI)) { throw new IllegalArgumentException("Invalid attribute namespace URI: " + namespaceURI); } if (prefix.length() != 0 && !isValidNCName(prefix)) { throw new IllegalArgumentException("Invalid attribute prefix: " + prefix); } if (!isValidNCName(localName)) { throw new IllegalArgumentException("Invalid attribute local name: " + localName); } if (!isValidChars(value)) { throw new IllegalArgumentException("Invalid characters in attribute content: " + value); } try { NodeName nn = new FingerprintedQName(prefix, namespaceURI, localName); receiver.attribute(nn, BuiltInAtomicType.UNTYPED_ATOMIC, value, -1, 0); } catch (XPathException err) { throw new XMLStreamException(err); } } public void writeAttribute(String namespaceURI, String localName, String value) throws XMLStreamException { String prefix = getPrefix(namespaceURI); if (prefix == null) { if (inventPrefixes) { prefix = inventPrefix(namespaceURI); } else { throw new XMLStreamException("Namespace " + namespaceURI + " has not been declared"); } } writeAttribute(prefix, namespaceURI, localName, value); } public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException { if (!inStartTag) { throw new IllegalStateException("Cannot write namespace when not in a start tag"); } if (prefix == null || "".equals(prefix) || "xmlns".equals(prefix)) { writeDefaultNamespace(namespaceURI); return; } if (!isValidURI(namespaceURI)) { throw new IllegalArgumentException("Invalid namespace URI: " + namespaceURI); } if (!isValidNCName(prefix)) { throw new IllegalArgumentException("Invalid namespace prefix: " + prefix); } outputNamespaceDeclaration(prefix, namespaceURI); } public void writeDefaultNamespace(String namespaceURI) throws XMLStreamException { if (!inStartTag) { throw new IllegalStateException(); } if (!isValidURI(namespaceURI)) { throw new IllegalArgumentException("Invalid namespace URI: " + namespaceURI); } outputNamespaceDeclaration("", namespaceURI); } private void outputNamespaceDeclaration(String prefix, String namespaceURI) throws XMLStreamException { try { if (prefix == null) { prefix = ""; } receiver.namespace(new NamespaceBinding(prefix, namespaceURI), 0); } catch (XPathException err) { throw new XMLStreamException(err); } } public void writeComment(/*@Nullable*/ String data) throws XMLStreamException { if (data == null) { data = ""; } try { if (!isValidChars(data)) { throw new IllegalArgumentException("Invalid XML character in comment: " + data); } if (isChecking && data.contains("--")) { throw new IllegalArgumentException("Comment contains '--'"); } startContent(); receiver.comment(data, 0, 0); } catch (XPathException err) { throw new XMLStreamException(err); } } public void writeProcessingInstruction(String target) throws XMLStreamException { writeProcessingInstruction(target, ""); } public void writeProcessingInstruction(/*@NotNull*/ String target, /*@NotNull*/ String data) throws XMLStreamException { try { if (isChecking) { if (!isValidNCName(target) || "xml".equalsIgnoreCase(target)) { throw new IllegalArgumentException("Invalid PITarget: " + target); } if (!isValidChars(data)) { throw new IllegalArgumentException("Invalid character in PI data: " + data); } } startContent(); receiver.processingInstruction(target, data, 0, 0); } catch (XPathException err) { throw new XMLStreamException(err); } } public void writeCData(/*@NotNull*/ String data) throws XMLStreamException { writeCharacters(data); } public void writeDTD(String dtd) throws XMLStreamException { // no-op } public void writeEntityRef(String name) throws XMLStreamException { throw new UnsupportedOperationException("writeEntityRef"); } public void writeStartDocument() throws XMLStreamException { writeStartDocument(null, null); } public void writeStartDocument(/*@Nullable*/ String version) throws XMLStreamException { writeStartDocument(null, version); } public void writeStartDocument(/*@Nullable*/ String encoding, /*@Nullable*/ String version) throws XMLStreamException { if ("1.1".equals(version)) { nameChecker = Name11Checker.getInstance(); } if (depth != -1) { throw new IllegalStateException("writeStartDocument must be the first call"); } try { receiver.startDocument(0); } catch (XPathException err) { throw new XMLStreamException(err); } depth = 0; } public void writeCharacters(/*@Nullable*/ String text) throws XMLStreamException { if (text != null) { if (!isValidChars(text)) { throw new IllegalArgumentException("illegal XML character: " + text); } startContent(); try { receiver.characters(text, 0, 0); } catch (XPathException err) { throw new XMLStreamException(err); } } } public void writeCharacters(char[] text, int start, int len) throws XMLStreamException { writeCharacters(new String(text, start, len)); } public String getPrefix(String uri) { String prefix = declaredNamespaces.get(uri); if (prefix == null && rootNamespaceContext != null) { prefix = rootNamespaceContext.getPrefix(uri); } return prefix; } public void setPrefix(String prefix, String uri) { if (!isValidURI(uri)) { throw new IllegalArgumentException("Invalid namespace URI: " + uri); } if (!"".equals(prefix) && !isValidNCName(prefix)) { throw new IllegalArgumentException("Invalid namespace prefix: " + prefix); } declaredNamespaces.put(uri, prefix); //sic } public void setDefaultNamespace(String uri) throws XMLStreamException { setPrefix("", uri); } public void setNamespaceContext(javax.xml.namespace.NamespaceContext context) throws XMLStreamException { if (depth > 0) { throw new IllegalStateException("setNamespaceContext may only be called at the start of the document"); } // Unfortunately the JAXP NamespaceContext class does not allow us to discover all the namespaces // that were declared, nor to declare new ones. So we have to retain it separately rootNamespaceContext = context; } /*@Nullable*/ public javax.xml.namespace.NamespaceContext getNamespaceContext() { // Note: the spec is unclear. We return the namespace context that was supplied to setNamespaceContext, // regardless of any other subsequent additions return rootNamespaceContext; } public Object getProperty(String name) throws IllegalArgumentException { throw new IllegalArgumentException(name); } /** * Test whether a supplied name is a valid NCName * @param name the name to be tested * @return true if the name is valid or if checking is disabled */ private boolean isValidNCName(String name) { return !isChecking || nameChecker.isValidNCName(name); } /** * Test whether a supplied character string is valid in XML * @param text the string to be tested * @return true if the string is valid or if checking is disabled */ private boolean isValidChars(String text) { return !isChecking || (nameChecker.firstInvalidChar(text) == -1); } /** * Test whether a supplied namespace URI is a valid URI * @param uri the namespace URI to be tested * @return true if the name is valid or if checking is disabled */ private boolean isValidURI(String uri) { return !isChecking || StandardURIChecker.getInstance().isValidURI(uri); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/SourceLocationProvider.java0000644000175000017500000000205611671711573026636 0ustar mathieumathieupackage net.sf.saxon.event; /** * A SourceLocationProvider is a {@link LocationProvider} that represents locations * in the source document from which the events * are derived (as distinct from locations in a query or stylesheet of the instructions causing the * events) */ public interface SourceLocationProvider extends LocationProvider { } /// // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/CommentStripper.java0000644000175000017500000000760411671711573025331 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.NodeName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.tiny.CompressedWhitespace; import net.sf.saxon.tree.util.FastStringBuffer; import net.sf.saxon.type.SchemaType; /** * The CommentStripper class is a filter that removes all comments and processing instructions. * It also concatenates text nodes that are split by comments and PIs. This follows the rules for * processing stylesheets; it is also used for removing comments and PIs from the tree seen * by XPath expressions used to process XSD 1.1 assertions * @author Michael H. Kay */ public class CommentStripper extends ProxyReceiver { /*@Nullable*/ private CompressedWhitespace savedWhitespace = null; private FastStringBuffer buffer = new FastStringBuffer(FastStringBuffer.MEDIUM); /** * Default constructor for use in subclasses * @param next the next receiver in the pipeline */ public CommentStripper(Receiver next) { super(next); } public void startElement (NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { flush(); nextReceiver.startElement(nameCode, typeCode, locationId, properties); } /** * Callback interface for SAX: not for application use */ public void endElement () throws XPathException { flush(); nextReceiver.endElement(); } /** * Handle a text node. Because we're often handling stylesheets on this path, whitespace text * nodes will often be stripped but we can't strip them immediately because of the case * [element] [!-- comment --]text[/element], where the space before the comment is considered * significant. But it's worth going to some effort to avoid uncompressing the whitespace in the * more common case, so that it can easily be detected and stripped downstream. */ public void characters (CharSequence chars, int locationId, int properties) throws XPathException { if (chars instanceof CompressedWhitespace) { if (buffer.length() == 0 && savedWhitespace == null) { savedWhitespace = (CompressedWhitespace)chars; } else { ((CompressedWhitespace)chars).uncompress(buffer); } } else { if (savedWhitespace != null) { savedWhitespace.uncompress(buffer); savedWhitespace = null; } buffer.append(chars); } } /** * Remove comments */ public void comment (CharSequence chars, int locationId, int properties) {} /** * Remove processing instructions */ public void processingInstruction(String name, CharSequence data, int locationId, int properties) {} /** * Flush the character buffer * @throws net.sf.saxon.trans.XPathException if a failure occurs writing the output */ private void flush() throws XPathException { if (buffer.length() > 0) { nextReceiver.characters(buffer, 0, 0); } else if (savedWhitespace != null) { nextReceiver.characters(savedWhitespace, 0, 0); } savedWhitespace = null; buffer.setLength(0); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/CopyInformee.java0000644000175000017500000000304111671711573024564 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.om.NodeInfo; /** * A CopyInformee is an agent that receives extra information while a tree is being copied. Specifically, * each time an element node is copied to the receiver, before calling the startElement() method, the copying * code will first call notifyElementNode(), giving the informee extra information about the element currently * being copied. */ public interface CopyInformee { /** * Provide information about the node being copied. This method is called immediately before * the startElement call for the element node in question. * @param element the node being copied, which must be an element node * @return int a locationId to be used when referring to this element in the pipeline */ public int notifyElementNode(NodeInfo element); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/ContentHandlerProxyLocator.java0000644000175000017500000001124311671711573027466 0ustar mathieumathieupackage net.sf.saxon.event; import org.xml.sax.Locator; import java.util.Stack; /** * Implementation of Locator, used to supply location information to the ContentHandler. * *

When the ContentHandler is used to receive the results of a query or stylesheet, * the information supplied by the standard methods such as {@link #getSystemId} and * {@link #getLineNumber} relates to the position of the expression/instruction in the stylesheet * or query that caused the relevant nodes to be output.

* *

If the ContentHandler is used in other contexts, for example as the destination of an * IdentityTransformer, the information reflects the position in the source document.

* *

If the output property saxon:supply-source-locator was set to the * value "yes" (which in turn requires that tracing was enabled at compile time), the Locator will * also contain information about the current location in the source document (specifically, the position * of the context node). This will not always be 100% accurate, since there is some buffering of events * in the output pipeline: it reflects the context node at the time the event reaches the ContentHandler, * which may not be the same as the context node at the time the relevant instruction was executed; * however, it still provides some information that may be useful for diagnostics.

*/ public class ContentHandlerProxyLocator implements Locator { private ContentHandlerProxy parent = null; /** * Create the Locator for a ContentHandlerProxy * @param parent the ContentHandlerProxy */ public ContentHandlerProxyLocator(ContentHandlerProxy parent) { this.parent = parent; } // previously ContentHandlerProxy implemented Locator directly. However, this caused a clash // over the semantics of getSystemId(), which is inherited from both Receiver and Locator. // The getSystemId() method in the Receiver interface identifies the URI of the document represented // by the event stream. The getSystemId() method in this class typically returns the URI of the stylesheet // or query module that generated the event. /** * Get the Public ID * @return null (always) */ public String getPublicId() { return null; } /** * Get the System ID * @return the system ID giving the location in the query or stylesheet of the most recent event notified */ public String getSystemId() { final LocationProvider locationProvider = parent.getLocationProvider(); if (locationProvider == null) { return null; } else { return locationProvider.getSystemId(parent.getCurrentLocationId()); } } /** * Get the line number * @return the line number giving the location of the most recent event notified */ public int getLineNumber() { final LocationProvider locationProvider = parent.getLocationProvider(); if (locationProvider == null) { return -1; } else { return locationProvider.getLineNumber(parent.getCurrentLocationId()); } } /** * Get the column number * @return -1 (always) */ public int getColumnNumber() { return -1; } /** * Get the current item stack. This is a Stack, whose members are objects of class * {@link net.sf.saxon.om.Item}. The top item in the stack is the context node or atomic value; items * further down the stack represent previous context node or atomic value * @return the stack of context items */ /*@Nullable*/ public Stack getContextItemStack() { final ContentHandlerProxy.ContentHandlerProxyTraceListener traceListener = parent.getTraceListener(); if (traceListener == null) { return null; } else { return traceListener.getContextItemStack(); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/Builder.java0000644000175000017500000002134711671711573023564 0ustar mathieumathieupackage net.sf.saxon.event; import net.sf.saxon.Configuration; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.tiny.TinyDocumentImpl; import java.util.Date; /** * The abstract Builder class is responsible for taking a stream of SAX events * and constructing a Document tree. There is one concrete subclass for each * tree implementation. * @author Michael H. Kay */ public abstract class Builder implements Receiver { /** * Constant denoting a request for the default tree model */ public static final int UNSPECIFIED_TREE_MODEL = -1; /** * Constant denoting the "linked tree" in which each node is represented as an object */ public static final int LINKED_TREE = 0; /** * Alternative constant denoting the "linked tree" in which each node is represented as an object * Retained for backwards compatibility */ public static final int STANDARD_TREE = 0; /** * Constant denoting the "tiny tree" in which the tree is represented internally using arrays of integers */ public static final int TINY_TREE = 1; /** * Constant denoting the "tiny tree condensed", a variant of the tiny tree in which text and attribute nodes * sharing the same string value use shared storage for the value. */ public static final int TINY_TREE_CONDENSED = 2; public static final int JDOM_TREE = 3; public static final int JDOM2_TREE = 4; /*@NotNull*/ protected PipelineConfiguration pipe; /*@NotNull*/ protected Configuration config; /*@NotNull*/ protected NamePool namePool; /*@Nullable*/ protected String systemId; /*@Nullable*/ protected String baseURI; /*@Nullable*/ protected NodeInfo currentRoot; protected boolean lineNumbering = false; protected boolean started = false; protected boolean timing = false; protected boolean open = false; private long startTime; /** * Create a Builder and initialise variables */ public Builder() { } public Builder(PipelineConfiguration pipe) { this.pipe = pipe; config = pipe.getConfiguration(); lineNumbering = (lineNumbering || config.isLineNumbering()); namePool = config.getNamePool(); } public void setPipelineConfiguration(/*@NotNull*/ PipelineConfiguration pipe) { //System.err.println("Builder#setPipelineConfiguration pipe = " + pipe); // if (pipe == null) { // new NullPointerException("pipe not initialized").printStackTrace(); // } this.pipe = pipe; config = pipe.getConfiguration(); lineNumbering = (lineNumbering || config.isLineNumbering()); namePool = config.getNamePool(); } /*@NotNull*/ public PipelineConfiguration getPipelineConfiguration () { return pipe; } /** * Get the Configuration * @return the Saxon configuration */ /*@NotNull*/ public Configuration getConfiguration() { return config; } /** * Get a builder monitor for this builder. This must be called immediately after opening the builder, * and all events to the builder must thenceforth be sent via the BuilderMonitor. * @return a new BuilderMonitor appropriate to this kind of Builder; or null if the Builder does * not provide this service. The default implementation returns null. */ /*@Nullable*/ public BuilderMonitor getBuilderMonitor() { return null; } /** * The SystemId is equivalent to the document-uri property defined in the XDM data model. * It should be set only in the case of a document that is potentially retrievable via this URI. * This means it should not be set in the case of a temporary tree constructed in the course of * executing a query or transformation. * @param systemId the SystemId, that is, the document-uri. */ public void setSystemId(/*@Nullable*/ String systemId) { this.systemId = systemId; } /** * The SystemId is equivalent to the document-uri property defined in the XDM data model. * It should be set only in the case of a document that is potentially retrievable via this URI. * This means the value will be null in the case of a temporary tree constructed in the course of * executing a query or transformation. * @return the SystemId, that is, the document-uri. */ /*@Nullable*/ public String getSystemId() { return systemId; } /** * Set the base URI of the document node of the tree being constructed by this builder * @param baseURI the base URI */ public void setBaseURI(/*@Nullable*/ String baseURI) { this.baseURI = baseURI; } /** * Get the base URI of the document node of the tree being constructed by this builder * @return the base URI */ /*@Nullable*/ public String getBaseURI() { return baseURI; } ///////////////////////////////////////////////////////////////////////// // Methods setting and getting options for building the tree ///////////////////////////////////////////////////////////////////////// /** * Set line numbering on or off * @param lineNumbering set to true if line numbers are to be maintained for nodes in the tree being * constructed. */ public void setLineNumbering(boolean lineNumbering) { this.lineNumbering = lineNumbering; } /** * Set timing option on or off * @param on set to true to turn timing on. This causes the builder to display statistical information * about the tree that is constructed. It corresponds to the command line -t option */ public void setTiming(boolean on) { timing = on; } /** * Get timing option * @return true if timing information has been requested */ public boolean isTiming() { return timing; } public void open() { if (timing && !open) { getConfiguration().getStandardErrorOutput().println( "Building tree for " + getSystemId() + " using " + getClass()); startTime = (new Date()).getTime(); } open = true; } public void close() throws XPathException { if (timing && open) { long endTime = (new Date()).getTime(); getConfiguration().getStandardErrorOutput().println( "Tree built in " + (endTime - startTime) + " milliseconds"); if (currentRoot instanceof TinyDocumentImpl) { ((TinyDocumentImpl)currentRoot).showSize(); } startTime = endTime; } open = false; } /** * Ask whether this Receiver (or the downstream pipeline) makes any use of the type annotations * supplied on element and attribute events * @return true if the Receiver makes any use of this information. If false, the caller * may supply untyped nodes instead of supplying the type annotation */ public boolean usesTypeAnnotations() { return true; } /** * Get the current root node. This will normally be a document node, but if the root of the tree * is an element node, it can be an element. * @return the root of the tree that is currently being built, or that has been most recently built * using this builder */ /*@Nullable*/ public NodeInfo getCurrentRoot() { return currentRoot; } /** * Reset the builder to its initial state. The most important effect of calling this * method (implemented in subclasses) is to release any links to the constructed document * tree, allowing the memory occupied by the tree to released by the garbage collector even * if the Builder is still in memory. This can happen because the Builder is referenced from a * parser in the Configuration's parser pool. */ public void reset() { systemId = null; baseURI = null; currentRoot = null; lineNumbering = false; started = false; timing = false; open = false; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/event/FilterFactory.java0000644000175000017500000000214411671711573024745 0ustar mathieumathieupackage net.sf.saxon.event; /** * Factory class to create a ProxyReceiver which filters events on a push pipeline */ public interface FilterFactory { /** * Make a ProxyReceiver to filter events on a push pipeline * @param next the next receiver in the pipeline * @return a ProxyReceiver initialized to send events to the next receiver in the pipeine */ public ProxyReceiver makeFilter(Receiver next); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/Filter.java0000644000175000017500000003763511671711573022311 0ustar mathieumathieupackage net.sf.saxon; import net.sf.saxon.event.ContentHandlerProxy; import org.xml.sax.*; import org.xml.sax.ext.LexicalHandler; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.sax.SAXSource; import java.io.IOException; /** * Filter is an XMLFilter (a SAX2 filter) that performs a transformation * taking a SAX stream as input and producing a SAX stream as output. * @author Michael H. Kay */ public class Filter implements XMLFilter { private Controller controller; private XMLReader parser; private ContentHandler contentHandler; // destination for output of this filter private LexicalHandler lexicalHandler; // destination for output of this filter /** * Create a Filter and initialise variables. The constructor is protected, because * the Filter should be created using newXMLFilter() in the SAXTransformerFactory * class */ protected Filter(Controller controller) { this.controller = controller; } ////////////////////////////////////////////////////////////////// // Implement XMLFilter interface methods ////////////////////////////////////////////////////////////////// /** * Set the parent reader. * *

This method allows the application to link the filter to * a parent reader (which may be another filter). The argument * may not be null.

* * @param parent The parent reader (the supplier of SAX events). */ public void setParent (XMLReader parent) { parser = parent; } /** * Get the parent reader. * *

This method allows the application to query the parent * reader (which may be another filter). It is generally a * bad idea to perform any operations on the parent reader * directly: they should all pass through this filter.

* * @return The parent filter, or null if none has been set. */ public XMLReader getParent() { return parser; } /////////////////////////////////////////////////////////////////// // implement XMLReader interface methods /////////////////////////////////////////////////////////////////// /** * Look up the value of a feature. * *

The feature name is any fully-qualified URI. It is * possible for an XMLReader to recognize a feature name but * to be unable to return its value; this is especially true * in the case of an adapter for a SAX1 Parser, which has * no way of knowing whether the underlying parser is * performing validation or expanding external entities.

* *

All XMLReaders are required to recognize the * http://xml.org/sax/features/namespaces and the * http://xml.org/sax/features/namespace-prefixes feature names.

* * @param name The feature name, which is a fully-qualified URI. * @return The current state of the feature (true or false). * @exception org.xml.sax.SAXNotRecognizedException When the * XMLReader does not recognize the feature name. * @exception org.xml.sax.SAXNotSupportedException When the * XMLReader recognizes the feature name but * cannot determine its value at this time. * @see #setFeature */ public boolean getFeature (String name) throws SAXNotRecognizedException, SAXNotSupportedException { if (name.equals("http://xml.org/sax/features/namespaces")) { return true; } else if (name.equals("http://xml.org/sax/features/namespace-prefixes")) { return false; } else { throw new SAXNotRecognizedException(name); } } /** * Set the state of a feature. * *

The feature name is any fully-qualified URI. It is * possible for an XMLReader to recognize a feature name but * to be unable to set its value

* *

All XMLReaders are required to support setting * http://xml.org/sax/features/namespaces to true and * http://xml.org/sax/features/namespace-prefixes to false.

* *

Some feature values may be immutable or mutable only * in specific contexts, such as before, during, or after * a parse.

* * @param name The feature name, which is a fully-qualified URI. * @param value The requested state of the feature (true or false). * @exception org.xml.sax.SAXNotRecognizedException When the * XMLReader does not recognize the feature name. * @exception org.xml.sax.SAXNotSupportedException When the * XMLReader recognizes the feature name but * cannot set the requested value. * @see #getFeature */ public void setFeature (String name, boolean value) throws SAXNotRecognizedException, SAXNotSupportedException { if (name.equals("http://xml.org/sax/features/namespaces")) { if (!value) { throw new SAXNotSupportedException(name); } } else if (name.equals("http://xml.org/sax/features/namespace-prefixes")) { if (value) { throw new SAXNotSupportedException(name); } } else { throw new SAXNotRecognizedException(name); } } /** * Look up the value of a property. * *

The property name is any fully-qualified URI. It is * possible for an XMLReader to recognize a property name but * to be unable to return its state.

* *

XMLReaders are not required to recognize any specific * property names, though an initial core set is documented for * SAX2.

* *

Some property values may be available only in specific * contexts, such as before, during, or after a parse.

* *

Implementors are free (and encouraged) to invent their own properties, * using names built on their own URIs.

* * @param name The property name, which is a fully-qualified URI. * @return The current value of the property. * @exception org.xml.sax.SAXNotRecognizedException When the * XMLReader does not recognize the property name. * @exception org.xml.sax.SAXNotSupportedException When the * XMLReader recognizes the property name but * cannot determine its value at this time. * @see #setProperty */ public Object getProperty (String name) throws SAXNotRecognizedException, SAXNotSupportedException { if (name.equals("http://xml.org/sax/properties/lexical-handler")) { return lexicalHandler; } else { throw new SAXNotRecognizedException(name); } } /** * Set the value of a property. * *

The property name is any fully-qualified URI. It is * possible for an XMLReader to recognize a property name but * to be unable to set its value.

* *

XMLReaders are not required to recognize setting * any specific property names, though a core set is provided with * SAX2.

* *

Some property values may be immutable or mutable only * in specific contexts, such as before, during, or after * a parse.

* *

This method is also the standard mechanism for setting * extended handlers.

* * @param name The property name, which is a fully-qualified URI. * @param value The requested value for the property. * @exception org.xml.sax.SAXNotRecognizedException When the * XMLReader does not recognize the property name. * @exception org.xml.sax.SAXNotSupportedException When the * XMLReader recognizes the property name but * cannot set the requested value. */ public void setProperty (String name, Object value) throws SAXNotRecognizedException, SAXNotSupportedException { if (name.equals("http://xml.org/sax/properties/lexical-handler")) { if (value instanceof LexicalHandler) { lexicalHandler = (LexicalHandler)value; } else { throw new SAXNotSupportedException( "Lexical Handler must be instance of org.xml.sax.ext.LexicalHandler"); } } else { throw new SAXNotRecognizedException(name); } } /** * Register a content handler to receive the output of the transformation * filter. If the content handler is also a LexicalHandler, and if no LexicalHandler * is separately registered, the ContentHandler will also act as the LexicalHandler */ public void setContentHandler(ContentHandler handler) { contentHandler = handler; if (handler instanceof LexicalHandler && lexicalHandler==null) { lexicalHandler = (LexicalHandler)handler; } } /** * Get the ContentHandler registered using setContentHandler() */ public ContentHandler getContentHandler() { return contentHandler; } /** * Allow an application to register an entity resolver. * *

If the application does not register an entity resolver, * the XMLReader will perform its own default resolution.

* *

Applications may register a new or different resolver in the * middle of a parse, and the SAX parser must begin using the new * resolver immediately.

* * @param resolver The entity resolver. * @exception java.lang.NullPointerException If the resolver * argument is null. * @see #getEntityResolver */ public void setEntityResolver (EntityResolver resolver) { // XSLT output does not use entities, so the resolver is never used } /** * Return the current entity resolver. * * @return Always null, since no entity resolver is used even if one * is supplied. * @see #setEntityResolver */ /*@Nullable*/ public EntityResolver getEntityResolver () { return null; } /** * Allow an application to register a DTD event handler. * *

If the application does not register a DTD handler, all DTD * events reported by the SAX parser will be silently ignored.

* *

Applications may register a new or different handler in the * middle of a parse, and the SAX parser must begin using the new * handler immediately.

* * @param handler The DTD handler. * @exception java.lang.NullPointerException If the handler * argument is null. * @see #getDTDHandler */ public void setDTDHandler (DTDHandler handler) { // XSLT output does not include a DTD } /** * Return the current DTD handler. * * @return Always null, since no DTD handler is used even if one has been * supplied. * @see #setDTDHandler */ /*@Nullable*/ public DTDHandler getDTDHandler () { return null; } /** * Allow an application to register an error event handler. * *

If the application does not register an error handler, all * error events reported by the SAX parser will be silently * ignored; however, normal processing may not continue. It is * highly recommended that all SAX applications implement an * error handler to avoid unexpected bugs.

* *

Applications may register a new or different handler in the * middle of a parse, and the SAX parser must begin using the new * handler immediately.

* * @param handler The error handler. * @exception java.lang.NullPointerException If the handler * argument is null. * @see #getErrorHandler */ public void setErrorHandler (ErrorHandler handler) { // No effect } /** * Return the current error handler. * * @return The current error handler, or null if none * has been registered. * @see #setErrorHandler */ /*@Nullable*/ public ErrorHandler getErrorHandler () { return null; } /** * Parse an XML document - In the context of a Transformer, this means * perform a transformation. The method is equivalent to transform(). * * @param input The input source (the XML document to be transformed) * @exception org.xml.sax.SAXException Any SAX exception, possibly * wrapping another exception. * @exception java.io.IOException An IO exception from the parser, * possibly from a byte stream or character stream * supplied by the application. * @see org.xml.sax.InputSource * @see #parse(java.lang.String) * @see #setEntityResolver * @see #setDTDHandler * @see #setContentHandler * @see #setErrorHandler */ public void parse (InputSource input) throws IOException, SAXException { if (parser==null) { try { parser = Configuration.getPlatform().loadParser(); } catch (Exception err) { throw new SAXException(err); } } SAXSource source = new SAXSource(); source.setInputSource(input); source.setXMLReader(parser); ContentHandlerProxy result = new ContentHandlerProxy(); result.setPipelineConfiguration(controller.makePipelineConfiguration()); result.setUnderlyingContentHandler(contentHandler); if (lexicalHandler!=null) { result.setLexicalHandler(lexicalHandler); } try { //result.open(); result.setOutputProperties(controller.getOutputProperties()); controller.transform(source, result); } catch (TransformerException err) { Throwable cause = err.getException(); if (cause != null && cause instanceof SAXException) { throw (SAXException)cause; } else if (cause != null && cause instanceof IOException) { throw (IOException)cause; } else { throw new SAXException(err); } } } /** * Parse (that is, transform) an XML document given a system identifier (URI). * *

This method is a shortcut for the common case of reading a * document from a system identifier. It is the exact * equivalent of the following:

* *
     * parse(new InputSource(systemId));
     * 
* *

If the system identifier is a URL, it must be fully resolved * by the application before it is passed to the parser.

* * @param systemId The system identifier (URI). * @exception org.xml.sax.SAXException Any SAX exception, possibly * wrapping another exception. * @exception java.io.IOException An IO exception from the parser, * possibly from a byte stream or character stream * supplied by the application. * @see #parse(org.xml.sax.InputSource) */ public void parse (String systemId) throws IOException, SAXException { InputSource input = new InputSource(systemId); parse(input); } /** * Get the underlying Transformer. This is a Saxon-specific method that allows the * user to set parameters on the transformation, set a URIResolver or ErrorListener, etc. * New in Saxon 7.2 */ public Transformer getTransformer() { return controller; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/0000755000175000017500000000000012213124636021217 5ustar mathieumathieusaxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XPathCompiler.java0000644000175000017500000007205611671711573024624 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.expr.sort.RuleBasedSubstringMatcher; import net.sf.saxon.expr.sort.SimpleCollation; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.lib.StringCollator; import net.sf.saxon.sxpath.*; import net.sf.saxon.trans.DecimalFormatManager; import net.sf.saxon.trans.DecimalSymbols; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ValidationException; import net.sf.saxon.value.DecimalValue; import net.sf.saxon.value.SequenceType; import java.net.URI; import java.net.URISyntaxException; import java.text.Collator; import java.text.RuleBasedCollator; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * An XPathCompiler object allows XPath queries to be compiled. The compiler holds information that * represents the static context for an XPath expression. *

*

To construct an XPathCompiler, use the factory method * {@link Processor#newXPathCompiler}.

*

*

An XPathCompiler may be used repeatedly to compile multiple * queries. Any changes made to the XPathCompiler (that is, to the * static context) do not affect queries that have already been compiled. * An XPathCompiler may be used concurrently in multiple threads, but * it should not then be modified once initialized.

*

*

Changes to an XPathCompiler are cumulative. There is no simple way to reset * the XPathCompiler to its initial state; instead, simply create a new * XPathCompiler.

*

*

The XPathCompiler has the ability to maintain a cache of compiled * expressions. This is active only if enabled by calling {@link #setCaching(boolean)}. * If caching is enabled, then the compiler will recognize an attempt to compile * the same expression twice, and will avoid the cost of recompiling it. The cache * is emptied by any method that changes the static context for subsequent expressions, * for example, {@link #setBaseURI(java.net.URI)}. Unless the cache is emptied, * it grows indefinitely: compiled expressions are never discarded.

* * @since 9.0 */ public class XPathCompiler { private Processor processor; private IndependentContext env; private ItemType requiredContextItemType; /*@Nullable*/ private Map cache = null; private Map symbolsMap = null; /** * Protected constructor * * @param processor the s9api Processor */ protected XPathCompiler(Processor processor) { this.processor = processor; env = new IndependentContext(processor.getUnderlyingConfiguration()); } /** * Get the Processor from which this XPathCompiler was constructed * * @return the Processor to which this XPathCompiler belongs * @since 9.3 */ public Processor getProcessor() { return processor; } /** * Set whether XPath 1.0 backwards compatibility mode is to be used. In backwards compatibility * mode, more implicit type conversions are allowed in XPath expressions, for example it * is possible to compare a number with a string. The default is false (backwards compatibility * mode is off). * * @param option true if XPath 1.0 backwards compatibility is to be enabled, false if it is to * be disabled. */ public void setBackwardsCompatible(boolean option) { if (cache != null) { cache.clear(); } env.setBackwardsCompatibilityMode(option); } /** * Ask whether XPath 1.0 backwards compatibility mode is in force. * * @return true if XPath 1.0 backwards compatibility is enabled, false if it is disabled. */ public boolean isBackwardsCompatible() { return env.isInBackwardsCompatibleMode(); } /** * Say whether XPath expressions compiled using this XPathCompiler are * schema-aware. They will automatically be schema-aware if the method * {@link #importSchemaNamespace(String)} is called. An XPath expression * must be marked as schema-aware if it is to handle typed (validated) * input documents. * * @param schemaAware true if expressions are to be schema-aware, false otherwise * @since 9.3 */ public void setSchemaAware(boolean schemaAware) { env.setSchemaAware(schemaAware); } /** * Ask whether XPath expressions compiled using this XPathCompiler are * schema-aware. They will automatically be schema-aware if the method * {@link #importSchemaNamespace(String)} is called. An XPath expression * must be marked as schema-aware if it is to handle typed (validated) * input documents. * * @return true if expressions are to be schema-aware, false otherwise * @since 9.3 */ public boolean isSchemaAware() { return env.isSchemaAware(); } /** * Say whether an XPath 2.0 or XPath 3.0 processor is required. * * @param version Must be numerically equal to 1.0, 2.0 or 3.0. Currently * support for XPath 3.0 is incomplete: check the release notes. *

Setting the option to 1.0 requests an XPath 2.0 processor running in 1.0 compatibility mode; * this is equivalent to setting the language version to 2.0 and backwards compatibility mode to true.

* @throws IllegalArgumentException if the version is not numerically equal to 1.0, 2.0 or 3.0. * @since 9.3 */ public void setLanguageVersion(String version) { if (cache != null) { cache.clear(); } DecimalValue dv; try { dv = (DecimalValue) DecimalValue.makeDecimalValue(version, true).asAtomic(); } catch (ValidationException err) { throw new IllegalArgumentException("Language version must be in the form of a decimal number"); } if (DecimalValue.ONE.equals(dv)) { dv = DecimalValue.TWO; env.setBackwardsCompatibilityMode(true); } if (!DecimalValue.ONE.equals(dv) && !DecimalValue.TWO.equals(dv) && !DecimalValue.THREE.equals(dv)) { throw new IllegalArgumentException("Unknown XPath language version " + version); } env.setXPathLanguageLevel(dv); } /** * Ask whether an XPath 2.0 or XPath 3.0 processor is being used * * @return version: "2.0" or "3.0" * @since 9.3 */ public String getLanguageVersion() { return (env.getXPathLanguageLevel().equals(DecimalValue.TWO) ? "2.0" : "3.0"); } /** * Set the static base URI for XPath expressions compiled using this XPathCompiler. The base URI * is part of the static context, and is used to resolve any relative URIs appearing within an XPath * expression, for example a relative URI passed as an argument to the doc() function. If no * static base URI is supplied, then the current working directory is used. * * @param uri the base URI to be set in the static context. This must be an absolute URI. */ public void setBaseURI(URI uri) { if (cache != null) { cache.clear(); } if (!uri.isAbsolute()) { throw new IllegalArgumentException("Supplied base URI must be absolute"); } env.setBaseURI(uri.toString()); } /** * Get the static base URI for XPath expressions compiled using this XPathCompiler. The base URI * is part of the static context, and is used to resolve any relative URIs appearing within an XPath * expression, for example a relative URI passed as an argument to the doc() function. If no * static base URI has been explicitly set, this method returns null. * * @return the base URI from the static context */ public URI getBaseURI() { try { return new URI(env.getBaseURI()); } catch (URISyntaxException err) { throw new IllegalStateException(err); } } /** * Declare a namespace binding as part of the static context for XPath expressions compiled using this * XPathCompiler * * @param prefix The namespace prefix. If the value is a zero-length string, this method sets the default * namespace for elements and types. * @param uri The namespace URI. It is possible to specify a zero-length string to "undeclare" a namespace; * in this case the prefix will not be available for use, except in the case where the prefix * is also a zero length string, in which case the absence of a prefix implies that the name * is in no namespace. * @throws NullPointerException if either the prefix or uri is null. */ public void declareNamespace(String prefix, String uri) { if (cache != null) { cache.clear(); } env.declareNamespace(prefix, uri); } /** * Import a schema namespace: that is, add the element and attribute declarations and type definitions * contained in a given namespace to the static context for the XPath expression. *

*

This method will not cause the schema to be loaded. That must be done separately, using the * {@link SchemaManager}. This method will not fail if the schema has not been loaded (but in that case * the set of declarations and definitions made available to the XPath expression is empty). The schema * document for the specified namespace may be loaded before or after this method is called.

*

*

This method does not bind a prefix to the namespace. That must be done separately, using the * {@link #declareNamespace(String, String)} method.

* * @param uri The schema namespace to be imported. To import declarations in a no-namespace schema, * supply a zero-length string. * @since 9.1 */ public void importSchemaNamespace(String uri) { if (cache != null) { cache.clear(); } env.getImportedSchemaNamespaces().add(uri); env.setSchemaAware(true); } /** * Say whether undeclared variables are allowed. By default, they are not allowed. When * undeclared variables are allowed, it is not necessary to predeclare the variables that * may be used in the XPath expression; instead, a variable is automatically declared when a reference * to the variable is encountered within the expression. * * @param allow true if undeclared variables are allowed, false if they are not allowed. * @since 9.2 */ public void setAllowUndeclaredVariables(boolean allow) { if (cache != null) { cache.clear(); } env.setAllowUndeclaredVariables(allow); } /** * Ask whether undeclared variables are allowed. By default, they are not allowed. When * undeclared variables are allowed, it is not necessary to predeclare the variables that * may be used in the XPath expression; instead, a variable is automatically declared when a reference * to the variable is encountered within the expression. * * @return true if undeclared variables are allowed, false if they are not allowed. * @since 9.2 */ public boolean isAllowUndeclaredVariables() { return env.isAllowUndeclaredVariables(); } /** * Declare a variable as part of the static context for XPath expressions compiled using this * XPathCompiler. It is an error for the XPath expression to refer to a variable unless it has been * declared. This method declares the existence of the variable, but it does not * bind any value to the variable; that is done later, when the XPath expression is evaluated. * The variable is allowed to have any type (that is, the required type is item()*). * * @param qname The name of the variable, expressions as a QName */ public void declareVariable(QName qname) { if (cache != null) { cache.clear(); } env.declareVariable(qname.getNamespaceURI(), qname.getLocalName()); //declaredVariables.add(var); } /** * Declare a variable as part of the static context for XPath expressions compiled using this * XPathCompiler. It is an error for the XPath expression to refer to a variable unless it has been * declared. This method declares the existence of the variable, and defines the required type * of the variable, but it does not bind any value to the variable; that is done later, * when the XPath expression is evaluated. * * @param qname The name of the variable, expressed as a QName * @param itemType The required item type of the value of the variable * @param occurrences The allowed number of items in the sequence forming the value of the variable * @throws SaxonApiException if the requiredType is syntactically invalid or if it refers to namespace * prefixes or schema components that are not present in the static context */ public void declareVariable(QName qname, ItemType itemType, OccurrenceIndicator occurrences) throws SaxonApiException { if (cache != null) { cache.clear(); } XPathVariable var = env.declareVariable(qname.getNamespaceURI(), qname.getLocalName()); var.setRequiredType( SequenceType.makeSequenceType( itemType.getUnderlyingItemType(), occurrences.getCardinality())); } /** * Declare the static type of the context item. If this type is declared, and if a context item * is supplied when the query is invoked, then the context item must conform to this type (no * type conversion will take place to force it into this type). * * @param type the required type of the context item * @since 9.3 */ public void setRequiredContextItemType(ItemType type) { requiredContextItemType = type; env.setRequiredContextItemType(type.getUnderlyingItemType()); } /** * Get the required type of the context item. If no type has been explicitly declared for the context * item, an instance of AnyItemType (representing the type item()) is returned. * * @return the required type of the context item * @since 9.3 */ public ItemType getRequiredContextItemType() { return requiredContextItemType; } /** * Bind a collation URI to a collation * * @param uri the absolute collation URI * @param collation a {@link Collator} object that implements the required collation * @throws IllegalArgumentException if an attempt is made to rebind the standard URI * for the Unicode codepoint collation * @since 9.4 */ public void declareCollation(String uri, final java.text.Collator collation) { if (uri.equals(NamespaceConstant.CODEPOINT_COLLATION_URI)) { throw new IllegalArgumentException("Cannot declare the Unicode codepoint collation URI"); } StringCollator saxonCollation; if (collation instanceof RuleBasedCollator) { saxonCollation = new RuleBasedSubstringMatcher((RuleBasedCollator) collation); } else { saxonCollation = new SimpleCollation(collation); } env.getCollationMap().setNamedCollation(uri, saxonCollation); } /** * Declare the default collation * * @param uri the absolute URI of the default collation. This URI must have been bound to a collation * using the method {@link #declareCollation(String, Collator)} * @throws IllegalStateException if the collation URI has not been registered, unless it is the standard * Unicode codepoint collation which is registered implicitly * @since 9.4 */ public void declareDefaultCollation(String uri) { if (env.getCollationMap().getNamedCollation(uri) == null) { throw new IllegalStateException("Unknown collation " + uri); } env.getCollationMap().setDefaultCollationName(uri); } /** * Say whether the compiler should maintain a cache of compiled expressions. * * @param caching if set to true, caching of compiled expressions is enabled. * If set to false, any existing cache is cleared, and future compiled expressions * will not be cached until caching is re-enabled. The cache is also cleared * (but without disabling future caching) * if any method is called that changes the static context for compiling * expressions, for example {@link #declareVariable(QName)} or * {@link #declareNamespace(String, String)}. * @since 9.3 */ public void setCaching(boolean caching) { if (caching) { if (cache == null) { cache = new ConcurrentHashMap(); } } else { cache = null; } } /** * Ask whether the compiler is maintaining a cache of compiled expressions * * @return true if a cache is being maintained * @since 9.3 */ public boolean isCaching() { return cache != null; } /** * Compile an XPath expression, supplied as a character string. * * @param source A string containing the source text of the XPath expression * @return An XPathExecutable which represents the compiled xpath expression object. * The XPathExecutable may be run as many times as required, in the same or a different thread. * The XPathExecutable is not affected by any changes made to the XPathCompiler once it has been compiled. * @throws SaxonApiException if any static error is detected while analyzing the expression */ public XPathExecutable compile(String source) throws SaxonApiException { if (symbolsMap != null) { DecimalFormatManager dfm = env.getDecimalFormatManager(); for (QName format : symbolsMap.keySet()) { try { symbolsMap.get(format).checkDistinctRoles(); if (format == null) { dfm.setDefaultDecimalFormat(symbolsMap.get(format), 0); } else { dfm.setNamedDecimalFormat(net.sf.saxon.om.StructuredQName.fromClarkName(format.getClarkName()), symbolsMap.get(format), 0); } } catch (net.sf.saxon.trans.XPathException e) { throw new SaxonApiException(e); } } } if (cache != null) { synchronized (this) { XPathExecutable expr = cache.get(source); if (expr == null) { expr = internalCompile(source); cache.put(source, expr); } return expr; } } else { return internalCompile(source); } } private XPathExecutable internalCompile(String source) throws SaxonApiException { IndependentContext ic = env; if (ic.isAllowUndeclaredVariables()) { // self-declaring variables modify the static context. The XPathCompiler must not change state // as the result of compiling an expression, so we need to copy the static context. ic = new DedicatedStaticContext(env); for (Iterator iter = env.iterateExternalVariables(); iter.hasNext(); ) { XPathVariable var = (XPathVariable) iter.next(); XPathVariable var2 = ic.declareVariable(var.getVariableQName()); var2.setRequiredType(var.getRequiredType()); } } try { XPathEvaluator eval = new XPathEvaluator(processor.getUnderlyingConfiguration()); eval.setStaticContext(ic); XPathExpression cexp = eval.createExpression(source); cexp.getInternalExpression().getExecutable().setCollationMap(env.getCollationMap()); return new XPathExecutable(cexp, processor, ic); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Compile and evaluate an XPath expression, supplied as a character string, with a given * context item. * * @param expression A string containing the source text of the XPath expression * @param contextItem The context item to be used for evaluating the expression. This * may be null if the expression is to be evaluated with no context item. * @return the result of evaluating the XPath expression with this context item. Note that * the result is an iterable, so that it can be used in a construct such as * for (XdmItem item : xpath.evaluate("//x", doc) {...} * @throws SaxonApiException if any static error is detected while analyzing the expression, * or if any dynamic error is detected while evaluating it. * @since 9.3 */ public XdmValue evaluate(String expression, /*@Nullable*/ XdmItem contextItem) throws SaxonApiException { XPathSelector selector = compile(expression).load(); if (contextItem != null) { selector.setContextItem(contextItem); } return selector.evaluate(); } /** * Compile and evaluate an XPath expression whose result is expected to be * a single item, with a given context item. The expression is supplied as * a character string. * * @param expression A string containing the source text of the XPath expression * @param contextItem The context item to be used for evaluating the expression. This * may be null if the expression is to be evaluated with no context item. * @return the result of evaluating the XPath expression with this context item. * If the result is a singleton it is returned as an XdmItem; if it is an empty * sequence, the return value is null. If the expression returns a sequence of more than one item, * any items after the first are ignored. * @throws SaxonApiException if any static error is detected while analyzing the expression, * or if any dynamic error is detected while evaluating it. * @since 9.3 */ public XdmItem evaluateSingle(String expression, /*@Nullable*/ XdmItem contextItem) throws SaxonApiException { XPathSelector selector = compile(expression).load(); if (contextItem != null) { selector.setContextItem(contextItem); } return selector.evaluateSingle(); } /** * Compile an XSLT 2.0 pattern, supplied as a character string. The compiled pattern behaves as a boolean * expression which, when evaluated in a particular context, returns true if the context node matches * the pattern, and false if it does not. An error is reported if there is no context item or it the context * item is not a node. * * @param source A string conforming to the syntax of XSLT 2.0 patterns * @return An XPathExecutable representing an expression which evaluates to true when the context node matches * the pattern, and false when it does not. * @throws SaxonApiException if the pattern contains static errors: for example, if its syntax is incorrect, * or if it refers to undeclared variables or namespaces * @since 9.1 */ public XPathExecutable compilePattern(String source) throws SaxonApiException { if (symbolsMap != null) { DecimalFormatManager dfm = env.getDecimalFormatManager(); for (QName format : symbolsMap.keySet()) { try { symbolsMap.get(format).checkDistinctRoles(); if (format == null) { dfm.setDefaultDecimalFormat(symbolsMap.get(format), 0); } else { dfm.setNamedDecimalFormat(net.sf.saxon.om.StructuredQName.fromClarkName(format.getClarkName()), symbolsMap.get(format), 0); } } catch (net.sf.saxon.trans.XPathException e) { throw new SaxonApiException(e); } } } try { XPathEvaluator eval = new XPathEvaluator(processor.getUnderlyingConfiguration()); eval.setStaticContext(env); XPathExpression cexp = eval.createPattern(source); return new XPathExecutable(cexp, processor, env); } catch (XPathException e) { throw new SaxonApiException(e); } } private int checkSingleChar(String s) { int[] e = net.sf.saxon.value.StringValue.expand(s); if (e.length != 1) { throw new IllegalArgumentException("Attribute \"" + s + "\" should be a single character"); } return e[0]; } /** * Registers the required decimal format properties * * @param format The name of the decimal format * @param property The decimal symbols name to update * @param value The value to update the decimal symbol property * @throws SaxonApiException if there are two conflicting definitions of the named decimal-format * @since 9.4 */ public void setDecimalFormatProperty(QName format, String property, String value) throws SaxonApiException { if (symbolsMap == null) { symbolsMap = new HashMap(); } DecimalFormatManager dfm = env.getDecimalFormatManager(); if (dfm == null) { dfm = new DecimalFormatManager(); env.setDecimalFormatManager(dfm); } DecimalSymbols symbols; if (symbolsMap.get(format) != null) { symbols = symbolsMap.get(format); }else { symbols = new DecimalSymbols(); } if (property.equals("decimal-separator")) { symbols.decimalSeparator = checkSingleChar(value); } else if (property.equals("grouping-separator")) { symbols.groupingSeparator = checkSingleChar(value); } else if (property.equals("infinity")) { symbols.infinity = value; } else if (property.equals("NaN")) { symbols.NaN = value; } else if (property.equals("minus-sign")) { symbols.minusSign = checkSingleChar(value); } else if (property.equals("percent")) { symbols.percent = checkSingleChar(value); } else if (property.equals("per-mille")) { symbols.permill = checkSingleChar(value); } else if (property.equals("zero-digit")) { symbols.zeroDigit = checkSingleChar(value); } else if (property.equals("digit")) { symbols.digit = checkSingleChar(value); } else if (property.equals("pattern-separator")) { symbols.patternSeparator = checkSingleChar(value); } else { System.err.println("**** Unknown decimal format attribute " + property); } symbolsMap.put(format, symbols); } /** * Escape-hatch method to get the underlying static context object used by the implementation. * * @return the underlying static context object. In the current implementation this will always * be an instance of {@link IndependentContext}. *

*

This method provides an escape hatch to internal Saxon implementation objects that offer a finer and * lower-level degree of control than the s9api classes and methods. Some of these classes and methods may change * from release to release.

* @since 9.1 */ public StaticContext getUnderlyingStaticContext() { return env; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/ItemTypeFactory.java0000644000175000017500000005423411671711573025173 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.expr.parser.Token; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StandardNames; import net.sf.saxon.pattern.*; import net.sf.saxon.type.*; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.ObjectValue; /** * This class is used for creating ItemType objects. * *

The ItemTypeFactory class is thread-safe.

*/ public class ItemTypeFactory { private Processor processor; /** * Create an ItemTypeFactory * @param processor the processor used by this ItemTypeFactory. This must be supplied * in the case of user-defined types or types that reference element or attribute names; * for built-in types it can be omitted. */ public ItemTypeFactory(Processor processor) { this.processor = processor; } /** * Get an item type representing an atomic type. This may be a built-in type in the * XML Schema namespace, or a user-defined atomic type. The resulting type will use * the conversion rules configured for the supplied Processor. * *

It is undefined whether two calls supplying the same QName will return the same ItemType * object.

* @param name the name of the built-in or user-defined atomic type required * @return an ItemType object representing this built-in or user-defined atomic type * @throws SaxonApiException if the type name is not known, or if the type identified by the * name is not an atomic type. */ public ItemType getAtomicType(QName name) throws SaxonApiException { String uri = name.getNamespaceURI(); String local = name.getLocalName(); if (NamespaceConstant.SCHEMA.equals(uri)) { int fp = StandardNames.getFingerprint(uri, local); Configuration config = processor.getUnderlyingConfiguration(); if (config.getXsdVersion() == Configuration.XSD10 && config.getXMLVersion() == Configuration.XML10) { return getBuiltInAtomicType(fp); } else { return ItemType.BuiltInAtomicItemType.makeVariant( (ItemType.BuiltInAtomicItemType)getBuiltInAtomicType(fp), config.getConversionRules()); } } else { Configuration config = processor.getUnderlyingConfiguration(); int fp = config.getNamePool().allocate("", name.getNamespaceURI(), local) & NamePool.FP_MASK; SchemaType type = config.getSchemaType(fp); if (type == null || !type.isAtomicType()) { throw new SaxonApiException("Unknown atomic type " + name.getClarkName()); } return new ConstructedItemType((AtomicType)type, processor); } } private ItemType getBuiltInAtomicType(int fp) throws SaxonApiException { switch (fp) { case StandardNames.XS_ANY_ATOMIC_TYPE: return ItemType.ANY_ATOMIC_VALUE; case StandardNames.XS_NUMERIC: return ItemType.NUMERIC; case StandardNames.XS_STRING: return ItemType.STRING; case StandardNames.XS_BOOLEAN: return ItemType.BOOLEAN; case StandardNames.XS_DURATION: return ItemType.DURATION; case StandardNames.XS_DATE_TIME: return ItemType.DATE_TIME; case StandardNames.XS_DATE: return ItemType.DATE; case StandardNames.XS_TIME: return ItemType.TIME; case StandardNames.XS_G_YEAR_MONTH: return ItemType.G_YEAR_MONTH; case StandardNames.XS_G_MONTH: return ItemType.G_MONTH; case StandardNames.XS_G_MONTH_DAY: return ItemType.G_MONTH_DAY; case StandardNames.XS_G_YEAR: return ItemType.G_YEAR; case StandardNames.XS_G_DAY: return ItemType.G_DAY; case StandardNames.XS_HEX_BINARY: return ItemType.HEX_BINARY; case StandardNames.XS_BASE64_BINARY: return ItemType.BASE64_BINARY; case StandardNames.XS_ANY_URI: return ItemType.ANY_URI; case StandardNames.XS_QNAME: return ItemType.QNAME; case StandardNames.XS_NOTATION: return ItemType.NOTATION; case StandardNames.XS_UNTYPED_ATOMIC: return ItemType.UNTYPED_ATOMIC; case StandardNames.XS_DECIMAL: return ItemType.DECIMAL; case StandardNames.XS_FLOAT: return ItemType.FLOAT; case StandardNames.XS_DOUBLE: return ItemType.DOUBLE; case StandardNames.XS_INTEGER: return ItemType.INTEGER; case StandardNames.XS_NON_POSITIVE_INTEGER: return ItemType.NON_POSITIVE_INTEGER; case StandardNames.XS_NEGATIVE_INTEGER: return ItemType.NEGATIVE_INTEGER; case StandardNames.XS_LONG: return ItemType.LONG; case StandardNames.XS_INT: return ItemType.INT; case StandardNames.XS_SHORT: return ItemType.SHORT; case StandardNames.XS_BYTE: return ItemType.BYTE; case StandardNames.XS_NON_NEGATIVE_INTEGER: return ItemType.NON_NEGATIVE_INTEGER; case StandardNames.XS_POSITIVE_INTEGER: return ItemType.POSITIVE_INTEGER; case StandardNames.XS_UNSIGNED_LONG: return ItemType.UNSIGNED_LONG; case StandardNames.XS_UNSIGNED_INT: return ItemType.UNSIGNED_INT; case StandardNames.XS_UNSIGNED_SHORT: return ItemType.UNSIGNED_SHORT; case StandardNames.XS_UNSIGNED_BYTE: return ItemType.UNSIGNED_BYTE; case StandardNames.XS_YEAR_MONTH_DURATION: return ItemType.YEAR_MONTH_DURATION; case StandardNames.XS_DAY_TIME_DURATION: return ItemType.DAY_TIME_DURATION; case StandardNames.XS_NORMALIZED_STRING: return ItemType.NORMALIZED_STRING; case StandardNames.XS_TOKEN: return ItemType.TOKEN; case StandardNames.XS_LANGUAGE: return ItemType.LANGUAGE; case StandardNames.XS_NAME: return ItemType.NAME; case StandardNames.XS_NMTOKEN: return ItemType.NMTOKEN; case StandardNames.XS_NCNAME: return ItemType.NCNAME; case StandardNames.XS_ID: return ItemType.ID; case StandardNames.XS_IDREF: return ItemType.IDREF; case StandardNames.XS_ENTITY: return ItemType.ENTITY; case StandardNames.XS_DATE_TIME_STAMP: return ItemType.DATE_TIME_STAMP; default: throw new SaxonApiException("Unknown atomic type " + processor.getUnderlyingConfiguration().getNamePool().getClarkName(fp)); } } /** * Get an item type that matches any node of a specified kind. * *

This corresponds to the XPath syntactic forms element(), attribute(), * document-node(), text(), comment(), processing-instruction(). It also provides * an option, not available in the XPath syntax, that matches namespace nodes.

* *

It is undefined whether two calls supplying the same argument value will * return the same ItemType object.

* * @param kind the kind of node for which a NodeTest is required * @return an item type corresponding to the specified kind of node */ public ItemType getNodeKindTest(XdmNodeKind kind) { switch (kind) { case DOCUMENT: return new ConstructedItemType(NodeKindTest.DOCUMENT, processor); case ELEMENT: return new ConstructedItemType(NodeKindTest.ELEMENT, processor); case ATTRIBUTE: return new ConstructedItemType(NodeKindTest.ATTRIBUTE, processor); case TEXT: return new ConstructedItemType(NodeKindTest.TEXT, processor); case COMMENT: return new ConstructedItemType(NodeKindTest.COMMENT, processor); case PROCESSING_INSTRUCTION: return new ConstructedItemType(NodeKindTest.PROCESSING_INSTRUCTION, processor); case NAMESPACE: return new ConstructedItemType(NodeKindTest.NAMESPACE, processor); default: throw new IllegalArgumentException("XdmNodeKind"); } } /** * Get an item type that matches nodes of a specified kind with a specified name. * *

This corresponds to the XPath syntactic forms element(name), attribute(name), * and processing-instruction(name). In the case of processing-instruction, the supplied * QName must have no namespace.

* *

It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

* * @param kind the kind of nodes that match * @param name the name of the nodes that match * @return an ItemType that matches nodes of a given node kind with a given name * @throws IllegalArgumentException if the node kind is other than element, attribute, or * processing instruction, or if the node kind is processing instruction and the name is in a namespace. */ public ItemType getItemType(XdmNodeKind kind, QName name) { int k = kind.getNumber(); if (k == Type.ELEMENT || k == Type.ATTRIBUTE || k == Type.PROCESSING_INSTRUCTION) { if (k == Type.PROCESSING_INSTRUCTION && name.getNamespaceURI().length()==0) { throw new IllegalArgumentException("The name of a processing instruction must not be in a namespace"); } NameTest type = new NameTest(k, name.getNamespaceURI(), name.getLocalName(), processor.getUnderlyingConfiguration().getNamePool()); return new ConstructedItemType(type, processor); } else { throw new IllegalArgumentException("Node kind must be element, attribute, or processing-instruction"); } } /** * Make an ItemType representing an element declaration in the schema. This is the * equivalent of the XPath syntax schema-element(element-name) * *

It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

* * @param name the element name * @return the ItemType * @throws SaxonApiException if the schema does not contain a global element declaration * for the given name */ public ItemType getSchemaElementTest(QName name) throws SaxonApiException { Configuration config = processor.getUnderlyingConfiguration(); int fingerprint = config.getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); SchemaDeclaration decl = config.getElementDeclaration(fingerprint); if (decl == null) { throw new SaxonApiException("No global declaration found for element " + name.getClarkName()); } NodeTest test = decl.makeSchemaNodeTest(); return new ConstructedItemType(test, processor); } /** * Make an ItemType that tests an element name and/or schema type. This is the * equivalent of the XPath syntax element(element-name, type) * *

It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

* * @param name the element name, or null if there is no constraint on the name (equivalent to * specifying element(*, type)) * @param schemaType the name of the required schema type, or null if there is no constraint * on the type (equivalent to specifying element(name)) * @param nillable if a nilled element is allowed to match the type (equivalent to specifying * "?" after the type name). The value is ignored if schemaType is null. * @return the constructed ItemType * @throws SaxonApiException if the schema does not contain a global element declaration * for the given name */ public ItemType getElementTest(/*@Nullable*/ QName name, QName schemaType, boolean nillable) throws SaxonApiException { Configuration config = processor.getUnderlyingConfiguration(); NameTest nameTest = null; ContentTypeTest contentTest = null; if (name != null) { int elementFP = config.getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); nameTest = new NameTest(Type.ELEMENT, elementFP, config.getNamePool()); } if (schemaType != null) { int typeFP = config.getNamePool().allocate("", schemaType.getNamespaceURI(), schemaType.getLocalName()); SchemaType type = config.getSchemaType(typeFP); if (type == null) { throw new SaxonApiException("Unknown schema type " + schemaType.getClarkName()); } contentTest = new ContentTypeTest(Type.ELEMENT, type, config); contentTest.setNillable(nillable); } if (contentTest == null) { if (nameTest == null) { return getNodeKindTest(XdmNodeKind.ELEMENT); } else { return new ConstructedItemType(nameTest, processor); } } else { if (nameTest == null) { return new ConstructedItemType(contentTest, processor); } else { CombinedNodeTest combo = new CombinedNodeTest( nameTest, Token.INTERSECT, contentTest); return new ConstructedItemType(combo, processor); } } } /** * Get an ItemType representing an attribute declaration in the schema. This is the * equivalent of the XPath syntax schema-attribute(attribute-name) * *

It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

* * @param name the attribute name * @return the ItemType * @throws SaxonApiException if the schema does not contain a global attribute declaration * for the given name */ public ItemType getSchemaAttributeTest(QName name) throws SaxonApiException { Configuration config = processor.getUnderlyingConfiguration(); int fingerprint = config.getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); SchemaDeclaration decl = config.getAttributeDeclaration(fingerprint); if (decl == null) { throw new SaxonApiException("No global declaration found for attribute " + name.getClarkName()); } NodeTest test = decl.makeSchemaNodeTest(); return new ConstructedItemType(test, processor); } /** * Get an ItemType that tests an element name and/or schema type. This is the * equivalent of the XPath syntax element(element-name, type) * *

It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

* * @param name the element name, or null if there is no constraint on the name (equivalent to * specifying element(*, type)) * @param schemaType the name of the required schema type, or null of there is no constraint * on the type (equivalent to specifying element(name)) * @return the constructed ItemType * @throws SaxonApiException if the schema does not contain a global element declaration * for the given name */ public ItemType getAttributeTest(QName name, QName schemaType) throws SaxonApiException { NameTest nameTest = null; ContentTypeTest contentTest = null; Configuration config = processor.getUnderlyingConfiguration(); if (name != null) { int attributeFP = config.getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); nameTest = new NameTest(Type.ATTRIBUTE, attributeFP, config.getNamePool()); } if (schemaType != null) { int typeFP = config.getNamePool().allocate("", schemaType.getNamespaceURI(), schemaType.getLocalName()); SchemaType type = config.getSchemaType(typeFP); if (type == null) { throw new SaxonApiException("Unknown schema type " + schemaType.getClarkName()); } contentTest = new ContentTypeTest(Type.ATTRIBUTE, type, config); } if (contentTest == null) { if (nameTest == null) { return getNodeKindTest(XdmNodeKind.ATTRIBUTE); } else { return new ConstructedItemType(nameTest, processor); } } else { if (nameTest == null) { return new ConstructedItemType(contentTest, processor); } else { CombinedNodeTest combo = new CombinedNodeTest( nameTest, Token.INTERSECT, contentTest); return new ConstructedItemType(combo, processor); } } } /** * Make an ItemType representing a document-node() test with an embedded element test. * This reflects the XPath syntax document-node(element(N, T)) or * document-node(schema-element(N)). * *

It is undefined whether two calls supplying the same argument values will * return the same ItemType object.

* * @param elementTest the elementTest. An IllegalArgumentException is thrown if the supplied * ItemTest is not an elementTest or schemaElementTest. * @return a new ItemType representing the document test */ public ItemType getDocumentTest(ItemType elementTest) { net.sf.saxon.type.ItemType test = elementTest.getUnderlyingItemType(); if (test.getPrimitiveType() != Type.ELEMENT) { throw new IllegalArgumentException("Supplied itemType is not an element test"); } DocumentNodeTest docTest = new DocumentNodeTest((NodeTest)test); return new ConstructedItemType(docTest, processor); } /** * Get an ItemType representing the type of a Java object when used as an external object * for use in conjunction with calls on extension/external functions. * @param externalClass a Java class * @return the ItemType representing the type of external objects of this class */ public ItemType getExternalObjectType(Class externalClass) { ExternalObjectType type = new ExternalObjectType(externalClass, processor.getUnderlyingConfiguration()); return new ConstructedItemType(type, processor); } /** * Factory method to construct an "external object". This is an XDM value that wraps a Java * object. Such values can be passed as parameters to stylesheets or queries, for use in conjunction * with external (extension) functions. * *

Each call on this method will return a distinct XdmAtomicValue object.

* * @param object the value to be wrapped as an external object * @return the object, wrapped as an XdmAtomicValue */ public XdmAtomicValue getExternalObject(Object object) { ExternalObjectType type = new ExternalObjectType(object.getClass(), processor.getUnderlyingConfiguration()); return (XdmAtomicValue)XdmItem.wrap(new ObjectValue(object, type)); } /** * Get an ItemType representing the type of a supplied XdmItem. If the supplied item is * an atomic value, the returned ItemType will reflect the most specific atomic type of the * item. If the supplied item is a node, the returned item type will reflect the node kind, * and if the node has a name, then its name. It will not reflect the type annotation. * @param item the supplied item whose type is required * @return the type of the supplied item */ public ItemType getItemType(XdmItem item) { Configuration config = processor.getUnderlyingConfiguration(); if (item.isAtomicValue()) { AtomicValue value = (AtomicValue)item.getUnderlyingValue(); AtomicType type = (AtomicType)value.getItemType(config.getTypeHierarchy()); return new ConstructedItemType(type, processor); } else { NodeInfo node = (NodeInfo)item.getUnderlyingValue(); int kind = node.getNodeKind(); int fp = node.getFingerprint(); if (fp == -1) { return new ConstructedItemType(NodeKindTest.makeNodeKindTest(kind), processor); } else { return new ConstructedItemType(new NameTest(kind, fp, config.getNamePool()), processor); } } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/ItemType.java0000644000175000017500000004331211671711573023636 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.lib.StandardURIChecker; import net.sf.saxon.om.Item; import net.sf.saxon.om.Name10Checker; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.pattern.AnyNodeTest; import net.sf.saxon.pattern.NodeTest; import net.sf.saxon.type.*; import net.sf.saxon.value.AtomicValue; /** * An item type, as defined in the XPath/XQuery specifications. * *

This class contains a number of static constant fields * referring to instances that represent simple item types, such as * item(), node(), and xs:anyAtomicType. These named types are currently * based on the definitions in XSD 1.0 and XML 1.0. They may be changed in a future version to be based * on a later version.

* *

More complicated item types, especially those that are dependent on information in a schema, * are available using factory methods on the {@link ItemTypeFactory} object. The factory methods can * also be used to create variants of the types that use the rules given in the XML 1.1 and/or XSD 1.1 specifications.

*/ public abstract class ItemType { private static ConversionRules defaultConversionRules = new ConversionRules(); static { defaultConversionRules.setNameChecker(Name10Checker.getInstance()); defaultConversionRules.setStringToDoubleConverter(StringToDouble.getInstance()); defaultConversionRules.setNotationSet(null); defaultConversionRules.setURIChecker(StandardURIChecker.getInstance()); } /** * ItemType representing the type item(), that is, any item at all */ public static ItemType ANY_ITEM = new ItemType() { public ConversionRules getConversionRules() { return defaultConversionRules; } public boolean matches(XdmItem item) { return true; } public boolean subsumes(ItemType other) { return true; } public net.sf.saxon.type.ItemType getUnderlyingItemType() { return AnyItemType.getInstance(); } }; /** * ItemType representing the type node(), that is, any node */ public static final ItemType ANY_NODE = new ItemType() { public ConversionRules getConversionRules() { return defaultConversionRules; } public boolean matches(XdmItem item) { return item.getUnderlyingValue() instanceof NodeInfo; } public boolean subsumes(ItemType other) { return other.getUnderlyingItemType() instanceof NodeTest; } public net.sf.saxon.type.ItemType getUnderlyingItemType() { return AnyNodeTest.getInstance(); } }; /** * ItemType representing the type xs:anyAtomicType, that is, any atomic value */ public static final ItemType ANY_ATOMIC_VALUE = new ItemType() { public ConversionRules getConversionRules() { return defaultConversionRules; } public boolean matches(XdmItem item) { return item.getUnderlyingValue() instanceof AtomicValue; } public boolean subsumes(ItemType other) { return other.getUnderlyingItemType() instanceof AtomicType; } public net.sf.saxon.type.ItemType getUnderlyingItemType() { return BuiltInAtomicType.ANY_ATOMIC; } }; static class BuiltInAtomicItemType extends ItemType { private BuiltInAtomicType underlyingType; private ConversionRules conversionRules; public BuiltInAtomicItemType(BuiltInAtomicType underlyingType, ConversionRules conversionRules) { this.underlyingType = underlyingType; this.conversionRules = conversionRules; } public static BuiltInAtomicItemType makeVariant(BuiltInAtomicItemType type, ConversionRules conversionRules) { // TODO: allocate from a pool return new BuiltInAtomicItemType(type.underlyingType, conversionRules); } public ConversionRules getConversionRules() { return conversionRules; } public boolean matches(XdmItem item) { Item value = (Item)item.getUnderlyingValue(); if (!(value instanceof AtomicValue)) { return false; } AtomicType type = ((AtomicValue)value).getTypeLabel(); return subsumesUnderlyingType(type); } public boolean subsumes(ItemType other) { net.sf.saxon.type.ItemType otherType = other.getUnderlyingItemType(); if (!(otherType.isPlainType())) { return false; } AtomicType type = (AtomicType)otherType; return subsumesUnderlyingType(type); } private boolean subsumesUnderlyingType(AtomicType type) { BuiltInAtomicType builtIn = (type instanceof BuiltInAtomicType ? ((BuiltInAtomicType)type) : (BuiltInAtomicType)type.getBuiltInBaseType()); while (true) { if (builtIn.isSameType(underlyingType)) { return true; } SchemaType base = builtIn.getBaseType(); if (!(base instanceof BuiltInAtomicType)) { return false; } builtIn = (BuiltInAtomicType)base; } } public net.sf.saxon.type.ItemType getUnderlyingItemType() { return underlyingType; } } /** * A Saxon-specific item type representing the base type of double, float, and decimal */ public static final ItemType NUMERIC = new BuiltInAtomicItemType(BuiltInAtomicType.NUMERIC, defaultConversionRules); /** * ItemType representing the primitive type xs:string */ public static final ItemType STRING = new BuiltInAtomicItemType(BuiltInAtomicType.STRING, defaultConversionRules); /** * ItemType representing the primitive type xs:boolean */ public static final ItemType BOOLEAN = new BuiltInAtomicItemType(BuiltInAtomicType.BOOLEAN, defaultConversionRules); /** * ItemType representing the primitive type xs:duration */ public static final ItemType DURATION = new BuiltInAtomicItemType(BuiltInAtomicType.DURATION, defaultConversionRules); /** * ItemType representing the primitive type xs:dateTime */ public static final ItemType DATE_TIME = new BuiltInAtomicItemType(BuiltInAtomicType.DATE_TIME, defaultConversionRules); /** * ItemType representing the primitive type xs:date */ public static final ItemType DATE = new BuiltInAtomicItemType(BuiltInAtomicType.DATE, defaultConversionRules); /** * ItemType representing the primitive type xs:time */ public static final ItemType TIME = new BuiltInAtomicItemType(BuiltInAtomicType.TIME, defaultConversionRules); /** * ItemType representing the primitive type xs:gYearMonth */ public static final ItemType G_YEAR_MONTH = new BuiltInAtomicItemType(BuiltInAtomicType.G_YEAR_MONTH, defaultConversionRules); /** * ItemType representing the primitive type xs:gMonth */ public static final ItemType G_MONTH = new BuiltInAtomicItemType(BuiltInAtomicType.G_MONTH, defaultConversionRules); /** * ItemType representing the primitive type xs:gMonthDay */ public static final ItemType G_MONTH_DAY = new BuiltInAtomicItemType(BuiltInAtomicType.G_MONTH_DAY, defaultConversionRules); /** * ItemType representing the primitive type xs:gYear */ public static final ItemType G_YEAR = new BuiltInAtomicItemType(BuiltInAtomicType.G_YEAR, defaultConversionRules); /** * ItemType representing the primitive type xs:gDay */ public static final ItemType G_DAY = new BuiltInAtomicItemType(BuiltInAtomicType.G_DAY, defaultConversionRules); /** * ItemType representing the primitive type xs:hexBinary */ public static final ItemType HEX_BINARY = new BuiltInAtomicItemType(BuiltInAtomicType.HEX_BINARY, defaultConversionRules); /** * ItemType representing the primitive type xs:base64Binary */ public static final ItemType BASE64_BINARY = new BuiltInAtomicItemType(BuiltInAtomicType.BASE64_BINARY, defaultConversionRules); /** * ItemType representing the primitive type xs:anyURI */ public static final ItemType ANY_URI = new BuiltInAtomicItemType(BuiltInAtomicType.ANY_URI, defaultConversionRules); /** * ItemType representing the primitive type xs:QName */ public static final ItemType QNAME = new BuiltInAtomicItemType(BuiltInAtomicType.QNAME, defaultConversionRules); /** * ItemType representing the primitive type xs:NOTATION */ public static final ItemType NOTATION = new BuiltInAtomicItemType(BuiltInAtomicType.NOTATION, defaultConversionRules); /** * ItemType representing the XPath-defined type xs:untypedAtomic */ public static final ItemType UNTYPED_ATOMIC = new BuiltInAtomicItemType(BuiltInAtomicType.UNTYPED_ATOMIC, defaultConversionRules); /** * ItemType representing the primitive type xs:decimal */ public static final ItemType DECIMAL = new BuiltInAtomicItemType(BuiltInAtomicType.DECIMAL, defaultConversionRules); /** * ItemType representing the primitive type xs:float */ public static final ItemType FLOAT = new BuiltInAtomicItemType(BuiltInAtomicType.FLOAT, defaultConversionRules); /** * ItemType representing the primitive type xs:double */ public static final ItemType DOUBLE = new BuiltInAtomicItemType(BuiltInAtomicType.DOUBLE, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:integer */ public static final ItemType INTEGER = new BuiltInAtomicItemType(BuiltInAtomicType.INTEGER, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:nonPositiveInteger */ public static final ItemType NON_POSITIVE_INTEGER = new BuiltInAtomicItemType(BuiltInAtomicType.NON_POSITIVE_INTEGER, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:negativeInteger */ public static final ItemType NEGATIVE_INTEGER = new BuiltInAtomicItemType(BuiltInAtomicType.NEGATIVE_INTEGER, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:long */ public static final ItemType LONG = new BuiltInAtomicItemType(BuiltInAtomicType.LONG, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:int */ public static final ItemType INT = new BuiltInAtomicItemType(BuiltInAtomicType.INT, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:short */ public static final ItemType SHORT = new BuiltInAtomicItemType(BuiltInAtomicType.SHORT, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:byte */ public static final ItemType BYTE = new BuiltInAtomicItemType(BuiltInAtomicType.BYTE, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:nonNegativeInteger */ public static final ItemType NON_NEGATIVE_INTEGER = new BuiltInAtomicItemType(BuiltInAtomicType.NON_NEGATIVE_INTEGER, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:positiveInteger */ public static final ItemType POSITIVE_INTEGER = new BuiltInAtomicItemType(BuiltInAtomicType.POSITIVE_INTEGER, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:unsignedLong */ public static final ItemType UNSIGNED_LONG = new BuiltInAtomicItemType(BuiltInAtomicType.UNSIGNED_LONG, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:unsignedInt */ public static final ItemType UNSIGNED_INT = new BuiltInAtomicItemType(BuiltInAtomicType.UNSIGNED_INT, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:unsignedShort */ public static final ItemType UNSIGNED_SHORT = new BuiltInAtomicItemType(BuiltInAtomicType.UNSIGNED_SHORT, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:unsignedByte */ public static final ItemType UNSIGNED_BYTE = new BuiltInAtomicItemType(BuiltInAtomicType.UNSIGNED_BYTE, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:yearMonthDuration */ public static final ItemType YEAR_MONTH_DURATION = new BuiltInAtomicItemType(BuiltInAtomicType.YEAR_MONTH_DURATION, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:dayTimeDuration */ public static final ItemType DAY_TIME_DURATION = new BuiltInAtomicItemType(BuiltInAtomicType.DAY_TIME_DURATION, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:normalizedString */ public static final ItemType NORMALIZED_STRING = new BuiltInAtomicItemType(BuiltInAtomicType.NORMALIZED_STRING, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:token */ public static final ItemType TOKEN = new BuiltInAtomicItemType(BuiltInAtomicType.TOKEN, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:language */ public static final ItemType LANGUAGE = new BuiltInAtomicItemType(BuiltInAtomicType.LANGUAGE, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:Name */ public static final ItemType NAME = new BuiltInAtomicItemType(BuiltInAtomicType.NAME, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:NMTOKEN */ public static final ItemType NMTOKEN = new BuiltInAtomicItemType(BuiltInAtomicType.NMTOKEN, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:NCName */ public static final ItemType NCNAME = new BuiltInAtomicItemType(BuiltInAtomicType.NCNAME, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:ID */ public static final ItemType ID = new BuiltInAtomicItemType(BuiltInAtomicType.ID, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:IDREF */ public static final ItemType IDREF = new BuiltInAtomicItemType(BuiltInAtomicType.IDREF, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:ENTITY */ public static final ItemType ENTITY = new BuiltInAtomicItemType(BuiltInAtomicType.ENTITY, defaultConversionRules); /** * ItemType representing the built-in (but non-primitive) type xs:dateTimeStamp * (introduced in XSD 1.1) */ public static final ItemType DATE_TIME_STAMP = new BuiltInAtomicItemType(BuiltInAtomicType.DATE_TIME_STAMP, defaultConversionRules); /** * Get the conversion rules implemented by this type. The conversion rules reflect variations * between different versions of the W3C specifications, for example XSD 1.1 allows "+INF" as * a lexical representation of xs:double, while XSD 1.0 does not. * @return the conversion rules */ /*@Nullable*/ public abstract ConversionRules getConversionRules(); /** * Determine whether this item type matches a given item. * * @param item the item to be tested against this item type * @return true if the item matches this item type, false if it does not match. */ public abstract boolean matches(XdmItem item); /** * Determine whether this ItemType subsumes another ItemType. Specifically, * A.subsumes(B) is true if every value that matches the ItemType B also matches * the ItemType A. * @param other the other ItemType * @return true if this ItemType subsumes the other ItemType. This includes the case where A and B * represent the same ItemType. * @since 9.1 */ public abstract boolean subsumes(ItemType other); /** * Method to get the underlying Saxon implementation object * *

This gives access to Saxon methods that may change from one release to another.

* @return the underlying Saxon implementation object */ public abstract net.sf.saxon.type.ItemType getUnderlyingItemType(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/SchemaManager.java0000644000175000017500000001374611671711573024601 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.lib.SchemaURIResolver; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaException; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; /** * The SchemaManager is used to load schema documents, and to set options for the way in which they are loaded. * At present all the resulting schema components are held in a single pool owned by the Processor object. */ public class SchemaManager { private Configuration config; /*@Nullable*/ private ErrorListener errorListener; protected SchemaManager(Configuration config) { this.config = config; this.errorListener = null; } /** * Set the ErrorListener to be used while loading and validating schema documents * @param listener The error listener to be used. This is notified of all errors detected during the * compilation. May be set to null to revert to the default ErrorListener. */ public void setErrorListener(/*@Nullable*/ ErrorListener listener) { this.errorListener = listener; } /** * Get the ErrorListener being used while loading and validating schema documents * @return listener The error listener in use. This is notified of all errors detected during the * compilation. Returns null if no user-supplied ErrorListener has been set. */ /*@Nullable*/ public ErrorListener getErrorListener() { return errorListener; } /** * Set the SchemaURIResolver to be used during schema loading. This SchemaURIResolver, despite its name, * is not used for resolving relative URIs against a base URI; it is used for dereferencing * an absolute URI (after resolution) to return a {@link javax.xml.transform.Source} representing the * location where a schema document can be found. * *

This SchemaURIResolver is used to dereference the URIs appearing in xs:import, * xs:include, and xs:redefine declarations. * * @param resolver the SchemaURIResolver to be used during schema loading. */ public void setSchemaURIResolver(SchemaURIResolver resolver) { config.setSchemaURIResolver(resolver); } /** * Get the SchemaURIResolver to be used during schema loading. * * @return the URIResolver used during stylesheet compilation. Returns null if no user-supplied * URIResolver has been set. */ public SchemaURIResolver getSchemaURIResolver() { return config.getSchemaURIResolver(); } /** * Load a schema document from a given Source. The schema components derived from this schema * document are added to the cache of schema components maintained by this SchemaManager * @param source the document containing the schema. The getSystemId() method applied to this Source * must return a base URI suitable for resolving xs:include and xs:import * directives. * @throws SaxonApiException if the schema document is not valid, or if its contents are inconsistent * with the schema components already held by this SchemaManager. */ public void load(Source source) throws SaxonApiException { try { config.addSchemaSource(source, errorListener); } catch (SchemaException e) { throw new SaxonApiException(e); } } /** * Import a precompiled Schema Component Model from a given Source. The schema components derived from this schema * document are added to the cache of schema components maintained by this SchemaManager * @param source the XML file containing the schema component model, as generated by a previous call on * {@link #exportComponents} * @throws SaxonApiException if a failure occurs loading the schema from the supplied source */ public void importComponents(Source source) throws SaxonApiException { try { config.importComponents(source); } catch (XPathException err) { throw new SaxonApiException(err); } } /** * Export a precompiled Schema Component Model containing all the components (except built-in components) * that have been loaded into this Processor. * @param destination the destination to recieve the precompiled Schema Component Model in the form of an * XML document * @throws SaxonApiException if a failure occurs writing the schema components to the supplied destination */ public void exportComponents(Destination destination) throws SaxonApiException { try { Receiver out = destination.getReceiver(config); config.exportComponents(out); destination.close(); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Create a SchemaValidator which can be used to validate instance documents against the schema held by this * SchemaManager * @return a new SchemaValidator */ public SchemaValidator newSchemaValidator() { return new SchemaValidator(config); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XdmNode.java0000644000175000017500000004137411671711573023442 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.om.NamePool; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.pattern.NameTest; import net.sf.saxon.query.QueryResult; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.iter.AxisIterator; import net.sf.saxon.tree.wrapper.VirtualNode; import net.sf.saxon.type.Type; import net.sf.saxon.value.AtomicValue; import javax.xml.transform.Source; import java.net.URI; import java.net.URISyntaxException; /** * This class represents a node in the XDM data model. A Node is an {@link XdmItem}, and is therefore an * {@link XdmValue} in its own right, and may also participate as one item within a sequence value. *

*

An XdmNode is implemented as a wrapper around an object of type {@link net.sf.saxon.om.NodeInfo}. * Because this is a key interface within Saxon, it is exposed via this API.

*

*

The XdmNode interface exposes basic properties of the node, such as its name, its string value, and * its typed value. Navigation to other nodes is supported through a single method, {@link #axisIterator}, * which allows other nodes to be retrieved by following any of the XPath axes.

*

*

Note that node identity cannot be inferred from object identity. The same node may be represented * by different XdmNode instances at different times, or even at the same time. The equals() * method on this class can be used to test for node identity.

* @since 9.0 */ public class XdmNode extends XdmItem { /** * Construct an XdmNode as a wrapper around an existing NodeInfo object * @param node the NodeInfo object to be wrapped. This can be retrieved using the * {@link #getUnderlyingNode} method. * @since 9.2 (previously a protected constructor) */ public XdmNode(NodeInfo node) { super(node); } /** * Get the kind of node. * @return the kind of node, for example {@link XdmNodeKind#ELEMENT} or {@link XdmNodeKind#ATTRIBUTE} */ public XdmNodeKind getNodeKind() { switch (getUnderlyingNode().getNodeKind()) { case Type.DOCUMENT: return XdmNodeKind.DOCUMENT; case Type.ELEMENT: return XdmNodeKind.ELEMENT; case Type.ATTRIBUTE: return XdmNodeKind.ATTRIBUTE; case Type.TEXT: return XdmNodeKind.TEXT; case Type.COMMENT: return XdmNodeKind.COMMENT; case Type.PROCESSING_INSTRUCTION: return XdmNodeKind.PROCESSING_INSTRUCTION; case Type.NAMESPACE: return XdmNodeKind.NAMESPACE; default: throw new IllegalStateException("nodeKind"); } } /** * Get the name of the node, as a QName * * @return the name of the node. In the case of unnamed nodes (for example, text and comment nodes) * return null. */ /*@Nullable*/ public QName getNodeName() { NodeInfo n = getUnderlyingNode(); switch (n.getNodeKind()) { case Type.DOCUMENT: case Type.TEXT: case Type.COMMENT: return null; case Type.PROCESSING_INSTRUCTION: case Type.NAMESPACE: return new QName(new StructuredQName("", "", n.getLocalPart())); case Type.ELEMENT: case Type.ATTRIBUTE: return new QName(n.getPrefix(), n.getURI(), n.getLocalPart()); default: return null; } } /** * Get the typed value of this node, as defined in XDM * * @return the typed value. If the typed value is atomic, this will be returned as an instance * of {@link XdmAtomicValue} * @throws SaxonApiException if an error occurs obtaining the typed value, for example because * the node is an element with element-only content */ public XdmValue getTypedValue() throws SaxonApiException { try { ValueRepresentation v = getUnderlyingNode().atomize(); return XdmValue.wrap(v); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Get the line number of the node in a source document. For a document constructed using the document * builder, this is available only if the line numbering option was set when the document was built (and * then only for element nodes). If the line number is not available, the value -1 is returned. Line numbers * will typically be as reported by a SAX parser: this means that the line number for an element node is the * line number containing the closing ">" of the start tag. * @return the line number of the node, or -1 if not available. */ public int getLineNumber() { return getUnderlyingNode().getLineNumber(); } /** * Get the column number of the node in a source document. For a document constructed using the document * builder, this is available only if the line numbering option was set when the document was built (and * then only for element nodes). If the column number is not available, the value -1 is returned. Column numbers * will typically be as reported by a SAX parser: this means that the column number for an element node is the * position of the closing ">" of the start tag. * @return the column number of the node, or -1 if not available. */ public int getColumnNumber() { return getUnderlyingNode().getColumnNumber(); } /** * Get a JAXP Source object corresponding to this node, allowing the node to be * used as input to transformations or queries. * *

The Source object that is returned will generally be one that is acceptable to Saxon interfaces * that expect an instance of javax.xml.transform.Source. However, there is no guarantee * that it will be recognized by other products.

* *

In fact, the current implementation always returns an instance of * net.sf.saxon.om.NodeInfo.

* @return a Source object corresponding to this node */ public Source asSource() { return getUnderlyingNode(); } /** * Get an iterator over the nodes reachable from this node via a given axis. * * @param axis identifies which axis is to be navigated * @return an iterator over the nodes on the specified axis, starting from this node as the * context node. The nodes are returned in axis order, that is, in document order for a forwards * axis and in reverse document order for a reverse axis. */ public XdmSequenceIterator axisIterator(Axis axis) { AxisIterator base = getUnderlyingNode().iterateAxis(axis.getAxisNumber()); return new XdmSequenceIterator(base); } /** * Get an iterator over the nodes reachable from this node via a given axis, selecting only * those nodes with a specified name. * * @param axis identifies which axis is to be navigated * @param name identifies the name of the nodes to be selected. The selected nodes will be those * whose node kind is the principal node kind of the axis (that is, attributes for the attribute * axis, namespaces for the namespace axis, and elements for all other axes) whose name matches * the specified name. *

For example, specify new QName("", "item") to select nodes with local name * "item", in no namespace.

* @return an iterator over the nodes on the specified axis, starting from this node as the * context node. The nodes are returned in axis order, that is, in document order for a forwards * axis and in reverse document order for a reverse axis. */ public XdmSequenceIterator axisIterator(Axis axis, QName name) { int kind; switch (axis) { case ATTRIBUTE: kind = Type.ATTRIBUTE; break; case NAMESPACE: kind = Type.NAMESPACE; break; default: kind = Type.ELEMENT; break; } NamePool pool = getUnderlyingNode().getNamePool(); int nameCode = pool.allocate("", name.getNamespaceURI(), name.getLocalName()); NameTest test = new NameTest(kind, nameCode, pool); AxisIterator base = getUnderlyingNode().iterateAxis(axis.getAxisNumber(), test); return new XdmSequenceIterator(base); } /** * Get the parent of this node * * @return the parent of this node (a document or element node), or null if this node has no parent. */ public XdmNode getParent() { return (XdmNode) XdmValue.wrap(getUnderlyingNode().getParent()); } /** * Get the string value of a named attribute of this element * @param name the name of the required attribute * @return null if this node is not an element, or if this element has no * attribute with the specified name. Otherwise return the string value of the * selected attribute node. */ public String getAttributeValue(QName name) { int fp = getUnderlyingNode().getNamePool().allocate("", name.getNamespaceURI(), name.getLocalName()); return getUnderlyingNode().getAttributeValue(fp); } /** * Get the base URI of this node * * @return the base URI, as defined in the XDM model. The value may be null if no base URI is known for the * node, for example if the tree was built from a StreamSource with no associated URI, or if the node has * no parent. * @throws IllegalStateException if the base URI property of the underlying node is not a valid URI. */ public URI getBaseURI() { try { String uri = getUnderlyingNode().getBaseURI(); if (uri == null) { return null; } return new URI(uri); } catch (URISyntaxException e) { throw new IllegalStateException("baseURI", e); } } /** * Get the document URI of this node. * @return the document URI, as defined in the XDM model. Returns null if no document URI is known * @throws IllegalStateException if the document URI property of the underlying node is not a valid URI. * @since 9.1 */ public URI getDocumentURI() { try { String systemId = getUnderlyingNode().getSystemId(); return (systemId == null || systemId.length() == 0 ? null : new URI(systemId)); } catch (URISyntaxException e) { throw new IllegalStateException("documentURI", e); } } /** * The hashcode is such that two XdmNode instances have the same hashCode if they represent the same * node. Note that the same node might be represented by different XdmNode objects, but these will * compare equal. * * @return a hashCode representing node identity */ public int hashCode() { return getUnderlyingNode().hashCode(); } /** * The equals() relation between two XdmNode objects is true if they both represent the same * node. That is, it corresponds to the "is" operator in XPath. * * @param other the object to be compared * @return true if and only if the other object is an XdmNode instance representing the same node */ public boolean equals(Object other) { return other instanceof XdmNode && getUnderlyingNode().isSameNodeInfo(((XdmNode) other).getUnderlyingNode()); } /** * The toString() method returns a simple XML serialization of the node * with defaulted serialization parameters. * *

In the case of an element node, the result will be a well-formed * XML document serialized as defined in the W3C XSLT/XQuery serialization specification, * using options method="xml", indent="yes", omit-xml-declaration="yes".

* *

In the case of a document node, the result will be a well-formed * XML document provided that the document node contains exactly one element child, * and no text node children. In other cases it will be a well-formed external * general parsed entity.

* *

In the case of an attribute node, the output is a string in the form * name="value". The name will use the original namespace prefix.

* *

In the case of a namespace node, the output is a string in the form of a namespace * declaration, that is xmlns="uri" or xmlns:pre="uri".

* *

Other nodes, such as text nodes, comments, and processing instructions, are * represented as they would appear in lexical XML.

* *

For more control over serialization, use the {@link Serializer} class.

* * @return a simple XML serialization of the node. Under error conditions the method * may return an error message which will always begin with the label "Error: ". */ public String toString() { NodeInfo node = getUnderlyingNode(); if (node.getNodeKind() == Type.ATTRIBUTE) { String val = node.getStringValue().replace("\"", """); val = val.replace("<", "<"); val = val.replace("&", "&"); return node.getDisplayName() + "=\"" + val + '"'; } else if (node.getNodeKind() == Type.NAMESPACE) { String val = node.getStringValue().replace("\"", """); val = val.replace("<", "<"); val = val.replace("&", "&"); String name = node.getDisplayName(); name = (name.equals("") ? "xmlns" : "xmlns:" + name); return name + "=\"" + val + '"'; } try { return QueryResult.serialize(node); } catch (XPathException err) { throw new IllegalStateException(err); } } /** * Get the Processor that was used to construct this node. * @return the Processor used to construct this node, either via a {@link DocumentBuilder}, * or by executing XSLT or XQuery code. * @since 9.2 */ public Processor getProcessor() { Object p = getUnderlyingNode().getConfiguration().getProcessor(); if (p instanceof Processor) { return (Processor)p; } else { // I don't think this can happen, hence not a documented exception throw new IllegalStateException("Node was not created using a s9api Processor"); } } /** * Get the underlying Saxon implementation object representing this node. This provides * access to classes and methods in the Saxon implementation that may be subject to change * from one release to another. * * @return the underlying implementation object */ public NodeInfo getUnderlyingNode() { return (NodeInfo) getUnderlyingValue(); } /** * In the case of an XdmNode that wraps a node in an external object model such as DOM, JDOM, * XOM, or DOM4J, get the underlying wrapped node * @return the underlying external node if there is one, or null if this is not an XdmNode that * wraps such an external node * @since 9.1.0.2 */ public Object getExternalNode() { NodeInfo saxonNode = getUnderlyingNode(); if (saxonNode instanceof VirtualNode) { Object externalNode = ((VirtualNode)saxonNode).getRealNode(); return (externalNode instanceof NodeInfo ? null : externalNode); } else { return null; } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): // saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/DOMDestination.java0000644000175000017500000000513411671711573024717 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.dom.DOMWriter; import net.sf.saxon.event.Receiver; /** * This class represents a Destination (for example, the destination of the output of a transformation) * in which the results are written to a newly constructed DOM tree in memory. The caller must supply * a Document node, which will be used as the root of the constructed tree */ public class DOMDestination implements Destination { private DOMWriter domWriter; /** * Create a DOMDestination, supplying the root of a DOM document to which the * content of the result tree will be appended. * @param root the root node for the new tree. */ public DOMDestination(org.w3c.dom.Document root) { domWriter = new DOMWriter(); domWriter.setNode(root); } /** * Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. * * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. * @throws SaxonApiException * if the Receiver cannot be created */ public Receiver getReceiver(/*@NotNull*/ Configuration config) throws SaxonApiException { domWriter.setPipelineConfiguration(config.makePipelineConfiguration()); return domWriter; } /** * Close the destination, allowing resources to be released. Saxon calls this method when * it has finished writing to the destination. */ public void close() throws SaxonApiException { // no action } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XsltCompiler.java0000644000175000017500000003101511671711573024520 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.PreparedStylesheet; import net.sf.saxon.trace.XSLTTraceCodeInjector; import net.sf.saxon.trans.CompilerInfo; import net.sf.saxon.type.ValidationException; import net.sf.saxon.value.DecimalValue; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.URIResolver; /** * An XsltCompiler object allows XSLT 2.0 stylesheets to be compiled. The compiler holds information that * represents the static context for the compilation. * *

To construct an XsltCompiler, use the factory method {@link Processor#newXsltCompiler} on the Processor object.

* *

An XsltCompiler may be used repeatedly to compile multiple queries. Any changes made to the * XsltCompiler (that is, to the static context) do not affect queries that have already been compiled. * An XsltCompiler may be used concurrently in multiple threads, but it should not then be modified once * initialized.

* @since 9.0 */ public class XsltCompiler { private Processor processor; private Configuration config; private CompilerInfo compilerInfo; /** * Protected constructor. The public way to create an XsltCompiler is by using the factory method * {@link Processor#newXsltCompiler} . * @param processor the Saxon processor */ protected XsltCompiler(Processor processor) { this.processor = processor; this.config = processor.getUnderlyingConfiguration(); compilerInfo = new CompilerInfo(config.getDefaultXsltCompilerInfo()); } /** * Get the Processor from which this XsltCompiler was constructed * @return the Processor to which this XsltCompiler belongs * @since 9.3 */ public Processor getProcessor() { return processor; } /** * Set the URIResolver to be used during stylesheet compilation. This URIResolver, despite its name, * is not used for resolving relative URIs against a base URI; it is used for dereferencing * an absolute URI (after resolution) to return a {@link javax.xml.transform.Source} representing the * location where a stylesheet module can be found. * *

This URIResolver is used to dereference the URIs appearing in xsl:import, * xsl:include, and xsl:import-schema declarations. * It is not used at run-time for resolving requests to the document() or similar functions.

* * @param resolver the URIResolver to be used during stylesheet compilation. */ public void setURIResolver(URIResolver resolver) { compilerInfo.setURIResolver(resolver); } /** * Get the URIResolver to be used during stylesheet compilation. * * @return the URIResolver used during stylesheet compilation. Returns null if no user-supplied * URIResolver has been set. */ public URIResolver getURIResolver() { return compilerInfo.getURIResolver(); } /** * Set the ErrorListener to be used during this compilation episode * @param listener The error listener to be used. This is notified of all errors detected during the * compilation. */ public void setErrorListener(ErrorListener listener) { compilerInfo.setErrorListener(listener); } /** * Get the ErrorListener being used during this compilation episode * @return listener The error listener in use. This is notified of all errors detected during the * compilation. Returns null if no user-supplied ErrorListener has been set. */ public ErrorListener getErrorListener() { return compilerInfo.getErrorListener(); } /** * Say that the stylesheet must be compiled to be schema-aware, even if it contains no * xsl:import-schema declarations. Normally a stylesheet is treated as schema-aware * only if it contains one or more xsl:import-schema declarations. If it is not schema-aware, * then all input documents must be untyped, and validation of temporary trees is disallowed * (though validation of the final result tree is permitted). Setting the argument to true * means that schema-aware code will be compiled regardless. * @param schemaAware If true, the stylesheet will be compiled with schema-awareness * enabled even if it contains no xsl:import-schema declarations. If false, the stylesheet * is treated as schema-aware only if it contains one or more xsl:import-schema declarations. * @since 9.2 */ public void setSchemaAware(boolean schemaAware) { compilerInfo.setSchemaAware(schemaAware); } /** * Ask whether schema-awareness has been requested by means of a call on * {@link #setSchemaAware} * @return true if schema-awareness has been requested * @since 9.2 */ public boolean isSchemaAware() { return compilerInfo.isSchemaAware(); } /** * Set the XSLT (and XPath) language level to be supported by the processor. * @param version the language level to be supported. The value 2.0 requests a processor conforming to the * XSLT 2.0 specification; 3.0 requests an XSLT 3.0 processor, while the value "0.0" (which is the * default setting in the absence of a call on this method) gets a processor according to the * value of the version attribute on the xsl:stylesheet element. *

Although this interface can be used to run a 1.0 stylesheet, it is not possible to request * a 1.0 processor; Saxon will handle it as a 2.0 processor in backwards-compatibility mode, which * is not quite the same thing.

*

The value 2.1 is accepted temporarily as a synonym for 3.0

* @throws IllegalArgumentException if the value is not numerically equal to 0.0, 2.0, or 3.0 * @since 9.3 */ public void setXsltLanguageVersion(String version) { DecimalValue v; try { v = (DecimalValue)DecimalValue.makeDecimalValue(version, true).asAtomic(); } catch (ValidationException ve) { throw new IllegalArgumentException(ve); } if (DecimalValue.TWO_POINT_ONE.equals(v)) { v = DecimalValue.THREE; } if (!DecimalValue.TWO.equals(v) && !DecimalValue.THREE.equals(v)) { throw new IllegalArgumentException("LanguageVersion " + v); } compilerInfo.setXsltVersion(v); } /** * Get the XSLT (and XPath) language level supported by the processor. * @return the language level supported. The value 2.0 represents a processor conforming to the * XSLT 2.0 specification; 3.0 represents an XSLT 3.0 processor, while the value zero (which is the * default setting in the absence of a call on {@link #setXsltLanguageVersion} represents a processor * selected according to the value of the version attribute on the xsl:stylesheet element. * @since 9.3 */ public String getXsltLanguageVersion() { return compilerInfo.getXsltVersion().toString(); } /** * Set whether trace hooks are to be included in the compiled code. To use tracing, it is necessary * both to compile the code with trace hooks included, and to supply a TraceListener at run-time * @param option true if trace code is to be compiled in, false otherwise * @since 9.3 */ public void setCompileWithTracing(boolean option) { if (option) { compilerInfo.setCodeInjector(new XSLTTraceCodeInjector()); } else { compilerInfo.setCodeInjector(null); } } /** * Ask whether trace hooks are included in the compiled code. * @return true if trace hooks are included, false if not. * @since 9.3 */ public boolean isCompileWithTracing() { return compilerInfo.isCompileWithTracing(); } // /** // * Import a compiled XQuery function library. // * @param queryCompiler An XQueryCompiler that has been used to compile a library of XQuery functions // * (by using one of the overloaded methods named compileLibrary). // * @param namespace The namespace of the functions that are to be made available to the stylesheet. // * All the global functions with this namespace that are // * defined in libraries that have been compiled using this XQueryCompiler are added to the static context // * of the XSLT stylesheet. The stylesheet does not need to (and should not) contain a call on // * saxon:import-query to import these functions. // */ // // public void importXQueryLibrary(XQueryCompiler queryCompiler, String namespace) { // compilerInfo.importXQueryLibrary(queryCompiler.) // } /** * Compile a stylesheet. * *

Note: the term "compile" here indicates that the stylesheet is converted into an executable * form. There is no implication that this involves code generation.

* *

The source argument identifies the XML document holding the principal stylesheet module. Other * modules will be located relative to this module by resolving against the base URI that is defined * as the systemId property of the supplied Source.

* *

The following kinds of {@link javax.xml.transform.Source} are recognized:

* *
    *
  • {@link javax.xml.transform.stream.StreamSource}, allowing the stylesheet to be supplied as a * URI, as a {@link java.io.File}, as an {@link java.io.InputStream}, or as a {@link java.io.Reader}
  • *
  • {@link javax.xml.transform.sax.SAXSource}, allowing the stylesheet to be supplied as a stream * of SAX events from a SAX2-compliant XML parser (or any other source of SAX events)
  • *
  • {@link javax.xml.transform.dom.DOMSource}, allowing the stylesheet to be supplied as a * DOM tree. This option is available only if saxon9-dom.jar is on the classpath.
  • *
  • Document wrappers for XOM, JDOM, or DOM4J trees, provided the appropriate support libraries * are on the classpath
  • *
  • A Saxon NodeInfo, representing the root of a tree in any of the native tree formats supported * by Saxon
  • *
  • An {@link XdmNode} representing the document node of the stylesheet module
  • *
* @param source Source object representing the principal stylesheet module to be compiled * @return an XsltExecutable, which represents the compiled stylesheet. * @throws SaxonApiException if the stylesheet contains static errors or if it cannot be read. Note that * the exception that is thrown will not contain details of the actual errors found in the stylesheet. These * will instead be notified to the registered ErrorListener. The default ErrorListener displays error messages * on the standard error output. */ public XsltExecutable compile(/*@NotNull*/ Source source) throws SaxonApiException { try { PreparedStylesheet pss = PreparedStylesheet.compile(source, config, compilerInfo); return new XsltExecutable(processor, pss); } catch (TransformerConfigurationException e) { throw new SaxonApiException(e); } } /** * Get the underlying CompilerInfo object, which provides more detailed (but less stable) control * over some compilation options * @return the underlying CompilerInfo object, which holds compilation-time options. The methods on * this object are not guaranteed stable from release to release. */ public CompilerInfo getUnderlyingCompilerInfo() { return compilerInfo; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XsltExecutable.java0000644000175000017500000001455011671711573025034 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.PreparedStylesheet; import net.sf.saxon.expr.instruct.GlobalParam; import net.sf.saxon.expr.instruct.GlobalVariable; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.value.SequenceType; import java.util.HashMap; import java.util.Map; /** * An XsltExecutable represents the compiled form of a stylesheet. * To execute the stylesheet, it must first be loaded to form an {@link XsltTransformer}. * *

An XsltExecutable is immutable, and therefore thread-safe. * It is simplest to load a new XsltTransformer each time the stylesheet is to be run. * However, the XsltTransformer is serially reusable within a single thread.

* *

An XsltExecutable is created by using one of the compile methods on the * {@link XsltCompiler} class.

*/ public class XsltExecutable { Processor processor; PreparedStylesheet pss; protected XsltExecutable(Processor processor, PreparedStylesheet pss) { this.processor = processor; this.pss = pss; } /** * Load the stylesheet to prepare it for execution. * @return An XsltTransformer. The returned XsltTransformer can be used to set up the * dynamic context for stylesheet evaluation, and to run the stylesheet. */ public XsltTransformer load() { return new XsltTransformer(processor, (Controller)pss.newTransformer()); } /** * Produce a diagnostic representation of the compiled stylesheet, in XML form. *

The detailed form of this representation is not stable (or even documented).

* @param destination the destination for the XML document containing the diagnostic representation * of the compiled stylesheet * @since 9.1 */ public void explain(Destination destination) throws SaxonApiException { Configuration config = processor.getUnderlyingConfiguration(); pss.explain(new ExpressionPresenter(config, destination.getReceiver(config))); } /** * Get the whitespace stripping policy defined by this stylesheet, that is, the policy * defined by the xsl:strip-space and xsl:preserve-space elements in the stylesheet * @return a newly constructed WhitespaceStrippingPolicy based on the declarations in this * stylesheet. This policy can be used as input to a {@link DocumentBuilder}. */ public WhitespaceStrippingPolicy getWhitespaceStrippingPolicy() { return new WhitespaceStrippingPolicy(pss); } /** * Get the names of the xsl:param elements defined in this stylesheet, with details * of each parameter including its required type, and whether it is required or optional * @return a HashMap whose keys are the names of global parameters in the stylesheet, * and whose values are {@link ParameterDetails} objects giving information about the * corresponding parameter. * @since 9.3 */ /*@NotNull*/ public HashMap getGlobalParameters() { HashMap globals = pss.getCompiledGlobalVariables(); HashMap params = new HashMap(globals.size()); for (Map.Entry e : globals.entrySet()) { StructuredQName name = e.getKey(); GlobalVariable var = e.getValue(); if (var instanceof GlobalParam) { ParameterDetails details = new ParameterDetails(var.getRequiredType(), var.isRequiredParam()); params.put(new QName(name), details); } } return params; } /** * Inner class containing information about a global parameter to a compiled stylesheet * @since 9.3 */ public class ParameterDetails { private SequenceType type; private boolean isRequired; protected ParameterDetails(SequenceType type, boolean isRequired) { this.type = type; this.isRequired = isRequired; } /** * Get the declared item type of the parameter * @return the type defined in the as attribute of the xsl:param element, * without its occurrence indicator */ public ItemType getDeclaredItemType() { return new ConstructedItemType(type.getPrimaryType(), processor); } /** * Get the declared cardinality of the parameter * @return the occurrence indicator from the type appearing in the as attribute * of the xsl:param element */ public OccurrenceIndicator getDeclaredCardinality() { return OccurrenceIndicator.getOccurrenceIndicator(type.getCardinality()); } /** * Ask whether the parameter is required (mandatory) or optional * @return true if the parameter is mandatory (required="yes"), false * if it is optional */ public boolean isRequired() { return this.isRequired; } } /** * Get the underlying implementation object representing the compiled stylesheet. This provides * an escape hatch into lower-level APIs. The object returned by this method may change from release * to release. * @return the underlying implementation of the compiled stylesheet */ public PreparedStylesheet getUnderlyingCompiledStylesheet() { return pss; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/Processor.java0000644000175000017500000005506711671711573024067 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.Version; import net.sf.saxon.event.NamespaceReducer; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.TreeReceiver; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.lib.ExtensionFunctionCall; import net.sf.saxon.lib.ExtensionFunctionDefinition; import net.sf.saxon.om.*; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.SequenceType; import net.sf.saxon.value.Value; import javax.xml.transform.Source; import java.io.File; import java.io.OutputStream; import java.io.Writer; /** * The Processor class serves three purposes: it allows global Saxon configuration options to be set; * it acts as a factory for generating XQuery, XPath, and XSLT compilers; and it owns certain shared * resources such as the Saxon NamePool and compiled schemas. This is the first object that a * Saxon application should create. Once established, a Processor may be used in multiple threads. *

*

It is possible to run more than one Saxon Processor concurrently, but only when running completely * independent workloads. Nothing can be shared between Processor instances. Within a query or transformation, * all source documents and schemas must be built using the same Processor, which must also be used to * compile the query or stylesheet.

*/ public class Processor { private Configuration config; private SchemaManager schemaManager; /** * Create a Processor * * @param licensedEdition indicates whether the Processor requires features of Saxon that need a license * file (that is, features not available in Saxon HE (Home Edition). If true, the method will create * a Configuration appropriate to the version of the software that is running: for example, if running * Saxon-EE, it will create an EnterpriseConfiguration. The method does not at this stage check that a license * is available, and in the absence of a license, it should run successfully provided no features that * require licensing are actually used. If the argument is set to false, a plain Home Edition Configuration * is created unconditionally. */ public Processor(boolean licensedEdition) { if (licensedEdition) { config = Configuration.newConfiguration(); if (config.getEditionCode().equals("EE")) { schemaManager = new SchemaManager(config); } } else { config = new Configuration(); } config.setProcessor(this); } /** * Create a Processor based on an existing Configuration. This constructor is useful for transition, * when new components of an application are to use s9api interfaces but existing components use lower-level * interfaces. * * @param config the Configuration to be used by this processor * @since 9.3 */ public Processor(/*@NotNull*/ Configuration config) { this.config = config; if (config.getEditionCode().equals("EE")) { schemaManager = new SchemaManager(config); } } /** * Create a Processor configured according to the settings in a supplied configuration file. * * @param source the Source of the configuration file * @throws SaxonApiException if the configuration file cannot be read, or its contents are invalid * @since 9.2 */ public Processor(Source source) throws SaxonApiException { try { config = Configuration.readConfiguration(source); schemaManager = new SchemaManager(config); } catch (XPathException e) { throw new SaxonApiException(e); } config.setProcessor(this); } /** * Create a DocumentBuilder. A DocumentBuilder is used to load source XML documents. * * @return a newly created DocumentBuilder */ /*@NotNull*/ public DocumentBuilder newDocumentBuilder() { return new DocumentBuilder(config); } /** * Create an XPathCompiler. An XPathCompiler is used to compile XPath expressions. * * @return a newly created XPathCompiler */ /*@NotNull*/ public XPathCompiler newXPathCompiler() { return new XPathCompiler(this); } /** * Create an XsltCompiler. An XsltCompiler is used to compile XSLT stylesheets. * * @return a newly created XsltCompiler * @throws UnsupportedOperationException if this version of the Saxon product does not support XSLT processing */ /*@NotNull*/ public XsltCompiler newXsltCompiler() { return new XsltCompiler(this); } /** * Create an XQueryCompiler. An XQueryCompiler is used to compile XQuery queries. * * @return a newly created XQueryCompiler * @throws UnsupportedOperationException if this version of the Saxon product does not support XQuery processing */ /*@NotNull*/ public XQueryCompiler newXQueryCompiler() { return new XQueryCompiler(this); } /** * Create a Serializer * * @return a new Serializer * @since 9.3 */ /*@NotNull*/ public Serializer newSerializer() { Serializer s = new Serializer(); s.setProcessor(this); return s; } /** * Create a Serializer initialized to write to a given OutputStream. *

Closing the output stream after use is the responsibility of the caller.

* * @param stream The OutputStream to which the Serializer will write * @return a new Serializer * @since 9.3 */ /*@NotNull*/ public Serializer newSerializer(OutputStream stream) { Serializer s = new Serializer(); s.setProcessor(this); s.setOutputStream(stream); return s; } /** * Create a Serializer initialized to write to a given Writer. *

Closing the writer after use is the responsibility of the caller.

* * @param writer The Writer to which the Serializer will write * @return a new Serializer * @since 9.3 */ /*@NotNull*/ public Serializer newSerializer(Writer writer) { Serializer s = new Serializer(); s.setProcessor(this); s.setOutputWriter(writer); return s; } /** * Create a Serializer initialized to write to a given File. * * @param file The File to which the Serializer will write * @return a new Serializer * @since 9.3 */ /*@NotNull*/ public Serializer newSerializer(File file) { Serializer s = new Serializer(); s.setProcessor(this); s.setOutputFile(file); return s; } /** * Register a simple external/extension function that is to be made available within any stylesheet, query, * or XPath expression compiled under the control of this processor. *

*

This interface provides only for simple extension functions that have no side-effects and no dependencies * on the static or dynamic context. * * @param function the implementation of the extension function.

* @since 9.4 */ public void registerExtensionFunction(ExtensionFunction function) { ExtensionFunctionDefinitionWrapper wrapper = new ExtensionFunctionDefinitionWrapper(function); registerExtensionFunction(wrapper); } /** * Register an extension function that is to be made available within any stylesheet, query, * or XPath expression compiled under the control of this processor. This method * registers an extension function implemented as an instance of * {@link net.sf.saxon.lib.ExtensionFunctionDefinition}, using an arbitrary name and namespace. *

*

This interface allows extension functions that have dependencies on the static or dynamic * context. It also allows an extension function to declare that it has side-effects, in which * case calls to the function will be optimized less aggressively than usual, although the semantics * are still to some degree unpredictable.

* * @param function the implementation of the extension function. * @since 9.2 */ public void registerExtensionFunction(ExtensionFunctionDefinition function) { try { config.registerExtensionFunction(function); } catch (Exception err) { throw new IllegalArgumentException(err); } } /** * Get the associated SchemaManager. The SchemaManager provides capabilities to load and cache * XML schema definitions. There is exactly one SchemaManager in a schema-aware Processor, and none * in a Processor that is not schema-aware. The SchemaManager is created automatically by the system. * * @return the associated SchemaManager, or null if the Processor is not schema-aware. */ public SchemaManager getSchemaManager() { return schemaManager; } /** * Test whether this processor is schema-aware * * @return true if this this processor is licensed for schema processing, false otherwise */ public boolean isSchemaAware() { return config.isLicensedFeature(Configuration.LicenseFeature.SCHEMA_VALIDATION); } /** * Get the user-visible Saxon product version, for example "9.0.0.1" * * @return the Saxon product version, as a string */ public String getSaxonProductVersion() { return Version.getProductVersion(); } /** * Set the version of XML used by this Processor. If the value is set to "1.0", then * output documents will be serialized as XML 1.0. This option also affects * the characters permitted to appear in queries and stylesheets, and the characters that can appear * in names (for example, in path expressions). *

*

Note that source documents specifying xml version="1.0" or "1.1" are accepted * regardless of this setting.

* * @param version must be one of the strings "1.0" or "1.1" * @throws IllegalArgumentException if any string other than "1.0" or "1.1" is supplied */ public void setXmlVersion(/*@NotNull*/ String version) { if (version.equals("1.0")) { config.setXMLVersion(Configuration.XML10); } else if (version.equals("1.1")) { config.setXMLVersion(Configuration.XML11); } else { throw new IllegalArgumentException("XmlVersion"); } } /** * Get the version of XML used by this Processor. If the value is "1.0", then input documents * must be XML 1.0 documents, and output documents will be serialized as XML 1.0. This option also affects * the characters permitted to appear in queries and stylesheets, and the characters that can appear * in names (for example, in path expressions). * * @return one of the strings "1.0" or "1.1" */ /*@NotNull*/ public String getXmlVersion() { if (config.getXMLVersion() == Configuration.XML10) { return "1.0"; } else { return "1.1"; } } /** * Set a configuration property * * @param name the name of the option to be set. The names of the options available are listed * as constants in class {@link net.sf.saxon.lib.FeatureKeys}. * @param value the value of the option to be set. * @throws IllegalArgumentException if the property name is not recognized */ public void setConfigurationProperty(/*@NotNull*/ String name, /*@NotNull*/ Object value) { config.setConfigurationProperty(name, value); } /** * Get the value of a configuration property * * @param name the name of the option required. The names of the properties available are listed * as constants in class {@link net.sf.saxon.lib.FeatureKeys}. * @return the value of the property, if one is set; or null if the property is unset and there is * no default. * @throws IllegalArgumentException if the property name is not recognized */ /*@Nullable*/ public Object getConfigurationProperty(/*@NotNull*/ String name) { return config.getConfigurationProperty(name); } /** * Get the underlying {@link Configuration} object that underpins this Processor. This method * provides an escape hatch to internal Saxon implementation objects that offer a finer and lower-level * degree of control than the s9api classes and methods. Some of these classes and methods may change * from release to release. * * @return the underlying Configuration object */ public Configuration getUnderlyingConfiguration() { return config; } /** * Write an XdmValue to a given destination. The sequence represented by the XdmValue is "normalized" * as defined in the serialization specification (this is equivalent to constructing a document node * in XSLT or XQuery with this sequence as the content expression), and the resulting document is * then copied to the destination. If the destination is a serializer this has the effect of serializing * the sequence as described in the W3C specifications. * * @param value the value to be written * @param destination the destination to which the value is to be written * @throws SaxonApiException if any failure occurs, for example a serialization error */ public void writeXdmValue(/*@NotNull*/ XdmValue value, /*@NotNull*/ Destination destination) throws SaxonApiException { try { Receiver out = destination.getReceiver(config); out = new NamespaceReducer(out); TreeReceiver tree = new TreeReceiver(out); tree.open(); tree.startDocument(0); for (XdmItem item : value) { tree.append((Item) item.getUnderlyingValue(), 0, NodeInfo.ALL_NAMESPACES); } tree.endDocument(); tree.close(); destination.close(); } catch (XPathException err) { throw new SaxonApiException(err); } } private static class ExtensionFunctionDefinitionWrapper extends ExtensionFunctionDefinition { private ExtensionFunction function; public ExtensionFunctionDefinitionWrapper(ExtensionFunction function) { this.function = function; } /** * Get the name of the function, as a QName. *

This method must be implemented in all subclasses

* * @return the function name */ @Override public StructuredQName getFunctionQName() { return function.getName().getStructuredQName(); } /** * Get the minimum number of arguments required by the function *

The default implementation returns the number of items in the result of calling * {@link #getArgumentTypes}

* * @return the minimum number of arguments that must be supplied in a call to this function */ @Override public int getMinimumNumberOfArguments() { return function.getArgumentTypes().length; } /** * Get the maximum number of arguments allowed by the function. *

The default implementation returns the value of {@link #getMinimumNumberOfArguments} * * @return the maximum number of arguments that may be supplied in a call to this function */ @Override public int getMaximumNumberOfArguments() { return function.getArgumentTypes().length; } /** * Get the required types for the arguments of this function. *

This method must be implemented in all subtypes.

* * @return the required types of the arguments, as defined by the function signature. Normally * this should be an array of size {@link #getMaximumNumberOfArguments()}; however for functions * that allow a variable number of arguments, the array can be smaller than this, with the last * entry in the array providing the required type for all the remaining arguments. */ /*@NotNull*/ @Override public net.sf.saxon.value.SequenceType[] getArgumentTypes() { net.sf.saxon.s9api.SequenceType[] declaredArgs = function.getArgumentTypes(); net.sf.saxon.value.SequenceType[] types = new net.sf.saxon.value.SequenceType[declaredArgs.length]; for (int i = 0; i < declaredArgs.length; i++) { types[i] = net.sf.saxon.value.SequenceType.makeSequenceType( declaredArgs[i].getItemType().getUnderlyingItemType(), declaredArgs[i].getOccurrenceIndicator().getCardinality()); } return types; } /** * Get the type of the result of the function *

This method must be implemented in all subtypes.

* * @param suppliedArgumentTypes the static types of the supplied arguments to the function. * This is provided so that a more precise result type can be returned in the common * case where the type of the result depends on the types of the arguments. * @return the return type of the function, as defined by its function signature */ @Override public SequenceType getResultType(SequenceType[] suppliedArgumentTypes) { net.sf.saxon.s9api.SequenceType declaredResult = function.getResultType(); return net.sf.saxon.value.SequenceType.makeSequenceType( declaredResult.getItemType().getUnderlyingItemType(), declaredResult.getOccurrenceIndicator().getCardinality()); } /** * Ask whether the result actually returned by the function can be trusted, * or whether it should be checked against the declared type. * * @return true if the function implementation warrants that the value it returns will * be an instance of the declared result type. The default value is false, in which case * the result will be checked at run-time to ensure that it conforms to the declared type. * If the value true is returned, but the function returns a value of the wrong type, the * consequences are unpredictable. */ @Override public boolean trustResultType() { return false; } /** * Ask whether the result of the function depends on the focus, or on other variable parts * of the context. * * @return true if the result of the function depends on the context item, position, or size. * Despite the method name, the method should also return true if the function depends on other * parts of the context that vary from one part of the query/stylesheet to another, for example * the XPath default namespace. *

The default implementation returns false.

*

The method must return true if the function * makes use of any of these values from the dynamic context. Returning true inhibits certain * optimizations, such as moving the function call out of the body of an xsl:for-each loop, * or extracting it into a global variable.

*/ @Override public boolean dependsOnFocus() { return false; } /** * Ask whether the function has side-effects. If the function does have side-effects, the optimizer * will be less aggressive in moving or removing calls to the function. However, calls on functions * with side-effects can never be guaranteed. * * @return true if the function has side-effects (including creation of new nodes, if the * identity of those nodes is significant). The default implementation returns false. */ @Override public boolean hasSideEffects() { return false; } /** * Create a call on this function. This method is called by the compiler when it identifies * a function call that calls this function. */ /*@NotNull*/ @Override public ExtensionFunctionCall makeCallExpression() { return new ExtensionFunctionCall() { @Override public SequenceIterator call( /*@NotNull*/ SequenceIterator[] arguments, XPathContext context) throws XPathException { XdmValue[] args = new XdmValue[arguments.length]; for (int i = 0; i < args.length; i++) { ValueRepresentation val = SequenceExtent.makeSequenceExtent(arguments[i]); args[i] = XdmValue.wrap(val); } try { XdmValue result = function.call(args); return Value.asIterator(result.getUnderlyingValue()); } catch (SaxonApiException e) { throw new XPathException(e); } } }; } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/BuildingContentHandler.java0000644000175000017500000000301511671711573026460 0ustar mathieumathieupackage net.sf.saxon.s9api; import org.xml.sax.ContentHandler; /** * A SAX {@link ContentHandler} that builds a Saxon tree, and allows the node at the root of the tree * to be retrieved on completion */ public interface BuildingContentHandler extends ContentHandler { /** * After building the document by writing a sequence of events, retrieve the root node * of the constructed document tree * @return the root node of the constructed tree. The result is undefined (maybe null, maybe an exception) * if the method is called before successfully completing the sequence of events (of which the last should be * {@link #endDocument}) that constructs the tree. * @throws SaxonApiException if any failure occurs */ public XdmNode getDocumentNode() throws SaxonApiException; } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/ExtensionFunction.java0000644000175000017500000000540011671711573025554 0ustar mathieumathieupackage net.sf.saxon.s9api; /** * This is an interface for simple external/extension functions. Users can implement this * interface and register the implementation with the {@link Processor}; the function will * then be available for calling from all queries, stylesheets, and XPath expressions compiled * under this Processor. * * Extension functions implemented using this interface are expected to be free of side-effects, * and to have no dependencies on the static or dynamic context. A richer interface for extension * functions is provided via the {@link net.sf.saxon.lib.ExtensionFunctionDefinition} class. */ public interface ExtensionFunction { /** * Return the name of the external function * @return the name of the function, as a QName. */ public QName getName(); /** * Declare the result type of the external function * @return the result type of the external function */ public SequenceType getResultType(); /** * Declare the types of the arguments * @return a sequence of SequenceType objects, one for each argument to the function, * representing the expected types of the arguments */ public SequenceType[] getArgumentTypes(); /** * Call the function. The implementation of this method represents the body of the external function. * @param arguments the arguments, as supplied in the XPath function call. These will always be of * the declared types. Arguments are converted to the required types according to the standard XPath * function conversion rules - for example, if the expected type is atomic and a node is supplied in the * call, the node will be atomized * @return the result of the function. This must be an instance of the declared return type; if it is not, * a dynamic error will be reported * @throws SaxonApiException can be thrown if the implementation of the function detects a dynamic error */ /*@NotNull*/ public XdmValue call(XdmValue[] arguments) throws SaxonApiException; } /// // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XQueryEvaluator.java0000644000175000017500000006123011671711573025215 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.Builder; import net.sf.saxon.event.Receiver; import net.sf.saxon.expr.instruct.UserFunction; import net.sf.saxon.lib.TraceListener; import net.sf.saxon.om.*; import net.sf.saxon.query.DynamicQueryContext; import net.sf.saxon.query.XQueryExpression; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import java.io.PrintStream; import java.util.HashSet; import java.util.Iterator; import java.util.Set; /** * An XQueryEvaluator represents a compiled and loaded query ready for execution. * The XQueryEvaluator holds details of the dynamic evaluation context for the query. *

*

An XQueryEvaluator must not be used concurrently in multiple threads. * It is safe, however, to reuse the object within a single thread to run the same * query several times. Running the query does not change the context * that has been established.

*

*

An XQueryEvaluator is always constructed by running the Load * method of an {@link net.sf.saxon.s9api.XQueryExecutable}.

*

*

An XQueryEvaluator is itself a Iterable. This makes it possible to * evaluate the results in a for-each expression.

*

*

An XQueryEvaluator is itself a Destination. This means it is possible to use * one XQueryEvaluator as the destination to receive the results of another transformation, * this providing a simple way for transformations to be chained into a pipeline. When the query is executed * this way, {@link #setDestination(Destination)} must be called to provide a destination for the result of this query. * Note however that a when the input to a query is supplied in this way, it will always be built as a tree in * memory, rather than the transformation being streamed.

*/ public class XQueryEvaluator implements Iterable, Destination { private Processor processor; private XQueryExpression expression; private DynamicQueryContext context; private Controller controller; // used only when making direct calls to global functions private Destination destination; private Set updatedDocuments; /*@Nullable*/ private Builder sourceTreeBuilder; /** * Protected constructor * * @param processor the Saxon processor * @param expression the XQuery expression */ protected XQueryEvaluator(Processor processor, XQueryExpression expression) { this.processor = processor; this.expression = expression; this.context = new DynamicQueryContext(expression.getExecutable().getConfiguration()); } /** * Set the schema validation mode for the transformation. This indicates how source documents * loaded specifically for this transformation will be handled. This applies to the * principal source document if supplied as a SAXSource or StreamSource, and to all * documents loaded during the transformation using the doc(), document(), * or collection() functions. * * @param mode the validation mode. Passing null causes no change to the existing value. * Passing Validation.DEFAULT resets to the initial value, which determines * the validation requirements from the Saxon Configuration. */ public void setSchemaValidationMode(ValidationMode mode) { if (mode != null) { context.setSchemaValidationMode(mode.getNumber()); } } /** * Get the schema validation mode for the transformation. This indicates how source documents * loaded specifically for this transformation will be handled. This applies to the * principal source document if supplied as a SAXSource or StreamSource, and to all * documents loaded during the transformation using the doc(), document(), * or collection() functions. * * @return the validation mode. */ public ValidationMode getSchemaValidationMode() { return ValidationMode.get(context.getSchemaValidationMode()); } /** * Set the source document for the query. *

*

If the source is an instance of {@link net.sf.saxon.om.NodeInfo}, the supplied node is used * directly as the context node of the query.

*

*

If the source is an instance of {@link javax.xml.transform.dom.DOMSource}, the DOM node identified * by the DOMSource is wrapped as a Saxon node, and this is then used as the context item

*

*

In all other cases a new Saxon tree is built, by calling * {@link net.sf.saxon.s9api.DocumentBuilder#build(javax.xml.transform.Source)}, and the document * node of this tree is then used as the context item for the query.

* * @param source the source document to act as the initial context item for the query. */ public void setSource(Source source) throws SaxonApiException { if (source instanceof NodeInfo) { setContextItem(new XdmNode((NodeInfo) source)); } else if (source instanceof DOMSource) { setContextItem(processor.newDocumentBuilder().wrap(source)); } else { setContextItem(processor.newDocumentBuilder().build(source)); } } /** * Set the initial context item for the query * * @param item the initial context item, or null if there is to be no initial context item */ public void setContextItem(XdmItem item) { if (item != null) { context.setContextItem((Item) item.getUnderlyingValue()); } } /** * Get the initial context item for the query, if one has been set * * @return the initial context item, or null if none has been set. This will not necessarily * be the same object as was supplied, but it will be an XdmItem object that represents * the same underlying node or atomic value. */ public XdmItem getContextItem() { return (XdmItem) XdmValue.wrap(context.getContextItem()); } /** * Set the value of external variable defined in the query * * @param name the name of the external variable, as a QName * @param value the value of the external variable, or null to clear a previously set value */ public void setExternalVariable(QName name, XdmValue value) { context.setParameterValue(name.getClarkName(), (value == null ? null : value.getUnderlyingValue())); } /** * Get the value that has been set for an external variable * * @param name the name of the external variable whose value is required * @return the value that has been set for the external variable, or null if no value has been set */ public XdmValue getExternalVariable(QName name) { Object oval = context.getParameter(name.getClarkName()); if (oval == null) { return null; } if (oval instanceof ValueRepresentation) { return XdmValue.wrap((ValueRepresentation) oval); } throw new IllegalStateException(oval.getClass().getName()); } /** * Set an object that will be used to resolve URIs used in * fn:doc() and related functions. * * @param resolver An object that implements the URIResolver interface, or * null. */ public void setURIResolver(URIResolver resolver) { context.setURIResolver(resolver); } /** * Get the URI resolver. * * @return the user-supplied URI resolver if there is one, or the * system-defined one otherwise */ public URIResolver getURIResolver() { return context.getURIResolver(); } /** * Set the error listener. The error listener receives reports of all run-time * errors and can decide how to report them. * * @param listener the ErrorListener to be used */ public void setErrorListener(ErrorListener listener) { context.setErrorListener(listener); } /** * Get the error listener. * * @return the ErrorListener in use */ public ErrorListener getErrorListener() { return context.getErrorListener(); } /** * Set a TraceListener which will receive messages relating to the evaluation of all expressions. * This option has no effect unless the query was compiled to enable tracing. * * @param listener the TraceListener to use */ public void setTraceListener(TraceListener listener) { context.setTraceListener(listener); } /** * Get the registered TraceListener, if any * * @return listener the TraceListener in use, or null if none has been set */ public TraceListener getTraceListener() { return context.getTraceListener(); } /** * Set the destination for output from the fn:trace() function. * By default, the destination is System.err. If a TraceListener is in use, * this is ignored, and the trace() output is sent to the TraceListener. * * @param stream the PrintStream to which trace output will be sent. If set to * null, trace output is suppressed entirely. It is the caller's responsibility * to close the stream after use. * @since 9.1 */ public void setTraceFunctionDestination(PrintStream stream) { context.setTraceFunctionDestination(stream); } /** * Get the destination for output from the fn:trace() function. * * @return the PrintStream to which trace output will be sent. If no explicitly * destination has been set, returns System.err. If the destination has been set * to null to suppress trace output, returns null. * @since 9.1 */ public PrintStream getTraceFunctionDestination() { return context.getTraceFunctionDestination(); } /** * Set the destination to be used for the query results * * @param destination the destination to which the results of the query will be sent */ public void setDestination(Destination destination) { this.destination = destination; } /** * Perform the query. *

*

  • In the case of a non-updating query, the results are sent to the * registered Destination.
  • *
  • In the case of an updating query, all updated documents will be available after query * execution as the result of the {@link #getUpdatedDocuments} method.
  • *
* * @throws net.sf.saxon.s9api.SaxonApiException * if any dynamic error occurs during the query * @throws IllegalStateException if this is a non-updating query and no Destination has been * supplied for the query results */ public void run() throws SaxonApiException { try { if (expression.isUpdateQuery()) { Set docs = expression.runUpdate(context); updatedDocuments = new HashSet(); for (Iterator iter = docs.iterator(); iter.hasNext();) { NodeInfo root = (NodeInfo) iter.next(); updatedDocuments.add((XdmNode) XdmNode.wrapItem(root)); } } else { if (destination == null) { throw new IllegalStateException("No destination supplied"); } Result receiver; if (destination instanceof Serializer) { //receiver = ((Serializer) destination).getResult(); //context.set receiver = ((Serializer) destination).getReceiver(expression.getExecutable()); } else { receiver = destination.getReceiver(expression.getExecutable().getConfiguration()); } expression.run(context, receiver, null); destination.close(); } } catch (TransformerException e) { throw new SaxonApiException(e); } } /** * Perform the query, sending the results to a specified destination. *

*

This method must not be used with an updating query.

*

*

This method is designed for use with a query that produces a single node (typically * a document node or element node) as its result. If the query produces multiple nodes, * the effect depends on the kind of destination. For example, if the result is an * XdmDestination, only the last of the nodes will be accessible.

* * @param destination The destination where the result document will be sent * @throws net.sf.saxon.s9api.SaxonApiException * if any dynamic error occurs during the query * @throws IllegalStateException if this is an updating query */ public void run(Destination destination) throws SaxonApiException { if (expression.isUpdateQuery()) { throw new IllegalStateException("Query is updating"); } try { Receiver receiver; if (destination instanceof Serializer) { receiver = ((Serializer) destination).getReceiver(expression.getExecutable()); } else { receiver = destination.getReceiver(expression.getExecutable().getConfiguration()); } expression.run(context, receiver, null); } catch (TransformerException e) { throw new SaxonApiException(e); } } /** * Perform the query, returning the results as an XdmValue. This method * must not be used with an updating query * * @return an XdmValue representing the results of the query * @throws SaxonApiException if the query fails with a dynamic error * @throws IllegalStateException if this is an updating query */ public XdmValue evaluate() throws SaxonApiException { if (expression.isUpdateQuery()) { throw new IllegalStateException("Query is updating"); } try { SequenceIterator iter = expression.iterator(context); ValueRepresentation result = SequenceExtent.makeSequenceExtent(iter); if (result instanceof NodeInfo) { return new XdmNode((NodeInfo) result); } else if (result instanceof AtomicValue) { return new XdmAtomicValue((AtomicValue) result); } else if (result instanceof EmptySequence) { return XdmEmptySequence.getInstance(); } else { return new XdmValue(result); } } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Evaluate the XQuery expression, returning the result as an XdmItem (that is, * a single node or atomic value). * * @return an XdmItem representing the result of the query, or null if the query * returns an empty sequence. If the expression returns a sequence of more than one item, * any items after the first are ignored. * @throws SaxonApiException if a dynamic error occurs during the query evaluation. * @since 9.2 */ public XdmItem evaluateSingle() throws SaxonApiException { try { SequenceIterator iter = expression.iterator(context); return (XdmItem) XdmValue.wrap(iter.next()); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Evaluate the query, and return an iterator over its results. *

This method must not be used with an updating query.

* * @throws SaxonApiUncheckedException if a dynamic error is detected while constructing the iterator. * It is also possible for an SaxonApiUncheckedException to be thrown by the hasNext() method of the * returned iterator if a dynamic error occurs while evaluating the result sequence. * @throws IllegalStateException if this is an updating query */ public Iterator iterator() throws SaxonApiUncheckedException { if (expression.isUpdateQuery()) { throw new IllegalStateException("Query is updating"); } try { return new XdmSequenceIterator(expression.iterator(context)); } catch (XPathException e) { throw new SaxonApiUncheckedException(e); } } /** * Return a Receiver which can be used to supply the principal source document for the transformation. * This method is intended primarily for internal use, though it can also * be called by a user application that wishes to feed events into the query engine. *

*

Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. This method is provided so that * XQueryEvaluator implements Destination, allowing one transformation * to receive the results of another in a pipeline.

*

*

Note that when an XQueryEvaluator is used as a Destination, the initial * context node set on that XQueryEvaluator (using {@link #setSource(javax.xml.transform.Source)}) is ignored.

* * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. * @throws SaxonApiException if the Receiver cannot be created * @throws IllegalStateException if no Destination has been supplied */ public Receiver getReceiver(Configuration config) throws SaxonApiException { if (destination == null) { throw new IllegalStateException("No destination has been supplied"); } if (controller == null) { controller = expression.newController(); context.initializeController(controller); try { controller.defineGlobalParameters(); } catch (XPathException e) { throw new SaxonApiException(e); } } sourceTreeBuilder = controller.makeBuilder(); Receiver stripper = controller.makeStripper(sourceTreeBuilder); if (controller.getExecutable().stripsInputTypeAnnotations()) { stripper = controller.getConfiguration().getAnnotationStripper(stripper); } return stripper; } /** * Close this destination, allowing resources to be released. Used when this XQueryEvaluator is acting * as the destination of another transformation or query. Saxon calls this method when it has finished writing * to the destination. */ public void close() throws SaxonApiException { if (sourceTreeBuilder != null) { DocumentInfo doc = (DocumentInfo) sourceTreeBuilder.getCurrentRoot(); setSource(doc); sourceTreeBuilder = null; if (doc == null) { throw new SaxonApiException("No source document has been built by the previous pipeline stage"); } run(destination); destination.close(); } } /** * After executing an updating query using the {@link #run()} method, iterate over the root * nodes of the documents updated by the query. *

*

The results remain available until a new query is executed. This method returns the results * of the most recently executed query. It does not consume the results.

* * @return an iterator over the root nodes of documents (or other trees) that were updated by the query * @since 9.1 */ public Iterator getUpdatedDocuments() { return updatedDocuments.iterator(); } /** * Call a global user-defined function in the compiled query. *

* If this is called more than once (to evaluate the same function repeatedly with different arguments, * or to evaluate different functions) then the sequence of evaluations uses the same values of global * variables including external variables (query parameters); the effect of any changes made to query parameters * between calls is undefined. * * @param function The name of the function to be called * @param arguments The values of the arguments to be supplied to the function. These * must be of the correct type as defined in the function signature (there is no automatic * conversion to the required type). * @throws SaxonApiException if no function has been defined with the given name and arity; * or if any of the arguments does not match its required type according to the function * signature; or if a dynamic error occurs in evaluating the function. * @since 9.3 */ public XdmValue callFunction(QName function, XdmValue[] arguments) throws SaxonApiException { final UserFunction fn = expression.getStaticContext().getUserDefinedFunction( function.getNamespaceURI(), function.getLocalName(), arguments.length); if (fn == null) { throw new SaxonApiException("No function with name " + function.getClarkName() + " and arity " + arguments.length + " has been declared in the query"); } try { // TODO: use the same controller in other interfaces such as run(), and expose it in a trapdoor API if (controller == null) { controller = expression.newController(); context.initializeController(controller); controller.defineGlobalParameters(); } ValueRepresentation[] vr = new ValueRepresentation[arguments.length]; for (int i = 0; i < arguments.length; i++) { net.sf.saxon.value.SequenceType type = fn.getParameterDefinitions()[i].getRequiredType(); vr[i] = arguments[i].getUnderlyingValue(); if (!type.matches(Value.asValue(vr[i]), controller.getConfiguration())) { throw new SaxonApiException("Argument " + (i + 1) + " of function " + function.getClarkName() + " does not match the required type " + type.toString()); } } ValueRepresentation result = fn.call(vr, controller); return XdmValue.wrap(result); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Get the underlying dynamic context object. This provides an escape hatch to the underlying * implementation classes, which contain methods that may change from one release to another. * * @return the underlying object representing the dynamic context for query execution */ public DynamicQueryContext getUnderlyingQueryContext() { return context; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/WhitespaceStrippingPolicy.java0000644000175000017500000000610511671711573027251 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.event.FilterFactory; import net.sf.saxon.event.ProxyReceiver; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.Stripper; import net.sf.saxon.expr.instruct.Executable; import net.sf.saxon.om.SpaceStrippingRule; import net.sf.saxon.value.Whitespace; /** * WhitespaceStrippingPolicy is class defining the possible policies for handling * whitespace text nodes in a source document. */ public class WhitespaceStrippingPolicy { private int policy; private SpaceStrippingRule stripperRules; /** * The value NONE indicates that all whitespace text nodes are retained */ public static final WhitespaceStrippingPolicy NONE = new WhitespaceStrippingPolicy(Whitespace.NONE); /** * The value IGNORABLE indicates that whitespace text nodes in element-only content are * discarded. Content is element-only if it is defined by a schema or DTD definition that * does not allow mixed or PCDATA content. */ public static final WhitespaceStrippingPolicy IGNORABLE = new WhitespaceStrippingPolicy(Whitespace.IGNORABLE); /** * The value ALL indicates that all whitespace-only text nodes are discarded. */ public static final WhitespaceStrippingPolicy ALL = new WhitespaceStrippingPolicy(Whitespace.ALL); /** * UNSPECIFIED means that no other value has been specifically requested. */ public static final WhitespaceStrippingPolicy UNSPECIFIED = new WhitespaceStrippingPolicy(Whitespace.UNSPECIFIED); private WhitespaceStrippingPolicy(int policy) { this.policy = policy; } /** * Create a WhitespaceStrippingPolicy based on the xsl:strip-space and xsl:preserve-space declarations * in a given XSLT stylesheet * @param executable the stylesheet containing the xsl:strip-space and xsl:preserve-space declarations */ protected WhitespaceStrippingPolicy (Executable executable) { policy = Whitespace.XSLT; stripperRules = executable.getStripperRules(); } protected int ordinal() { return policy; } /*@NotNull*/ protected FilterFactory makeStripper() { return new FilterFactory() { public ProxyReceiver makeFilter(Receiver next) { return new Stripper(stripperRules, next); } }; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XdmAtomicValue.java0000644000175000017500000002741411671711573024765 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.*; import net.sf.saxon.value.*; import java.math.BigDecimal; import java.net.URI; /** * The class XdmAtomicValue represents an item in an XPath 2.0 sequence that is an atomic value. * The value may belong to any of the 19 primitive types defined in XML Schema, or to a type * derived from these primitive types, or the XPath 2.0 type xs:untypedAtomic. The type may * be either a built-in type or a user-defined type. * *

An XdmAtomicValue is immutable.

*/ public class XdmAtomicValue extends XdmItem { protected XdmAtomicValue(AtomicValue value) { super(value); } /** * Create an xs:boolean atomic value * @param value the boolean value, true or false */ public XdmAtomicValue(boolean value) { super(BooleanValue.get(value)); } /** * Create an xs:integer atomic value * @param value the xs:integer value, as a long */ public XdmAtomicValue(long value) { super(Int64Value.makeIntegerValue(value)); } /** * Create an xs:decimal atomic value * @param value the xs:decimal value, as a BigDecimal */ public XdmAtomicValue(BigDecimal value) { super(new DecimalValue(value)); } /** * Create an xs:double atomic value * @param value the xs:double value, as a double */ public XdmAtomicValue(double value) { super(new DoubleValue(value)); } /** * Create an xs:float atomic value * @param value the xs:float value, as a float */ public XdmAtomicValue(float value) { super(new FloatValue(value)); } /** * Create an xs:string atomic value * @param value the xs:string value, as a string */ public XdmAtomicValue(String value) { super(new StringValue(value)); } /** * Create an xs:anyURI atomic value * @param value the xs:anyURI value, as a URI */ public XdmAtomicValue(URI value) { super(new AnyURIValue(value.toString())); } /** * Create an xs:QName atomic value * @param value the xs:QName value, as a QName */ public XdmAtomicValue(QName value) { super(new QNameValue(value.getStructuredQName(), BuiltInAtomicType.QNAME)); } /** * Construct an atomic value given its lexical representation and the name of the required * built-in atomic type. *

This method cannot be used to construct values that are namespace-sensitive (QNames and Notations)

* @param lexicalForm the value in the lexical space of the target data type. More strictly, the input * value before the actions of the whitespace facet for the target data type are applied. * @param type the required atomic type. This must either be one of the built-in * atomic types defined in XML Schema, or a user-defined type whose definition appears * in a schema that is known to the Processor. It must not be an abstract type. * @throws SaxonApiException if the type is unknown, or is not atomic, or is namespace-sensitive; * or if the value supplied in lexicalForm is not in the lexical space of the specified atomic * type. */ public XdmAtomicValue(String lexicalForm, ItemType type) throws SaxonApiException { net.sf.saxon.type.ItemType it = type.getUnderlyingItemType(); if (!it.isPlainType()) { throw new SaxonApiException("Requested type is not atomic"); } if (((AtomicType)it).isAbstract()) { throw new SaxonApiException("Requested type is an abstract type"); } if (((AtomicType)it).isNamespaceSensitive()) { throw new SaxonApiException("Requested type is namespace-sensitive"); } try { StringConverter converter = type.getConversionRules().getStringConverter((AtomicType)it); setValue(converter.convertString(lexicalForm).asAtomic()); } catch (ValidationException e) { throw new SaxonApiException(e); } } /** * Get the result of converting the atomic value to a string. This has the same * effect as the XPath string() function. */ public String toString() { return getStringValue(); } /** * Get the primitive type of this atomic value, as a QName. The primitive types for this purpose are * the 19 primitive types of XML Schema, plus xs:integer, xs:dayTimeDuration and xs:yearMonthDuration, * and xs:untypedAtomic. For external objects, the result is xs:anyAtomicType. * @return a QName naming the primitive type of this atomic value. This will always be an atomic type. */ /*@NotNull*/ public QName getPrimitiveTypeName() { AtomicValue value = (AtomicValue)getUnderlyingValue(); BuiltInAtomicType type = value.getPrimitiveType(); return new QName(type.getQualifiedName()); } /** * Get the value as a Java object of the nearest equivalent type. * *

The result type is as follows:

* * * * * * * * * * * * * *
XPath type Java class
xs:string String
xs:integer java.math.BigInteger
xs:decimal java.math.BigDecimal
xs:double Double
xs:float Float
xs:boolean Boolean
xs:QName QName
xs:anyURI String
xs:untypedAtomicString
Other types currently String, but this may change in the future
* @return the value, converted to a Java object of a suitable type */ @SuppressWarnings({"AutoBoxing"}) public Object getValue() { AtomicValue av = (AtomicValue)getUnderlyingValue(); if (av instanceof StringValue) { return av.getStringValue(); } else if (av instanceof IntegerValue) { return ((IntegerValue)av).asBigInteger(); } else if (av instanceof DoubleValue) { return ((DoubleValue)av).getDoubleValue(); } else if (av instanceof FloatValue) { return ((FloatValue)av).getFloatValue(); } else if (av instanceof BooleanValue) { return ((BooleanValue)av).getBooleanValue(); } else if (av instanceof DecimalValue) { return ((DecimalValue)av).getDecimalValue(); } else if (av instanceof QNameValue) { QNameValue q = (QNameValue)av; return new QName(q.getPrefix(), q.getNamespaceURI(), q.getLocalName()); } else { return av.getStringValue(); } } /** * Get the value converted to a boolean using the XPath casting rules * @return the result of converting to a boolean (Note: this is not the same as the * effective boolean value). * @throws SaxonApiException if the value cannot be cast to a boolean */ public boolean getBooleanValue() throws SaxonApiException { AtomicValue av = (AtomicValue)getUnderlyingValue(); if (av instanceof BooleanValue) { return ((BooleanValue)av).getBooleanValue(); } else if (av instanceof NumericValue) { return !av.isNaN() && ((NumericValue)av).signum() != 0; } else if (av instanceof StringValue) { String s = av.getStringValue().trim(); return "1".equals(s) || "true".equals(s); } else { throw new SaxonApiException("Cannot cast item to a boolean"); } } /** * Get the value converted to an integer using the XPath casting rules * @return the result of converting to an integer * @throws SaxonApiException if the value cannot be cast to an integer */ public long getLongValue() throws SaxonApiException { AtomicValue av = (AtomicValue)getUnderlyingValue(); if (av instanceof BooleanValue) { return ((BooleanValue)av).getBooleanValue() ? 0L : 1L; } else if (av instanceof NumericValue) { try { return ((NumericValue)av).longValue(); } catch (XPathException e) { throw new SaxonApiException("Cannot cast item to an integer"); } } else if (av instanceof StringValue) { StringToDouble converter = StringToDouble.getInstance(); return (long)converter.stringToNumber(av.getStringValueCS()); } else { throw new SaxonApiException("Cannot cast item to an integer"); } } /** * Get the value converted to a double using the XPath casting rules. *

If the value is a string, the XSD 1.1 rules are used, which means that the string * "+INF" is recognised.

* @return the result of converting to a double * @throws SaxonApiException if the value cannot be cast to a double */ public double getDoubleValue() throws SaxonApiException { AtomicValue av = (AtomicValue)getUnderlyingValue(); if (av instanceof BooleanValue) { return ((BooleanValue)av).getBooleanValue() ? 0.0 : 1.0; } else if (av instanceof NumericValue) { return ((NumericValue)av).getDoubleValue(); } else if (av instanceof StringValue) { try { StringToDouble converter = StringToDouble11.getInstance(); return converter.stringToNumber(av.getStringValueCS()); } catch (NumberFormatException e) { throw new SaxonApiException(e.getMessage()); } } else { throw new SaxonApiException("Cannot cast item to a double"); } } /** * Get the value converted to a decimal using the XPath casting rules * @return the result of converting to a decimal * @throws SaxonApiException if the value cannot be cast to a double */ public BigDecimal getDecimalValue() throws SaxonApiException { AtomicValue av = (AtomicValue)getUnderlyingValue(); if (av instanceof BooleanValue) { return ((BooleanValue)av).getBooleanValue() ? BigDecimal.ZERO : BigDecimal.ONE; } else if (av instanceof NumericValue) { try { return ((NumericValue)av).getDecimalValue(); } catch (XPathException e) { throw new SaxonApiException("Cannot cast item to a decimal"); } } else if (av instanceof StringValue) { return new BigDecimal(av.getStringValueCS().toString()); } else { throw new SaxonApiException("Cannot cast item to a decimal"); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XdmSequenceIterator.java0000644000175000017500000001016211671711573026026 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.trans.XPathException; import java.util.Iterator; /** * An iterator over an XPath sequence. * *

This class implements the standard Java Iterator interface.

* *

Because the Iterator interface does not define any checked * exceptions, the hasNext() method of this iterator throws an unchecked * exception if a dynamic error occurs while evaluating the expression. Applications * wishing to control error handling should take care to catch this exception.

*/ public class XdmSequenceIterator implements Iterator { /*@Nullable*/ private XdmItem next = null; private int state = BEFORE_ITEM; private SequenceIterator base; private final static int BEFORE_ITEM = 0; private final static int ON_ITEM = 1; private final static int FINISHED = 2; protected XdmSequenceIterator(SequenceIterator base) { this.base = base; this.state = BEFORE_ITEM; } /** * Returns true if the iteration has more elements. (In other * words, returns true if next would return an element * rather than throwing an exception.) * * @return true if the iterator has more elements. * * @throws SaxonApiUncheckedException if a dynamic error occurs during XPath evaluation that * is detected at this point. */ public boolean hasNext() throws SaxonApiUncheckedException { switch (state) { case ON_ITEM: return true; case FINISHED: return false; case BEFORE_ITEM: try { next = XdmItem.wrapItem(base.next()); if (next == null) { state = FINISHED; return false; } else { state = ON_ITEM; return true; } } catch (XPathException err) { throw new SaxonApiUncheckedException(err); } default: throw new IllegalStateException(); } } /** * Returns the next element in the iteration. Calling this method * repeatedly until the {@link #hasNext()} method returns false will * return each element in the underlying collection exactly once. * * @return the next element in the iteration. * @throws java.util.NoSuchElementException * iteration has no more elements. */ public XdmItem next() { switch (state) { case ON_ITEM: state = BEFORE_ITEM; return next; case FINISHED: throw new java.util.NoSuchElementException(); case BEFORE_ITEM: if (hasNext()) { state = BEFORE_ITEM; return next; } else { throw new java.util.NoSuchElementException(); } default: throw new IllegalStateException(); } } /** * Not supported on this implementation. * * @throws UnsupportedOperationException always */ public void remove() { throw new UnsupportedOperationException(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XdmDestination.java0000644000175000017500000002442511671711573025034 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.Builder; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.ProxyReceiver; import net.sf.saxon.event.Receiver; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.NodeName; import net.sf.saxon.om.TreeModel; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import java.net.URI; /** * An XdmDestination is a {@link Destination} in which an {@link XdmNode} * is constructed to hold the output of a query or transformation: * that is, a tree using Saxon's implementation of the XDM data model * *

No data needs to be supplied to the XdmDestination object. The query or transformation * populates an XdmNode, which may then be retrieved using the getXdmNode * method.

* *

An XdmDestination is designed to hold a single tree rooted at a document or element node. * It should therefore not be used as the destination of a query that produces multiple * documents, multiple elements, nodes other than elements and documents, or atomic values. If the query * does produce such a result, an exception will be thrown.

* *

An XdmDestination can be reused to hold the results of a second query or transformation only * if the {@link #reset} method is first called to reset its state.

* *

If an XDM tree is to be built from a lexical XML document, or programmatically from the application * by writing a sequence of events, the recommended mechanism is to use a {@link DocumentBuilder} rather * than this class.

*/ public class XdmDestination implements Destination { TreeModel treeModel = TreeModel.TINY_TREE; URI baseURI; Builder builder; public XdmDestination() { //builder = new TinyBuilder(); } /** * Set the base URI for the document node that will be created when the XdmDestination is written to. * This method must be called before writing to the destination; it has no effect on an XdmNode that * has already been constructed. * @param baseURI the base URI for the node that will be constructed when the XdmDestination is written to. * This must be an absolute URI * @throws IllegalArgumentException if the baseURI supplied is not an absolute URI * @since 9.1 */ public void setBaseURI(URI baseURI) { if (!baseURI.isAbsolute()) { throw new IllegalArgumentException("Supplied base URI must be absolute"); } //builder.setBaseURI(baseURI.toString()); this.baseURI = baseURI; } /** * Get the base URI that will be used for the document node when the XdmDestination is written to. * @return the base URI that will be used for the node that is constructed when the XdmDestination is written to. * @since 9.1 */ public URI getBaseURI() { return baseURI; } /** * Set the tree model to be used for documents constructed using this XdmDestination. * By default, the TinyTree is used. * @param model typically one of the constants {@link net.sf.saxon.om.TreeModel#TINY_TREE}, * {@link TreeModel#TINY_TREE_CONDENSED}, or {@link TreeModel#LINKED_TREE}. However, in principle * a user-defined tree model can be used. * @since 9.2 */ public void setTreeModel(TreeModel model) { this.treeModel = model; } /** * Get the tree model to be used for documents constructed using this XdmDestination. * By default, the TinyTree is used. * @return the tree model in use: typically one of the constants {@link net.sf.saxon.om.TreeModel#TINY_TREE}, * {@link net.sf.saxon.om.TreeModel#TINY_TREE_CONDENSED}, or {@link TreeModel#LINKED_TREE}. However, in principle * a user-defined tree model can be used. * @since 9.2 */ public TreeModel getTreeModel() { return treeModel; } /** * Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. * @throws net.sf.saxon.s9api.SaxonApiException * if the Receiver cannot be created */ public Receiver getReceiver(Configuration config) throws SaxonApiException { TreeModel model = treeModel; if (model == null) { model = TreeModel.getTreeModel(config.getTreeModel()); } PipelineConfiguration pipe = config.makePipelineConfiguration(); builder = model.makeBuilder(pipe); if (baseURI != null) { builder.setBaseURI(baseURI.toString()); } return new TreeProtector(builder); } /** * Close the destination, allowing resources to be released. Saxon calls this method when * it has finished writing to the destination. */ public void close() throws SaxonApiException { // no action } /** * Return the node at the root of the tree, after it has been constructed. *

*

This method should not be called while the tree is under construction.

* @return the root node of the tree (always a document or element node); or null if * nothing is written to the tree (for example, the result of a query that returns the * empty sequence) * @throws IllegalStateException if called during the execution of the process that * is writing the tree. */ public XdmNode getXdmNode() { if (builder == null) { throw new IllegalStateException("The document has not yet been built"); } NodeInfo node = builder.getCurrentRoot(); return (node == null ? null : (XdmNode)XdmValue.wrap(node)); } /** * Allow the XdmDestination to be reused, without resetting other properties * of the destination. */ public void reset() { builder = null; } /** * TreeProtector is a filter that ensures that the events reaching the Builder constitute a single * tree rooted at an element or document node (because anything else will crash the builder) */ private static class TreeProtector extends ProxyReceiver { private int level = 0; private boolean ended = false; public TreeProtector(Receiver next) { super(next); } @Override public void startDocument(int properties) throws XPathException { if (ended) { throw new XPathException("Only a single document can be written to an XdmDestination"); } super.startDocument(properties); level++; } @Override public void endDocument() throws XPathException { super.endDocument(); level--; if (level == 0) { ended = true; } } @Override public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { if (ended) { throw new XPathException("Only a single root node can be written to an XdmDestination"); } super.startElement(nameCode, typeCode, locationId, properties); level++; } @Override public void endElement() throws XPathException { super.endElement(); level--; if (level == 0) { ended = true; } } @Override public void characters(CharSequence chars, int locationId, int properties) throws XPathException { if (level == 0) { throw new XPathException("When writing to an XdmDestination, text nodes are only allowed within a document or element node"); } super.characters(chars, locationId, properties); } @Override public void processingInstruction(String target, CharSequence data, int locationId, int properties) throws XPathException { if (level == 0) { throw new XPathException("When writing to an XdmDestination, processing instructions are only allowed within a document or element node"); } super.processingInstruction(target, data, locationId, properties); } @Override public void comment(CharSequence chars, int locationId, int properties) throws XPathException { if (level == 0) { throw new XPathException("When writing to an XdmDestination, comment nodes are only allowed within a document or element node"); } super.comment(chars, locationId, properties); } @Override public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (level == 0) { throw new XPathException("When writing to an XdmDestination, atomic values are only allowed within a document or element node"); } super.append(item, locationId, copyNamespaces); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/Destination.java0000644000175000017500000001053711671711573024362 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; /** * A Destination represents a place where XML can be sent. It is used, for example, * to define the output of a transformation or query. * *

In general a Destination is designed to hold a single document. * It should therefore not be used as the destination of a query that produces multiple * documents. The effect of sending multiple documents to a Destination * depends on the kind of Destination.

* *

The interface Destination has some similarities with the JAXP * {@link javax.xml.transform.Result} class. It differs, however, in that implementations * of this interface can be written by users or third parties to define new kinds of * destination, and any such implementation can be supplied to the Saxon methods that * take a Destination as an argument.

* *

Implementing a new Destination, however, will generally require access * to implementation-level classes and methods within the Saxon product. The only method that * needs to be supplied is {@link #getReceiver}, which returns an instance of * {@link net.sf.saxon.event.Receiver}, and unless you use an existing implementation of * Receiver, you will need to handle internal Saxon concepts such as name codes * and name pools.

* *

In general a Destination is not thread-safe (cannot be used from more than one thread), * and is not serially reusable. The {@link #close} method is called by the system when * it finishes writing the document, and this causes all resources held by the Destination * to be released.

*/ public interface Destination { /** * Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. The method is intended * primarily for internal use, and may give poor diagnostics if used incorrectly. * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. It is the caller's responsibility to * initialize this Receiver with a {@link net.sf.saxon.event.PipelineConfiguration} before calling * its open() method. The caller is also responsible for ensuring that the sequence * of events sent to the Receiver represents a well-formed document: in particular the event * stream must include namespace events corresponding exactly to the namespace declarations * that are required. If the calling code cannot guarantee this, it should insert a * {@link net.sf.saxon.event.NamespaceReducer} into the pipeline in front of the returned * Receiver. * @throws SaxonApiException if the Receiver cannot be created */ public Receiver getReceiver(Configuration config) throws SaxonApiException; /** * Close the destination, allowing resources to be released. Saxon calls this method when * it has finished writing to the destination. * *

The close() method should not cause any adverse effects if it is called more than * once. If any other method is called after the close() call, the results are undefined. * This means that a Destination is not, in general, serially reusable.

* @throws SaxonApiException if any failure occurs */ public void close() throws SaxonApiException; } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/MessageListenerProxy.java0000644000175000017500000001034411671711573026231 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.event.LocationProvider; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.ReceiverOptions; import net.sf.saxon.event.SequenceWriter; import net.sf.saxon.expr.parser.ExpressionLocation; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.NodeName; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; /** * This class implements a Receiver that can receive xsl:message output and send it to a * user-supplied MessageListener. */ class MessageListenerProxy extends SequenceWriter { private MessageListener listener; private boolean terminate; private int locationId = -1; protected MessageListenerProxy(MessageListener listener, PipelineConfiguration pipe) { super(pipe); this.listener = listener; } /** * Get the wrapped MessageListener * @return the wrapped MessageListener */ public MessageListener getMessageListener() { return listener; } /** * Start of a document node. */ public void startDocument(int properties) throws XPathException { terminate = (properties & ReceiverOptions.TERMINATE) != 0; locationId = -1; super.startDocument(properties); } /** * Output an element start tag. * * @param nameCode The element name code - a code held in the Name Pool * @param typeCode Integer code identifying the type of this element. Zero identifies the default * type, that is xs:anyType * @param properties bit-significant flags indicating any special information */ public void startElement(NodeName nameCode, SchemaType typeCode, int locationId, int properties) throws XPathException { if (this.locationId == -1) { this.locationId = locationId; } super.startElement(nameCode, typeCode, locationId, properties); } /** * Produce text content output.
* * @param s The String to be output * @param properties bit-significant flags for extra information, e.g. disable-output-escaping * @throws net.sf.saxon.trans.XPathException * for any failure */ public void characters(CharSequence s, int locationId, int properties) throws XPathException { if (this.locationId == -1) { this.locationId = locationId; } super.characters(s, locationId, properties); } /** * Append an item to the sequence, performing any necessary type-checking and conversion */ public void append(Item item, int locationId, int copyNamespaces) throws XPathException { if (this.locationId == -1) { this.locationId = locationId; } super.append(item, locationId, copyNamespaces); } /** * Abstract method to be supplied by subclasses: output one item in the sequence. * * @param item the item to be written to the sequence */ public void write(Item item) throws XPathException { ExpressionLocation loc = new ExpressionLocation(); if (locationId != -1) { LocationProvider provider = getPipelineConfiguration().getLocationProvider(); loc.setSystemId(provider.getSystemId(locationId)); loc.setLineNumber(provider.getLineNumber(locationId)); } listener.message(new XdmNode((NodeInfo)item), terminate, loc); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/MessageListener.java0000644000175000017500000000431411671711573025167 0ustar mathieumathieupackage net.sf.saxon.s9api; import javax.xml.transform.SourceLocator; /** * A user-written implementation of the MessageListener interface may be registered with the XsltTransformer * to receive notification of xsl:message output. Each xsl:message instruction that is evaluated results in * a single call to the MessageListener */ public interface MessageListener { /** * Notify a message written using the xsl:message instruction * @param content a document node representing the message content. Note that the output of * xsl:message is always an XML document node. It can be flattened to obtain the * string value if required by calling getStringValue(). * @param terminate Set to true if terminate="yes" was specified or to false otherwise. * The message listener does not need to take any special action based on this parameter, but the information * is available if required. If terminate="yes" was specified, then the transformation will abort * with an exception immediately on return from this callback. * @param locator an object that contains the location of the xsl:message instruction in the * stylesheet that caused this message to be output. This provides access to the URI of the stylesheet module * and the line number of the xsl:message instruction. */ public void message(XdmNode content, boolean terminate, SourceLocator locator); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XQueryExecutable.java0000644000175000017500000000772011671711573025340 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.query.XQueryExpression; /** * An XQueryExecutable represents the compiled form of a query. * To execute the query, it must first be loaded to form an {@link net.sf.saxon.s9api.XQueryEvaluator}. * *

An XQueryExecutable is immutable, and therefore thread-safe. * It is simplest to load a new XQueryEvaluator each time the query is to be run. * However, the XQueryEvaluator is serially reusable within a single thread.

* *

An XQueryExecutable is created by using one of the compile methods on the * {@link net.sf.saxon.s9api.XQueryCompiler} class.

* * @since 9.0 */ public class XQueryExecutable { Processor processor; XQueryExpression exp; protected XQueryExecutable(Processor processor, XQueryExpression exp) { this.processor = processor; this.exp = exp; } /** * Load the stylesheet to prepare it for execution. * @return An XsltTransformer. The returned XsltTransformer can be used to set up the * dynamic context for stylesheet evaluation, and to run the stylesheet. */ public XQueryEvaluator load() { return new XQueryEvaluator(processor, exp); } /** * Get the ItemType of the items in the result of the query, as determined by static analysis. This * is the most precise ItemType that the processor is able to determine from static examination of the * query; the actual items in the query result are guaranteed to belong to this ItemType or to a subtype * of this ItemType. * @return the statically-determined ItemType of the result of the query * @since 9.1 */ public ItemType getResultItemType() { net.sf.saxon.type.ItemType it = exp.getExpression().getItemType(processor.getUnderlyingConfiguration().getTypeHierarchy()); return new ConstructedItemType(it, processor); } /** * Get the statically-determined cardinality of the result of the query. This is the most precise cardinality * that the processor is able to determine from static examination of the query. * @return the statically-determined cardinality of the result of the query * @since 9.1 */ /*@NotNull*/ public OccurrenceIndicator getResultCardinality() { int card = exp.getExpression().getCardinality(); return OccurrenceIndicator.getOccurrenceIndicator(card); } /** * Ask whether the query is an updating query: that is, whether it returns a Pending Update List * rather than a Value. Note that queries using the XUpdate copy-modify syntax are not considered * to be updating queries. * @return true if the query is an updating query, false if not * @since 9.1 */ public boolean isUpdateQuery() { return exp.isUpdateQuery(); } /** * Get the underlying implementation object representing the compiled stylesheet. This provides * an escape hatch into lower-level APIs. The object returned by this method may change from release * to release. * @return the underlying implementation of the compiled stylesheet */ public XQueryExpression getUnderlyingCompiledQuery() { return exp; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XdmItem.java0000644000175000017500000001040411671711573023441 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.om.Item; import net.sf.saxon.value.AtomicValue; /** * The class XdmItem represents an item in a sequence, as defined by the XDM data model. * An item is either an atomic value or a node. * *

An item is a member of a sequence, but it can also be considered as a sequence * (of length one) in its own right. XdmItem is a subtype of XdmValue because every * Item in the XDM data model is also a value.

* *

It cannot be assumed that every sequence of length one will be represented by * an XdmItem. It is quite possible for an XdmValue that is not an XdmItem to hold * a singleton sequence.

* *

Saxon provides two concrete subclasses of XdmItem, namely * {@link XdmNode} and {@link XdmAtomicValue}. Users must not attempt to create * additional subclasses.

*/ public abstract class XdmItem extends XdmValue { // internal protected constructor protected XdmItem() { } /** * Construct an XdmItem as a wrapper around an existing NodeInfo object * @param item the NodeInfo object to be wrapped. This can be retrieved using the * {@link #getUnderlyingValue} method. * @throws NullPointerException if item is null * @since 9.2 (previously a protected constructor) */ protected XdmItem(Item item) { super(item); } // internal factory mathod to wrap an Item /*@Nullable*/ protected static XdmItem wrapItem(Item item) { return item == null ? null : (XdmItem)XdmValue.wrap(item); } /** * Factory method to construct an atomic value given its lexical representation and the * required item type * @param value the lexical representation of the required value * @param type the item type of the required value * @return the constructed item * @throws SaxonApiException if the supplied string is not in the lexical space of the target type, or * if the target type is not atomic * @deprecated since 9.1. This factory method duplicates the constructor * {@link XdmAtomicValue#XdmAtomicValue(String, ItemType)} which should be used in preference */ public static XdmItem newAtomicValue(String value, ItemType type) throws SaxonApiException { return new XdmAtomicValue(value, type); } /** * Get the string value of the item. For a node, this gets the string value * of the node. For an atomic value, it has the same effect as casting the value * to a string. In all cases the result is the same as applying the XPath string() * function. * *

For atomic values, the result is the same as the result of calling * toString. This is not the case for nodes, where toString * returns an XML serialization of the node.

* * @return the result of converting the item to a string. */ public String getStringValue() { //noinspection RedundantCast return ((Item)getUnderlyingValue()).getStringValue(); } /** * Determine whether the item is an atomic value or a node * @return true if the item is an atomic value, false if it is a node */ public boolean isAtomicValue() { return ((Item)getUnderlyingValue()) instanceof AtomicValue; } /** * Get the number of items in the sequence * @return the number of items in the value - always one */ @Override public int size() { return 1; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XQueryCompiler.java0000644000175000017500000005606611671711573025040 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.expr.sort.RuleBasedSubstringMatcher; import net.sf.saxon.expr.sort.SimpleCollation; import net.sf.saxon.lib.ModuleURIResolver; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.lib.StringCollator; import net.sf.saxon.query.StaticQueryContext; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.ValidationException; import net.sf.saxon.value.DecimalValue; import javax.xml.transform.ErrorListener; import java.io.*; import java.net.URI; import java.net.URISyntaxException; import java.text.RuleBasedCollator; /** * An XQueryCompiler object allows XQuery 1.0 queries to be compiled. The compiler holds information that * represents the static context for the compilation. * *

To construct an XQueryCompiler, use the factory method {@link Processor#newXQueryCompiler}.

* *

An XQueryCompiler may be used repeatedly to compile multiple queries. Any changes made to the * XQueryCompiler (that is, to the static context) do not affect queries that have already been compiled. * An XQueryCompiler may be used concurrently in multiple threads, but it should not then be modified once * initialized.

* * @since 9.0 */ public class XQueryCompiler { private Processor processor; private StaticQueryContext env; private ItemType requiredContextItemType; private String encoding; /** * Protected constructor * @param processor the Saxon Processor */ protected XQueryCompiler(Processor processor) { this.processor = processor; this.env = processor.getUnderlyingConfiguration().newStaticQueryContext(); } /** * Get the Processor from which this XQueryCompiler was constructed * @return the Processor to which this XQueryCompiler belongs * @since 9.3 */ public Processor getProcessor() { return processor; } /** * Set the static base URI for the query * @param baseURI the static base URI */ public void setBaseURI(URI baseURI) { if (!baseURI.isAbsolute()) { throw new IllegalArgumentException("Base URI must be an absolute URI: " + baseURI); } env.setBaseURI(baseURI.toString()); } /** * Get the static base URI for the query * @return the static base URI */ public URI getBaseURI() { try { return new URI(env.getBaseURI()); } catch (URISyntaxException err) { throw new IllegalStateException(err); } } /** * Set the ErrorListener to be used during this query compilation episode * @param listener The error listener to be used. This is notified of all errors detected during the * compilation. */ public void setErrorListener(ErrorListener listener) { env.setErrorListener(listener); } /** * Get the ErrorListener being used during this compilation episode * @return listener The error listener in use. This is notified of all errors detected during the * compilation. If no user-supplied ErrorListener has been set, returns the system-supplied * ErrorListener. */ public ErrorListener getErrorListener() { return env.getErrorListener(); } /** * Set whether trace hooks are to be included in the compiled code. To use tracing, it is necessary * both to compile the code with trace hooks included, and to supply a TraceListener at run-time * @param option true if trace code is to be compiled in, false otherwise */ public void setCompileWithTracing(boolean option) { env.setCompileWithTracing(option); } /** * Ask whether trace hooks are included in the compiled code. * @return true if trace hooks are included, false if not. */ public boolean isCompileWithTracing() { return env.isCompileWithTracing(); } /** * Set a user-defined ModuleURIResolver for resolving URIs used in import module * declarations in the XQuery prolog. * This will override any ModuleURIResolver that was specified as part of the configuration. * @param resolver the ModuleURIResolver to be used */ public void setModuleURIResolver(ModuleURIResolver resolver) { env.setModuleURIResolver(resolver); } /** * Get the user-defined ModuleURIResolver for resolving URIs used in import module * declarations in the XQuery prolog; returns null if none has been explicitly set either * here or in the Saxon Configuration. * @return the registered ModuleURIResolver */ /*@Nullable*/ public ModuleURIResolver getModuleURIResolver() { return env.getModuleURIResolver(); } /** * Set the encoding of the supplied query. This is ignored if the query is supplied * in character form, that is, as a String or as a Reader. If no value * is set, the query processor will attempt to infer the encoding, defaulting to UTF-8 if no * information is available. * @param encoding the encoding of the supplied query, for example "iso-8859-1" * @since 9.1 */ public void setEncoding(String encoding) { this.encoding = encoding; } /** * Get the encoding previously set for the supplied query. * @return the encoding previously set using {@link #setEncoding(String)}, or null * if no value has been set. Note that this is not necessarily the actual encoding of the query. * @since 9.2 */ public String getEncoding() { return encoding; } /** * Say whether the query is allowed to be updating. XQuery update syntax will be rejected * during query compilation unless this flag is set. XQuery Update is supported only under Saxon-EE. * @param updating true if the query is allowed to use the XQuery Update facility * (requires Saxon-EE). If set to false, the query must not be an updating query. If set * to true, it may be either an updating or a non-updating query. * @since 9.1 */ public void setUpdatingEnabled(boolean updating) { env.setUpdatingEnabled(updating); } /** * Ask whether the query is allowed to use XQuery Update syntax * @return true if the query is allowed to use the XQuery Update facility. Note that this * does not necessarily mean that the query is an updating query; but if the value is false, * the it must definitely be non-updating. * @since 9.1 */ public boolean isUpdatingEnabled() { return env.isUpdatingEnabled(); } /** * Say that the query must be compiled to be schema-aware, even if it contains no * "import schema" declarations. Normally a query is treated as schema-aware * only if it contains one or more "import schema" declarations. If it is not schema-aware, * then all input documents must be untyped (or xs:anyType), and validation of temporary nodes is disallowed * (though validation of the final result tree is permitted). Setting the argument to true * means that schema-aware code will be compiled regardless. * @param schemaAware If true, the stylesheet will be compiled with schema-awareness * enabled even if it contains no xsl:import-schema declarations. If false, the stylesheet * is treated as schema-aware only if it contains one or more xsl:import-schema declarations. * @since 9.2 */ public void setSchemaAware(boolean schemaAware) { env.setSchemaAware(schemaAware); } /** * Ask whether schema-awareness has been requested either by means of a call on * {@link #setSchemaAware} * @return true if schema-awareness has been requested * @since 9.2 */ public boolean isSchemaAware() { return env.isSchemaAware(); } /** * Say whether an XQuery 1.0 or XQuery 3.0 processor is required. * @param version Must be "1.0" or "3.0". At present onle limited support * for XQuery 3.01 is available. This functionality is available only in Saxon-EE, and it cannot * be used in conjunction with XQuery Updates. To use XQuery 3.0 features, * the query prolog must also specify version="3.0". *

In Saxon 9.3, the value "1.1" is accepted as a synonym for "3.0".

* @throws IllegalArgumentException if the version is not 1.0 or 3.0. * @since 9.2 */ public void setLanguageVersion(String version) { DecimalValue v; try { v = (DecimalValue)DecimalValue.makeDecimalValue(version, true).asAtomic(); } catch (ValidationException ve) { throw new IllegalArgumentException(ve); } if (DecimalValue.ONE_POINT_ONE.equals(v)) { v = DecimalValue.THREE; } if (!DecimalValue.ONE.equals(v) && !DecimalValue.THREE.equals(v)) { throw new IllegalArgumentException("LanguageVersion " + v); } env.setLanguageVersion(v); } /** * Ask whether an XQuery 1.0 or XQuery 1.1 processor is being used * @return version: "1.0" or "3.0" * @since 9.2 */ public String getLanguageVersion() { return env.getLanguageVersion().toString(); } /** * Declare a namespace binding as part of the static context for queries compiled using this * XQueryCompiler. This binding may be overridden by a binding that appears in the query prolog. * The namespace binding will form part of the static context of the query, but it will not be copied * into result trees unless the prefix is actually used in an element or attribute name. * * @param prefix The namespace prefix. If the value is a zero-length string, this method sets the default * namespace for elements and types. * @param uri The namespace URI. It is possible to specify a zero-length string to "undeclare" a namespace; * in this case the prefix will not be available for use, except in the case where the prefix * is also a zero length string, in which case the absence of a prefix implies that the name * is in no namespace. * @throws NullPointerException if either the prefix or uri is null. * @throws IllegalArgumentException in the event of an invalid declaration of the XML namespace */ public void declareNamespace(String prefix, String uri) { env.declareNamespace(prefix, uri); } /** * Bind a collation URI to a collation * @param uri the absolute collation URI * @param collation a {@link java.text.Collator} object that implements the required collation * @throws IllegalArgumentException if an attempt is made to rebind the standard URI * for the Unicode codepoint collation * @since 9.4 */ public void declareCollation(String uri, final java.text.Collator collation) { if (uri.equals(NamespaceConstant.CODEPOINT_COLLATION_URI)) { throw new IllegalArgumentException("Cannot declare the Unicode codepoint collation URI"); } StringCollator saxonCollation; if (collation instanceof RuleBasedCollator) { saxonCollation = new RuleBasedSubstringMatcher((RuleBasedCollator)collation); } else { saxonCollation = new SimpleCollation(collation); } env.getCollationMap().setNamedCollation(uri, saxonCollation); } /** * Declare the default collation * @param uri the absolute URI of the default collation. This URI must have been bound to a collation * using the method {@link #declareCollation(String, java.text.Collator)} * @throws IllegalStateException if the collation URI has not been registered, unless it is the standard * Unicode codepoint collation which is registered implicitly * @since 9.4 */ public void declareDefaultCollation(String uri) { if (env.getCollationMap().getNamedCollation(uri) == null) { throw new IllegalStateException("Unknown collation " + uri); } env.getCollationMap().setDefaultCollationName(uri); } /** * Declare the static type of the context item. If this type is declared, and if a context item * is supplied when the query is invoked, then the context item must conform to this type (no * type conversion will take place to force it into this type). * @param type the required type of the context item */ public void setRequiredContextItemType(ItemType type) { requiredContextItemType = type; env.setRequiredContextItemType(type.getUnderlyingItemType()); } /** * Get the required type of the context item. If no type has been explicitly declared for the context * item, an instance of AnyItemType (representing the type item()) is returned. * @return the required type of the context item */ public ItemType getRequiredContextItemType() { return requiredContextItemType; } /** * Compile a library module supplied as a string. The code generated by compiling the library is available * for importing by all subsequent compilations using the same XQueryCompiler; it is identified by an * "import module" declaration that specifies the module URI of the library module. No module location * hint is required, and if one is present, it is ignored. *

The base URI of the query should be supplied by calling {@link #setBaseURI(java.net.URI)}

*

Separate compilation of library modules is supported only under Saxon-EE

* @param query the text of the query * @throws SaxonApiException if the query compilation fails with a static error * @since 9.2 */ public void compileLibrary(String query) throws SaxonApiException { try { env.compileLibrary(query); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Compile a library module supplied as a file. The code generated by compiling the library is available * for importing by all subsequent compilations using the same XQueryCompiler; it is identified by an * "import module" declaration that specifies the module URI of the library module. No module location * hint is required, and if one is present, it is ignored. *

The encoding of the input stream may be specified using {@link #setEncoding(String)}; * if this has not been set, the compiler determines the encoding from the version header of the * query, and if that too is absent, it assumes UTF-8.

*

Separate compilation of library modules is supported only under Saxon-EE

* @param query the file containing the query. The URI corresponding to this file will be used as the * base URI of the query, overriding any URI supplied using {@link #setBaseURI(java.net.URI)} (but not * overriding any base URI specified within the query prolog) * @throws SaxonApiException if the query compilation fails with a static error * @throws IOException if the file does not exist or cannot be read * @since 9.2 */ public void compileLibrary(File query) throws SaxonApiException, IOException { FileInputStream stream = null; try { stream = new FileInputStream(query); String savedBaseUri = env.getBaseURI(); env.setBaseURI(query.toURI().toString()); env.compileLibrary(stream, encoding); env.setBaseURI(savedBaseUri); } catch (XPathException e) { throw new SaxonApiException(e); } finally { if (stream != null) { stream.close(); } } } /** * Compile a library module supplied as a Reader. The code generated by compiling the library is available * for importing by all subsequent compilations using the same XQueryCompiler; it is identified by an * "import module" declaration that specifies the module URI of the library module. No module location * hint is required, and if one is present, it is ignored. *

The base URI of the query should be supplied by calling {@link #setBaseURI(java.net.URI)}

*

Separate compilation of library modules is supported only under Saxon-EE

* @param query the text of the query * @throws SaxonApiException if the query compilation fails with a static error * @since 9.2 */ public void compileLibrary(Reader query) throws SaxonApiException { try { env.compileLibrary(query); } catch (XPathException e) { throw new SaxonApiException(e); } catch (IOException e) { throw new SaxonApiException(e); } } /** * Compile a library module supplied as an InputStream. The code generated by compiling the library is available * for importing by all subsequent compilations using the same XQueryCompiler; it is identified by an * "import module" declaration that specifies the module URI of the library module. No module location * hint is required, and if one is present, it is ignored. *

The encoding of the input stream may be specified using {@link #setEncoding(String)}; * if this has not been set, the compiler determines the encoding from the version header of the * query, and if that too is absent, it assumes UTF-8.

*

The base URI of the query should be supplied by calling {@link #setBaseURI(java.net.URI)}

*

Separate compilation of library modules is supported only under Saxon-EE

* @param query the text of the query * @throws SaxonApiException if the query compilation fails with a static error * @since 9.2 */ public void compileLibrary(InputStream query) throws SaxonApiException { try { env.compileLibrary(query, encoding); } catch (XPathException e) { throw new SaxonApiException(e); } catch (IOException e) { throw new SaxonApiException(e); } } /** * Compile a query supplied as a string. *

The base URI of the query should be supplied by calling {@link #setBaseURI(java.net.URI)}

* @param query the text of the query * @return an XQueryExecutable representing the compiled query * @throws SaxonApiException if the query compilation fails with a static error * @since 9.0 */ public XQueryExecutable compile(String query) throws SaxonApiException { try { return new XQueryExecutable(processor, env.compileQuery(query)); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Compile a query supplied as a file * @param query the file containing the query. The URI corresponding to this file will be used as the * base URI of the query, overriding any URI supplied using {@link #setBaseURI(java.net.URI)} (but not * overriding any base URI specified within the query prolog) * @return an XQueryExecutable representing the compiled query * @throws SaxonApiException if the query compilation fails with a static error * @throws IOException if the file does not exist or cannot be read * @since 9.1 */ public XQueryExecutable compile(File query) throws SaxonApiException, IOException { FileInputStream stream = null; try { stream = new FileInputStream(query); String savedBaseUri = env.getBaseURI(); env.setBaseURI(query.toURI().toString()); XQueryExecutable exec = new XQueryExecutable(processor, env.compileQuery(stream, encoding)); env.setBaseURI(savedBaseUri); return exec; } catch (XPathException e) { throw new SaxonApiException(e); } finally { if (stream != null) { stream.close(); } } } /** * Compile a query supplied as an InputStream *

The base URI of the query should be supplied by calling {@link #setBaseURI(java.net.URI)}

* @param query the input stream on which the query is supplied. This will be consumed by this method * @return an XQueryExecutable representing the compiled query * @throws SaxonApiException if the query compilation fails with a static error * @throws IOException if the file does not exist or cannot be read * @since 9.1 */ public XQueryExecutable compile(InputStream query) throws SaxonApiException, IOException { try { return new XQueryExecutable(processor, env.compileQuery(query, encoding)); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Compile a query supplied as a Reader *

The base URI of the query should be supplied by calling {@link #setBaseURI(java.net.URI)}

* @param query the input stream on which the query is supplied. This will be consumed by this method * @return an XQueryExecutable representing the compiled query * @throws SaxonApiException if the query compilation fails with a static error * @throws IOException if the file does not exist or cannot be read * @since 9.1 */ public XQueryExecutable compile(Reader query) throws SaxonApiException, IOException { try { return new XQueryExecutable(processor, env.compileQuery(query)); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Get the underlying {@link net.sf.saxon.query.StaticQueryContext} object that maintains the static context * information on behalf of this XQueryCompiler. This method provides an escape hatch to internal Saxon * implementation objects that offer a finer and lower-level degree of control than the s9api classes and * methods. Some of these classes and methods may change from release to release. * @return the underlying StaticQueryContext object * @since 9.2 */ public StaticQueryContext getUnderlyingStaticContext() { return env; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/QName.java0000644000175000017500000004617611671711573023112 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.om.InscopeNamespaceResolver; import net.sf.saxon.om.NameChecker; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; /** * The QName class represents an instance of xs:QName, as defined in the XPath 2.0 data model. * Internally, it has three components, a namespace URI, a local name, and a prefix. The prefix * is intended to be used only when converting the value back to a string. * *

This class also defines a number of QName-valued constants relating to built-in types in * XML Schema

* *

A QName is immutable.

* *

Note that a QName is not itself an {@link XdmItem} in this model; however it can be wrapped in an * XdmItem.

*/ public class QName { private StructuredQName sqName; /** * Construct a QName using a namespace prefix, a namespace URI, and a local name (in that order). *

This constructor does not check that the components of the QName are lexically valid.

* * @param prefix The prefix of the name. Use either the string "" or null for names that have * no prefix (that is, they are in the default namespace) * @param uri The namespace URI. Use either the string "" or null for names that are not in any namespace. * @param localName The local part of the name */ public QName(String prefix, String uri, String localName) { sqName = new StructuredQName(prefix, uri, localName); } /** * Construct a QName using a namespace URI and a lexical representation. The lexical representation * may be a local name on its own, or it may be in the form prefix:local-name. *

This constructor does not check that the components of the QName are lexically valid.

* * @param uri The namespace URI. Use either the string "" or null for names that are not in any namespace. * @param lexical Either the local part of the name, or the prefix and local part in the format prefix:local */ public QName(String uri, String lexical) { uri = (uri == null ? "" : uri); int colon = lexical.indexOf(':'); if (colon < 0) { sqName = new StructuredQName("", uri, lexical); } else { String prefix = lexical.substring(0, colon); String local = lexical.substring(colon + 1); sqName = new StructuredQName(prefix, uri, local); } } /** * Construct a QName from a localName alone. The localName must not contain a colon. * The resulting QName represents a name in no namespace (which therefore has no prefix)

* * @param localName The local name. This must be a valid NCName, in particular it must contain no colon */ public QName(String localName) { int colon = localName.indexOf(':'); if (colon < 0) { sqName = new StructuredQName("", "", localName); } else { throw new IllegalArgumentException("Local name contains a colon"); } } /** * Construct a QName from a lexical QName, supplying an element node whose * in-scope namespaces are to be used to resolve any prefix contained in the QName. * *

This constructor checks that the components of the QName are * lexically valid.

*

If the lexical QName has no prefix, the name is considered to be in the * default namespace, as defined by xmlns="...".

*

If the prefix of the lexical QName is not in scope, returns null.

* * @param lexicalQName The lexical QName, in the form prefix:local * or simply local. * @param element The element node whose in-scope namespaces are to be used * to resolve the prefix part of the lexical QName. * @throws IllegalArgumentException If the prefix of the lexical QName is not in scope * or if the lexical QName is invalid (for example, if it contains invalid characters) */ public QName(String lexicalQName, XdmNode element) { try { NodeInfo node = (NodeInfo) element.getUnderlyingValue(); sqName = StructuredQName.fromLexicalQName(lexicalQName, true, node.getConfiguration().getNameChecker(), new InscopeNamespaceResolver(node)); } catch (XPathException err) { throw new IllegalArgumentException(err); } } /** * Construct a QName from a JAXP QName object * * @param qName the JAXP QName object */ public QName(javax.xml.namespace.QName qName) { sqName = new StructuredQName(qName.getPrefix(), qName.getNamespaceURI(), qName.getLocalPart()); } /** * Protected constructor accepting a StructuredQName * @param sqName the StructuredQName */ protected QName(StructuredQName sqName) { this.sqName = sqName; } /** * Factory method to construct a QName from a string containing the expanded * QName in Clark notation, that is, {uri}local *

* The prefix part of the QName will be set to an empty string. *

* * @param expandedName The URI in Clark notation: {uri}local if the * name is in a namespace, or simply local if not. * @return the QName corresponding to the supplied name in Clark notation. This will always * have an empty prefix. */ public static QName fromClarkName(String expandedName) { String namespaceURI; String localName; if (expandedName.charAt(0) == '{') { int closeBrace = expandedName.indexOf('}'); if (closeBrace < 0) { throw new IllegalArgumentException("No closing '}' in Clark name"); } namespaceURI = expandedName.substring(1, closeBrace); if (closeBrace == expandedName.length()) { throw new IllegalArgumentException("Missing local part in Clark name"); } localName = expandedName.substring(closeBrace + 1); } else { namespaceURI = ""; localName = expandedName; } return new QName("", namespaceURI, localName); } /** * Validate the QName against the XML 1.0 or XML 1.1 rules for valid names. * * @param processor The Processor in which the name is to be validated. * This determines whether the XML 1.0 or XML 1.1 rules for forming names are used. * @return true if the name is valid, false if not */ public boolean isValid(Processor processor) { NameChecker nc = processor.getUnderlyingConfiguration().getNameChecker(); String prefix = getPrefix(); if (prefix.length() > 0) { if (!nc.isValidNCName(prefix)) { return false; } } return nc.isValidNCName(getLocalName()); } /** * Get the prefix of the QName. This plays no role in operations such as comparison * of QNames for equality, but is retained (as specified in XPath) so that a string representation * can be reconstructed. *

* Returns the zero-length string in the case of a QName that has no prefix. *

* @return the prefix part of the QName, or "" if the name has no known prefix */ public String getPrefix() { return sqName.getPrefix(); } /** * The namespace URI of the QName. Returns "" (the zero-length string) if the * QName is not in a namespace. * @return the namespace part of the QName, or "" for a name in no namespace */ public String getNamespaceURI() { return sqName.getURI(); } /** * The local part of the QName * @return the local part of the QName */ public String getLocalName() { return sqName.getLocalPart(); } /** * The expanded name, as a string using the notation devised by James Clark. * If the name is in a namespace, the resulting string takes the form {uri}local. * Otherwise, the value is the local part of the name. * @return the name in Clark notation. If the name is not in a namespace, returns the * local part of the name. Otherwise returns the concatenation of "{", the namespace part * of the QName, "}", and the local part of the QName. */ public String getClarkName() { String uri = getNamespaceURI(); if (uri.length() == 0) { return getLocalName(); } else { return "{" + uri + "}" + getLocalName(); } } /** * Convert the value to a string. The resulting string is the lexical form of the QName, * using the original prefix if there was one. */ public String toString() { return sqName.getDisplayName(); } /** * Get a hash code for the QName, to support equality matching. This supports the * semantics of equality, which considers only the namespace URI and local name, and * not the prefix. * @return a hashCode for the QName */ public int hashCode() { return sqName.hashCode(); } /** * Test whether two QNames are equal. This supports the * semantics of equality, which considers only the namespace URI and local name, and * not the prefix. * @return true if the namespace URIs are equal and the local parts are equal, when * compared character-by-character. */ public boolean equals(Object other) { return other instanceof QName && sqName.equals(((QName)other).sqName); } /** * Get the underlying StructuredQName * @return the underlying StructuredQName */ protected StructuredQName getStructuredQName() { return sqName; } /** QName denoting the schema type xs:string **/ public static final QName XS_STRING = new QName("xs", NamespaceConstant.SCHEMA, "string"); /** QName denoting the schema type xs:boolean **/ public static final QName XS_BOOLEAN = new QName("xs", NamespaceConstant.SCHEMA, "boolean"); /** QName denoting the schema type xs:decimal **/ public static final QName XS_DECIMAL = new QName("xs", NamespaceConstant.SCHEMA, "decimal"); /** QName denoting the schema type xs:float **/ public static final QName XS_FLOAT = new QName("xs", NamespaceConstant.SCHEMA, "float"); /** QName denoting the schema type xs:double **/ public static final QName XS_DOUBLE = new QName("xs", NamespaceConstant.SCHEMA, "double"); /** QName denoting the schema type xs:duration **/ public static final QName XS_DURATION = new QName("xs", NamespaceConstant.SCHEMA, "duration"); /** QName denoting the schema type xs:dateTime **/ public static final QName XS_DATE_TIME = new QName("xs", NamespaceConstant.SCHEMA, "dateTime"); /** QName denoting the schema type xs:time **/ public static final QName XS_TIME = new QName("xs", NamespaceConstant.SCHEMA, "time"); /** QName denoting the schema type xs:date **/ public static final QName XS_DATE = new QName("xs", NamespaceConstant.SCHEMA, "date"); /** QName denoting the schema type xs:gYearMonth **/ public static final QName XS_G_YEAR_MONTH = new QName("xs", NamespaceConstant.SCHEMA, "gYearMonth"); /** QName denoting the schema type xs:gYear **/ public static final QName XS_G_YEAR = new QName("xs", NamespaceConstant.SCHEMA, "gYear"); /** QName denoting the schema type xs:gMonthDay **/ public static final QName XS_G_MONTH_DAY = new QName("xs", NamespaceConstant.SCHEMA, "gMonthDay"); /** QName denoting the schema type xs:gDay **/ public static final QName XS_G_DAY = new QName("xs", NamespaceConstant.SCHEMA, "gDay"); /** QName denoting the schema type xs:gMonth **/ public static final QName XS_G_MONTH = new QName("xs", NamespaceConstant.SCHEMA, "gMonth"); /** QName denoting the schema type xs:hexBinary **/ public static final QName XS_HEX_BINARY = new QName("xs", NamespaceConstant.SCHEMA, "hexBinary"); /** QName denoting the schema type xs:base64Binary **/ public static final QName XS_BASE64_BINARY = new QName("xs", NamespaceConstant.SCHEMA, "base64Binary"); /** QName denoting the schema type xs:anyURI **/ public static final QName XS_ANY_URI = new QName("xs", NamespaceConstant.SCHEMA, "anyURI"); /** QName denoting the schema type xs:QName **/ public static final QName XS_QNAME = new QName("xs", NamespaceConstant.SCHEMA, "QName"); /** QName denoting the schema type xs:NOTATION **/ public static final QName XS_NOTATION = new QName("xs", NamespaceConstant.SCHEMA, "NOTATION"); /** QName denoting the schema type xs:integer **/ public static final QName XS_INTEGER = new QName("xs", NamespaceConstant.SCHEMA, "integer"); /** QName denoting the schema type xs:nonPositiveInteger **/ public static final QName XS_NON_POSITIVE_INTEGER = new QName("xs", NamespaceConstant.SCHEMA, "nonPositiveInteger"); /** QName denoting the schema type xs:negativeInteger **/ public static final QName XS_NEGATIVE_INTEGER = new QName("xs", NamespaceConstant.SCHEMA, "negativeInteger"); /** QName denoting the schema type xs:long **/ public static final QName XS_LONG = new QName("xs", NamespaceConstant.SCHEMA, "long"); /** QName denoting the schema type xs:int **/ public static final QName XS_INT = new QName("xs", NamespaceConstant.SCHEMA, "int"); /** QName denoting the schema type xs:short **/ public static final QName XS_SHORT = new QName("xs", NamespaceConstant.SCHEMA, "short"); /** QName denoting the schema type xs:byte **/ public static final QName XS_BYTE = new QName("xs", NamespaceConstant.SCHEMA, "byte"); /** QName denoting the schema type xs:nonNegativeInteger **/ public static final QName XS_NON_NEGATIVE_INTEGER = new QName("xs", NamespaceConstant.SCHEMA, "nonNegativeInteger"); /** QName denoting the schema type xs:positiveInteger **/ public static final QName XS_POSITIVE_INTEGER = new QName("xs", NamespaceConstant.SCHEMA, "positiveInteger"); /** QName denoting the schema type xs:unsignedLong **/ public static final QName XS_UNSIGNED_LONG = new QName("xs", NamespaceConstant.SCHEMA, "unsignedLong"); /** QName denoting the schema type xs:unsignedInt **/ public static final QName XS_UNSIGNED_INT = new QName("xs", NamespaceConstant.SCHEMA, "unsignedInt"); /** QName denoting the schema type xs:unsignedShort **/ public static final QName XS_UNSIGNED_SHORT = new QName("xs", NamespaceConstant.SCHEMA, "unsignedShort"); /** QName denoting the schema type xs:unsignedByte **/ public static final QName XS_UNSIGNED_BYTE = new QName("xs", NamespaceConstant.SCHEMA, "unsignedByte"); /** QName denoting the schema type xs:normalizedString **/ public static final QName XS_NORMALIZED_STRING = new QName("xs", NamespaceConstant.SCHEMA, "normalizedString"); /** QName denoting the schema type xs:token **/ public static final QName XS_TOKEN = new QName("xs", NamespaceConstant.SCHEMA, "token"); /** QName denoting the schema type xs:language **/ public static final QName XS_LANGUAGE = new QName("xs", NamespaceConstant.SCHEMA, "language"); /** QName denoting the schema type xs:NMTOKEN **/ public static final QName XS_NMTOKEN = new QName("xs", NamespaceConstant.SCHEMA, "NMTOKEN"); /** QName denoting the schema type xs:NMTOKENS **/ public static final QName XS_NMTOKENS = new QName("xs", NamespaceConstant.SCHEMA, "NMTOKENS"); /** QName denoting the schema type xs:Name **/ public static final QName XS_NAME = new QName("xs", NamespaceConstant.SCHEMA, "Name"); /** QName denoting the schema type xs:NCName **/ public static final QName XS_NCNAME = new QName("xs", NamespaceConstant.SCHEMA, "NCName"); /** QName denoting the schema type xs:ID **/ public static final QName XS_ID = new QName("xs", NamespaceConstant.SCHEMA, "ID"); /** QName denoting the schema type xs:IDREF **/ public static final QName XS_IDREF = new QName("xs", NamespaceConstant.SCHEMA, "IDREF"); /** QName denoting the schema type xs:IDREFS **/ public static final QName XS_IDREFS = new QName("xs", NamespaceConstant.SCHEMA, "IDREFS"); /** QName denoting the schema type xs:ENTITY **/ public static final QName XS_ENTITY = new QName("xs", NamespaceConstant.SCHEMA, "ENTITY"); /** QName denoting the schema type xs:ENTITIES **/ public static final QName XS_ENTITIES = new QName("xs", NamespaceConstant.SCHEMA, "ENTITIES"); /** QName denoting the schema type xs:untyped **/ public static final QName XS_UNTYPED = new QName("xs", NamespaceConstant.SCHEMA, "untyped"); /** QName denoting the schema type xs:untypedAtomic **/ public static final QName XS_UNTYPED_ATOMIC = new QName("xs", NamespaceConstant.SCHEMA, "untypedAtomic"); /** QName denoting the schema type xs:anyAtomicType **/ public static final QName XS_ANY_ATOMIC_TYPE = new QName("xs", NamespaceConstant.SCHEMA, "anyAtomicType"); /** QName denoting the schema type xs:yearMonthDuration **/ public static final QName XS_YEAR_MONTH_DURATION = new QName("xs", NamespaceConstant.SCHEMA, "yearMonthDuration"); /** QName denoting the schema type xs:dayTimeDuration **/ public static final QName XS_DAY_TIME_DURATION = new QName("xs", NamespaceConstant.SCHEMA, "dayTimeDuration"); /** QName denoting the schema type xs:dateTimeStamp **/ /*@NotNull*/ public static final QName XS_DATE_TIME_STAMP = new QName("xs", NamespaceConstant.SCHEMA, "dateTimeStamp"); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/SequenceType.java0000644000175000017500000000411411671711573024505 0ustar mathieumathieupackage net.sf.saxon.s9api; /** * A SequenceType is the combination of an ItemType and an OccurrenceIndicator */ public class SequenceType { private ItemType itemType; private OccurrenceIndicator occurrenceIndicator; /** * Construct a SequenceType * @param itemType the ItemType * @param occurrenceIndicator the permitted number of occurrences of the item in the sequence */ private SequenceType(ItemType itemType, OccurrenceIndicator occurrenceIndicator) { this.itemType = itemType; this.occurrenceIndicator = occurrenceIndicator; } /** * Factory method to construct a SequenceType * @param itemType the ItemType * @param occurrenceIndicator the permitted number of occurrences of the item in the sequence * @return the constricted SequenceType */ /*@NotNull*/ public static SequenceType makeSequenceType(ItemType itemType, OccurrenceIndicator occurrenceIndicator) { return new SequenceType(itemType, occurrenceIndicator); } /** * Get the item type * @return the item type */ public ItemType getItemType() { return itemType; } /** * Get the occurrence indicator * @return the occurrence indicator */ public OccurrenceIndicator getOccurrenceIndicator() { return occurrenceIndicator; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/package.html0000644000175000017500000000610411671711573023512 0ustar mathieumathieu Package overview for net.sf.saxon.s9api

This package provides Saxon's preferred Java API for XSLT, XQuery, XPath, and XML Schema processing. The interface is designed to hide as much as possible of the detail of the implementation. However, the API architecture faithfully reflects the internal architecture of the Saxon product, unlike standard APIs such as JAXP and XQJ which in many cases force compromises in the design and performance of the application.

An application starts by loading a {@link net.sf.saxon.s9api.Processor}, which allows configuration options to be set. As far as possible, an application should instantiate a single Processor.

The interfaces for XSLT, XQuery, and XPath processing all follow the same pattern. There is a three-stage execution model: first a compiler is created using a factory method in the Processor object. The compiler holds compile-time options and the static context information. Then the compiler's compile() method is called to create an executable, a representation of the compiled stylesheet, query, or expression. This is thread-safe and immutable once created. To run the query or transformation, first call the load() method to create a run-time object called variously an {@link net.sf.saxon.s9api.XsltTransformer}, {@link net.sf.saxon.s9api.XQueryEvaluator}, or {@link net.sf.saxon.s9api.XPathSelector}. This holds run-time context information such as parameter settings and the initial context node; the object is therefore not shareable and should only be run in a single thread; indeed it should normally only be used once. This object also provides methods allowing the transformation or query to be executed.

In Saxon-EE the Processor owns a {@link net.sf.saxon.s9api.SchemaManager} that holds the cache of schema components and can be used to load new schema components from source schema documents. It can also be used to create a {@link net.sf.saxon.s9api.SchemaValidator}, which in turn is used to validate instance documents.

Source documents can be constructed using a {@link net.sf.saxon.s9api.DocumentBuilder}, which holds all the options and parameters to control document building.

The output of a transformation, or of any other process that generates an XML tree, can be sent to a {@link net.sf.saxon.s9api.Destination}. There are a number of implementations of this interface, including a {@link net.sf.saxon.s9api.Serializer} which translates the XML document tree into lexical XML form.

There are classes to represent the objects of the XDM data model, including {@link net.sf.saxon.s9api.XdmValue}, {@link net.sf.saxon.s9api.XdmItem}, {@link net.sf.saxon.s9api.XdmNode}, and {@link net.sf.saxon.s9api.XdmAtomicValue}.

The s9api interface is designed to take advantage of Java 5 constructs such as generics and iterables.


Michael H. Kay
Saxonica Limited
30 July 2010

saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/SaxonApiException.java0000644000175000017500000000466611671711573025510 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.trans.XPathException; /** * An exception thrown by the Saxon s9api API. This is always a wrapper for some other underlying exception */ public class SaxonApiException extends Exception { /** * Create a SaxonApiException * @param cause the underlying cause of the exception */ public SaxonApiException(Throwable cause) { super(cause); } /** * Create a SaxonApiException * @param message the message */ public SaxonApiException(String message) { super(new XPathException(message)); } /** * Create a SaxonApiException * @param message the message * @param cause the underlying cause of the exception */ public SaxonApiException(String message, Throwable cause) { super(new XPathException(message, cause)); } /** * Returns the detail message string of this throwable. * * @return the detail message string of this Throwable instance * (which may be null). */ public String getMessage() { return getCause().getMessage(); } /** * Get the error code associated with the exception, if there is one * @return the associated error code, or null if no error code is available * @since 9.3 */ /*@Nullable*/ public QName getErrorCode() { Throwable cause = getCause(); if (cause instanceof XPathException) { StructuredQName code = ((XPathException)cause).getErrorCodeQName(); return (code==null ? null : new QName(code)); } else { return null; } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/BuildingStreamWriter.java0000644000175000017500000000656211671711573026212 0ustar mathieumathieupackage net.sf.saxon.s9api; import javax.xml.stream.XMLStreamWriter; /** * A BuildingStreamWriter allows a document to be constructed by calling the methods defined in the * {@link javax.xml.stream.XMLStreamWriter} interface; after the document has been constructed, its root * node may be retrieved by calling the getDocumentNode() method. * *

The class will attempt to generate namespace prefixes where none have been supplied, unless the * inventPrefixes option is set to false. The preferred mode of use is to call the versions * of writeStartElement and writeAttribute that supply the prefix, URI, and * local name in full. If the prefix is omitted, the class attempts to invent a prefix. If the URI is * omitted, the name is assumed to be in no namespace. The writeNamespace

method should be * called only if there is a need to declare a namespace prefix that is not used on any element or * attribute name.

* *

The class will check all names, URIs, and character content for conformance against XML well-formedness * rules unless the checkValues option is set to false.

*/ public interface BuildingStreamWriter extends XMLStreamWriter { /** * After building the document by writing a sequence of events, retrieve the root node * of the constructed document tree * @return the root node of the constructed tree. The result is undefined (maybe null, maybe an exception) * if the method is called before successfully completing the sequence of events (of which the last should be * {@link #writeEndDocument}) that constructs the tree. * @throws SaxonApiException if any failure occurs */ public XdmNode getDocumentNode() throws SaxonApiException; /** * Say whether prefixes are to be invented when none is specified by the user * @param invent true if prefixes are to be invented. Default is true. */ public void setInventPrefixes(boolean invent); /** * Ask whether prefixes are to be invented when none is specified by the user * @return true if prefixes are to be invented. Default is true. */ public boolean isInventPrefixes(); /** * Say whether names and values are to be checked for conformance with XML rules * @param check true if names and values are to be checked. Default is true. */ public void setCheckValues(boolean check); /** * Ask whether names and values are to be checked for conformance with XML rules * @return true if names and values are to be checked. Default is true. */ public boolean isCheckValues(); } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/SaxonApiUncheckedException.java0000644000175000017500000000315111671711573027306 0ustar mathieumathieupackage net.sf.saxon.s9api; /** * An unchecked exception thrown by the Saxon API. Unchecked exceptions are used only when errors occur in a method * for which the interface specification defines no checked exception, for example {@link java.util.Iterator#next()}. * The exception always wraps some underlying exception, which can be retrieved using {@link #getCause()} */ public class SaxonApiUncheckedException extends RuntimeException { /** * Create an unchecked exception * @param err the underlying cause */ public SaxonApiUncheckedException(Throwable err) { super(err); } /** * Returns the detail message string of this throwable. * * @return the detail message string of this Throwable instance * (which may be null). */ public String getMessage() { return getCause().getMessage(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XdmNodeKind.java0000644000175000017500000000241611671711573024242 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.type.Type; /** * Enumeration class defining the seven kinds of node defined in the XDM model */ public enum XdmNodeKind { DOCUMENT (Type.DOCUMENT), ELEMENT (Type.ELEMENT), ATTRIBUTE (Type.ATTRIBUTE), TEXT (Type.TEXT), COMMENT (Type.COMMENT), PROCESSING_INSTRUCTION (Type.PROCESSING_INSTRUCTION), NAMESPACE (Type.NAMESPACE); private int number; private XdmNodeKind(int number) { this.number = number; } protected int getNumber() { return number; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XdmEmptySequence.java0000644000175000017500000000400111671711573025326 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.value.EmptySequence; /** * The class XdmEmptySequence represents an empty sequence in the XDM Data Model. * *

This is a singleton class: there is only one instance, which may be obtained * using the {@link #getInstance} method.

* *

An empty sequence may also be represented by an {@link XdmValue} whose length happens to be zero. * Applications should therefore not test to see whether an object is an instance of this class * in order to decide whether it is empty.

* *

Note: in interfaces that expect an {@link XdmItem}, an empty sequence is represented by a * Java null value.

*/ public class XdmEmptySequence extends XdmValue { private static XdmEmptySequence THE_INSTANCE = new XdmEmptySequence(); /** * Return the singleton instance of this class * @return an XdmValue representing an empty sequence */ /*@NotNull*/ public static XdmEmptySequence getInstance() { return THE_INSTANCE; } private XdmEmptySequence() { super(EmptySequence.getInstance()); } /** * Get the number of items in the sequence * @return the number of items in the value - always zero */ @Override public int size() { return 0; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/TeeDestination.java0000644000175000017500000000566311671711573025024 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.TeeOutputter; /** * A TeeDestination allows writing to two destinations at once. For example the output of a transformation * can be written simultaneously to a Serializer and to a second Transformation. By chaining together a number * of TeeDestinations it is possible to write to any number of destinations at once. * @since 9.1 */ public class TeeDestination implements Destination { private Destination dest0; private Destination dest1; /** * Create a TeeDestination: a destination which copies everything that is sent to it to two * separate destinations * @param destination0 the first destination * @param destination1 the second destination */ public TeeDestination(Destination destination0, Destination destination1) { dest0 = destination0; dest1 = destination1; } /** * Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. It is the caller's responsibility to * initialize this Receiver with a {@link net.sf.saxon.event.PipelineConfiguration} before calling * its open() method. * @throws net.sf.saxon.s9api.SaxonApiException * if the Receiver cannot be created */ /*@NotNull*/ public Receiver getReceiver(Configuration config) throws SaxonApiException { return new TeeOutputter(dest0.getReceiver(config), dest1.getReceiver(config)); } /** * Close the destination, allowing resources to be released. Saxon calls this method when * it has finished writing to the destination. */ public void close() throws SaxonApiException { dest0.close(); dest1.close(); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XsltTransformer.java0000644000175000017500000005400111754672153025252 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.Controller; import net.sf.saxon.event.Builder; import net.sf.saxon.event.Receiver; import net.sf.saxon.lib.TraceListener; import net.sf.saxon.om.DocumentInfo; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import java.io.File; import java.util.Properties; /** * An XsltTransformer represents a compiled and loaded stylesheet ready for execution. * The XsltTransformer holds details of the dynamic evaluation context for the stylesheet. *

*

An XsltTransformer must not be used concurrently in multiple threads. * It is safe, however, to reuse the object within a single thread to run the same * stylesheet several times. Running the stylesheet does not change the context * that has been established.

*

*

An XsltTransformer is always constructed by running the Load * method of an {@link XsltExecutable}.

*

*

An XsltTransformer is itself a Destination. This means it is possible to use * one XsltTransformer as the destination to receive the results of another transformation, * this providing a simple way for transformations to be chained into a pipeline. Note however that a * when the input to a transformation is supplied in this way, it will always be built as a tree in * memory, rather than the transformation being streamed.

* * @since 9.0 */ public class XsltTransformer implements Destination { // TODO: when input is piped into an XsltTransformer, do a streamed transformation where appropriate. private Processor processor; private Controller controller; /*@Nullable*/ private Source initialSource; private Destination destination; private Builder sourceTreeBuilder; boolean baseOutputUriWasSet = false; /** * Protected constructor * * @param processor the S9API processor * @param controller the Saxon controller object */ protected XsltTransformer(Processor processor, Controller controller) { this.processor = processor; this.controller = controller; } /** * Set the initial named template for the transformation * * @param templateName the name of the initial template, or null to indicate * that there should be no initial named template * @throws SaxonApiException if there is no named template with this name */ public void setInitialTemplate(QName templateName) throws SaxonApiException { try { controller.setInitialTemplate( templateName == null ? null : templateName.getClarkName()); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Get the initial named template for the transformation, if one has been set * * @return the name of the initial template, or null if none has been set */ public QName getInitialTemplate() { String template = controller.getInitialTemplate(); return (template == null ? null : QName.fromClarkName(template)); } /** * Set the initial mode for the transformation * * @param modeName the name of the initial mode, or null to indicate the default * (unnamed) mode */ public void setInitialMode(QName modeName) { controller.setInitialMode(modeName == null ? null : modeName.getClarkName()); } /** * Get the name of the initial mode for the transformation, if one has been set. * * @return the initial mode for the transformation. Returns null if no mode has been set, * or if the mode was set to null to represent the default (unnamed) mode */ public QName getInitialMode() { String mode = controller.getInitialModeName(); if (mode == null) { return null; } else { return QName.fromClarkName(mode); } } /** * Set the schema validation mode for the transformation. This indicates how source documents * loaded specifically for this transformation will be handled. This applies to the * principal source document if supplied as a SAXSource or StreamSource, and to all * documents loaded during the transformation using the doc(), document(), * or collection() functions. * * @param mode the validation mode. Passing null causes no change to the existing value. * Passing {@link ValidationMode#DEFAULT} resets to the initial value, which determines * the validation requirements from the Saxon Configuration. */ public void setSchemaValidationMode(ValidationMode mode) { if (mode != null) { controller.setSchemaValidationMode(mode.getNumber()); } } /** * Get the schema validation mode for the transformation. This indicates how source documents * loaded specifically for this transformation will be handled. This applies to the * principal source document if supplied as a SAXSource or StreamSource, and to all * documents loaded during the transformation using the doc(), document(), * or collection() functions. * * @return the validation mode. */ public ValidationMode getSchemaValidationMode() { return ValidationMode.get(controller.getSchemaValidationMode()); } /** * Set the source document for the transformation. *

*

If the source is an instance of {@link net.sf.saxon.om.NodeInfo}, the supplied node is used * directly as the context node of the query.

*

*

If the source is an instance of {@link javax.xml.transform.dom.DOMSource}, the DOM node identified * by the DOMSource is wrapped as a Saxon node, and this is then used as the context item

*

*

In all other cases a new Saxon tree will be built by the transformation engine when the * transformation starts, unless it is a Saxon-EE streaming transformation, in which case the * document is processed in streaming fashion as it is being parsed.

*

*

To run a transformation in streaming mode, the source should be supplied as an instance * of {@link javax.xml.transform.stream.StreamSource}, {@link javax.xml.transform.sax.SAXSource}, * or {@link net.sf.saxon.event.Transmitter}.

* * @param source the principal source document for the transformation */ public void setSource(Source source) throws SaxonApiException { if (source instanceof NodeInfo) { setInitialContextNode(new XdmNode((NodeInfo) source)); } else if (source instanceof DOMSource) { setInitialContextNode(processor.newDocumentBuilder().wrap(source)); } else { initialSource = source; } } /** * Set the initial context node for the transformation. *

This is ignored in the case where the {@link XsltTransformer} is used as the * {@link Destination} of another process. In that case the initial context node will always * be the document node of the document that is being streamed to this destination.

*

Calling this method has the side-effect of setting the initial source to null.

* * @param node the initial context node, or null if there is to be no initial context node */ public void setInitialContextNode(XdmNode node) { initialSource = (node == null ? null : node.getUnderlyingNode()); } /** * Get the initial context node for the transformation, if one has been set * * @return the initial context node, or null if none has been set. This will not necessarily * be the same {@link XdmNode} instance as was supplied, but it will be an XdmNode object that represents * the same underlying node. */ public XdmNode getInitialContextNode() { if (initialSource instanceof NodeInfo) { return (XdmNode) XdmValue.wrap(((NodeInfo) initialSource)); } else { return null; } } /** * Set the value of a stylesheet parameter * * @param name the name of the stylesheet parameter, as a QName * @param value the value of the stylesheet parameter, or null to clear a previously set value */ public void setParameter(QName name, XdmValue value) { controller.setParameter(name.getStructuredQName(), (value == null ? null : value.getUnderlyingValue())); } /** * Get the value that has been set for a stylesheet parameter * * @param name the parameter whose name is required * @return the value that has been set for the parameter, or null if no value has been set */ public XdmValue getParameter(QName name) { Object oval = controller.getParameter(name.getClarkName()); if (oval == null) { return null; } if (oval instanceof ValueRepresentation) { return XdmValue.wrap((ValueRepresentation) oval); } throw new IllegalStateException(oval.getClass().getName()); } /** * Set the destination to be used for the result of the transformation. *

This method can be used to chain transformations into a pipeline, by using one * {@link XsltTransformer} as the destination of another

*

If the destination is a {@link Serializer}, then a side-effect of this method is to set * the base output URI for the transformation. This acts as the base URI for resolving * the href attribute of any xsl:result-document instruction. * The serialiation parameters defined in the Serializer override any * serialization parameters defined using xsl:output for the principal * output of the transformation. However, they have no effect on any output produced * using xsl:result-document. * * @param destination the destination to be used */ public void setDestination(Destination destination) { this.destination = destination; } /** * Get the destination that was specified in a previous call of {@link #setDestination} * * @return the destination, or null if none has been supplied */ public Destination getDestination() { return destination; } /** * Set the base output URI. *

*

This defaults to the system ID of the Destination for the principal output * of the transformation if this is known; if it is not known, it defaults * to the current directory.

*

*

If no base output URI is supplied, but the Destination of the transformation * is a Serializer that writes to a file, then the URI of this file is used as * the base output URI.

*

*

The base output URI is used for resolving relative URIs in the href attribute * of the xsl:result-document instruction.

* * @param uri the base output URI * @since 9.2 */ public void setBaseOutputURI(String uri) { controller.setBaseOutputURI(uri); baseOutputUriWasSet = (uri != null); } /** * Get the base output URI. *

*

This returns the value set using the {@link #setBaseOutputURI} method. If no value has been set * explicitly, then the method returns null if called before the transformation, or the computed * default base output URI if called after the transformation.

*

*

The base output URI is used for resolving relative URIs in the href attribute * of the xsl:result-document instruction.

* * @return the base output URI * @since 9.2 */ public String getBaseOutputURI() { return controller.getBaseOutputURI(); } /** * Set an object that will be used to resolve URIs used in * fn:doc() and related functions. * * @param resolver An object that implements the URIResolver interface, or * null. * @since 9.3 */ public void setURIResolver(URIResolver resolver) { controller.setURIResolver(resolver); } /** * Get the URI resolver. * * @return the user-supplied URI resolver if there is one, or null otherwise * @since 9.3 */ public URIResolver getURIResolver() { return controller.getURIResolver(); } /** * Set the ErrorListener to be used during this transformation * * @param listener The error listener to be used. This is notified of all dynamic errors detected during the * transformation. * @since 9.2 */ public void setErrorListener(ErrorListener listener) { controller.setErrorListener(listener); } /** * Get the ErrorListener being used during this compilation episode * * @return listener The error listener in use. This is notified of all dynamic errors detected during the * transformation. If no user-supplied ErrorListener has been set the method will return a system-supplied * ErrorListener. * @since 9.2 */ public ErrorListener getErrorListener() { return controller.getErrorListener(); } /** * Set the MessageListener to be notified whenever the stylesheet evaluates an * xsl:message instruction. If no MessageListener is nominated, * the output of xsl:message instructions will be serialized and sent * to the standard error stream. * * @param listener the MessageListener to be used * @since 9.1 */ public void setMessageListener(MessageListener listener) { controller.setMessageEmitter(new MessageListenerProxy(listener, controller.makePipelineConfiguration())); } /** * Get the MessageListener to be notified whenever the stylesheet evaluates an * xsl:message instruction. If no MessageListener has been nominated, * return null * * @return the user-supplied MessageListener, or null if none has been supplied * @since 9.1 */ public MessageListener getMessageListener() { Receiver r = controller.getMessageEmitter(); if (r instanceof MessageListenerProxy) { return ((MessageListenerProxy) r).getMessageListener(); } else { return null; } } /** * Set a TraceListener to be notified of all events occurring during the transformation. * This will only be effective if the stylesheet was compiled with trace code enabled * (see {@link XsltCompiler#setCompileWithTracing(boolean)}) * * @param listener the TraceListener to be used. Note that the TraceListener has access to * interal Saxon interfaces which may vary from one release to the next. It is also possible that * the TraceListener interface itself may be changed in future releases. * @since 9.2 */ public void setTraceListener(TraceListener listener) { controller.setTraceListener(listener); } /** * Get the TraceListener to be notified of all events occurring during the transformation. * If no TraceListener has been nominated, return null * * @return the user-supplied TraceListener, or null if none has been supplied * @since 9.2 */ public TraceListener getTraceListener() { return controller.getTraceListener(); } /** * Perform the transformation. If this method is used, a destination must have been supplied * previously * * @throws SaxonApiException if any dynamic error occurs during the transformation * @throws IllegalStateException if no destination has been supplied */ public void transform() throws SaxonApiException { if (destination == null) { throw new IllegalStateException("No destination has been supplied"); } try { controller.transform(initialSource, getDestinationResult()); destination.close(); } catch (TransformerException e) { throw new SaxonApiException(e); } } private Result getDestinationResult() throws SaxonApiException { if (destination instanceof Serializer) { Properties props = ((Serializer) destination).getOutputProperties(); controller.setOutputProperties(props); if (!baseOutputUriWasSet) { Object dest = ((Serializer) destination).getOutputDestination(); if (dest instanceof File) { controller.setBaseOutputURI(((File) dest).toURI().toString()); } } return ((Serializer)destination).getResult(); } else { return destination.getReceiver(controller.getConfiguration()); } } /** * Return a Receiver which can be used to supply the principal source document for the transformation. * This method is intended primarily for internal use, though it can also * be called by a user application that wishes to feed events into the transformation engine. *

*

Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. This method is provided so that * XsltTransformer implements Destination, allowing one transformation * to receive the results of another in a pipeline.

*

*

Before calling this method, the {@link #setDestination} method must be called to supply a destination * for the transformation.

*

*

Note that when an XsltTransformer is used as a Destination, the initial * context node set on that XsltTransformer using {@link #setInitialContextNode(XdmNode)} is ignored, * as is the source set using {@link #setSource(javax.xml.transform.Source)}.

* * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. * @throws SaxonApiException if the Receiver cannot be created * @throws IllegalStateException if no Destination has been supplied */ public Receiver getReceiver(Configuration config) throws SaxonApiException { if (destination == null) { throw new IllegalStateException("No destination has been supplied"); } if (controller.getInitialMode().isStreamable()) { try { return controller.getStreamingReceiver(controller.getInitialMode(), getDestinationResult()); } catch (TransformerException e) { throw new SaxonApiException(e); } } else { sourceTreeBuilder = controller.makeBuilder(); Receiver stripper = controller.makeStripper(sourceTreeBuilder); if (controller.getExecutable().stripsInputTypeAnnotations()) { stripper = controller.getConfiguration().getAnnotationStripper(stripper); } return stripper; } } /** * Close this destination, allowing resources to be released. Used when this XsltTransformer is acting * as the destination of another transformation. Saxon calls this method when it has finished writing * to the destination. */ public void close() throws SaxonApiException { if (sourceTreeBuilder != null) { DocumentInfo doc = (DocumentInfo) sourceTreeBuilder.getCurrentRoot(); //sourceTreeBuilder.reset(); sourceTreeBuilder = null; if (doc == null) { throw new SaxonApiException("No source document has been built by the previous pipeline stage"); } Result result = getDestinationResult(); try { controller.transformDocument(doc, result); } catch (TransformerException e) { throw new SaxonApiException(e); } destination.close(); } } /** * Get the underlying Controller used to implement this XsltTransformer. This provides access * to lower-level methods not otherwise available in the s9api interface. Note that classes * and methods obtained by this route cannot be guaranteed stable from release to release. * * @since 9.0.0.4 */ public Controller getUnderlyingController() { return controller; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XPathExecutable.java0000644000175000017500000002025011671711573025120 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.expr.StaticContext; import net.sf.saxon.sxpath.IndependentContext; import net.sf.saxon.sxpath.XPathExpression; import net.sf.saxon.sxpath.XPathVariable; import java.util.ArrayList; import java.util.Iterator; /** * An XPathExecutable represents the compiled form of an XPath expression. * To evaluate the expression, it must first be loaded to form an {@link XPathSelector}. * *

An XPathExecutable is immutable, and therefore thread-safe. It is simplest to load * a new XPathSelector each time the expression is to be evaluated. However, the XPathSelector * is serially reusable within a single thread.

* *

An XPathExecutable is created by using the {@link XPathCompiler#compile} method * on the {@link XPathCompiler} class.

*/ public class XPathExecutable { private XPathExpression exp; private Processor processor; private IndependentContext env; // protected constructor protected XPathExecutable(XPathExpression exp, Processor processor, IndependentContext env) { this.exp = exp; this.processor = processor; this.env = env; //this.declaredVariables = declaredVariables; } /** * Load the compiled XPath expression to prepare it for execution. * @return An XPathSelector. The returned XPathSelector can be used to set up the * dynamic context, and then to evaluate the expression. */ public XPathSelector load() { ArrayList declaredVariables = new ArrayList(); for (Iterator iter=env.iterateExternalVariables(); iter.hasNext();) { XPathVariable var = (XPathVariable)iter.next(); declaredVariables.add(var); } return new XPathSelector(exp, declaredVariables); } /** * Get the ItemType of the items in the result of the expression, as determined by static analysis. This * is the most precise ItemType that the processor is able to determine from static examination of the * expression; the actual items in the expression result are guaranteed to belong to this ItemType or to a subtype * of this ItemType. * @return the statically-determined ItemType of the result of the expression * @since 9.1 */ public ItemType getResultItemType() { net.sf.saxon.type.ItemType it = exp.getInternalExpression().getItemType(processor.getUnderlyingConfiguration().getTypeHierarchy()); return new ConstructedItemType(it, processor); } /** * Get the statically-determined cardinality of the result of the expression. This is the most precise cardinality * that the processor is able to determine from static examination of the expression. * @return the statically-determined cardinality of the result of the expression * @since 9.1 */ public OccurrenceIndicator getResultCardinality() { int card = exp.getInternalExpression().getCardinality(); return OccurrenceIndicator.getOccurrenceIndicator(card); } /** * Get an iterator over the names of all the external variables. This includes both variables that have * been explicitly declared using a call to declareVariable(), and variables that are implicitly * declared by reference in the case where the allowUndeclaredVariables option is set. It does * not include range variables bound in a for, some, or every expression. * *

If the allowUndeclaredVariables option is set, this method allows discovery of the variable * references that appear in the compiled expression.

* @return an iterator over the names of the external variables defined in the XPath expression * @since 9.2 */ public Iterator iterateExternalVariables() { final Iterator varIterator = env.iterateExternalVariables(); return new Iterator() { public boolean hasNext() { return varIterator.hasNext(); } public QName next() { return new QName(((XPathVariable)varIterator.next()).getVariableQName()); } public void remove() { throw new UnsupportedOperationException("remove"); } }; } /** * Get the required item type of a declared variable in the static context of the expression. * @param variableName the name of a declared variable * @return the required item type. *

If the variable was explicitly declared, this will be the item type that was set when the * variable was declared. If no item type was set, it will be {@link ItemType#ANY_ITEM}.

*

If the variable was implicitly declared by reference (which can happen only when the * allowUndeclaredVariables option is set), the returned type will be {@link ItemType#ANY_ITEM}.

*

If no variable with the specified QName has been declared either explicitly or implicitly, * the method returns null.

* @since 9.2 */ /*@Nullable*/ public ItemType getRequiredItemTypeForVariable(QName variableName) { XPathVariable var = env.getExternalVariable(variableName.getStructuredQName()); if (var == null) { return null; } else { return new ConstructedItemType(var.getRequiredType().getPrimaryType(), processor); } } /** * Get the required cardinality of a declared variable in the static context of the expression. * @param variableName the name of a declared variable * @return the required cardinality. *

If the variable was explicitly declared, this will be the occurrence indicator that was set when the * variable was declared. If no item type was set, it will be {@link OccurrenceIndicator#ZERO_OR_MORE}.

*

If the variable was implicitly declared by reference (which can happen only when the * allowUndeclaredVariables option is set), the returned type will be * {@link OccurrenceIndicator#ZERO_OR_MORE}.

*

If no variable with the specified QName has been declared either explicitly or implicitly, * the method returns null.

* @since 9.2 */ public OccurrenceIndicator getRequiredCardinalityForVariable(QName variableName) { XPathVariable var = env.getExternalVariable(variableName.getStructuredQName()); if (var == null) { return null; } else { return OccurrenceIndicator.getOccurrenceIndicator(var.getRequiredType().getCardinality()); } } /** * Get the underlying implementation object representing the compiled XPath expression. * This method provides access to lower-level Saxon classes and methods which may be subject to change * from one release to the next. * @return the underlying compiled XPath expression. */ public XPathExpression getUnderlyingExpression() { return exp; } /** * Get the underlying implementation object representing the static context of the compiled * XPath expression. This method provides access to lower-level Saxon classes and methods which may be * subject to change from one release to the next. * @return the underlying static context. */ public StaticContext getUnderlyingStaticContext() { return env; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XdmValue.java0000644000175000017500000001604611671711573023627 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.om.FunctionItem; import net.sf.saxon.om.Item; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.iter.SingletonIterator; import net.sf.saxon.value.AtomicValue; import net.sf.saxon.value.EmptySequence; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; import java.util.ArrayList; import java.util.List; /** * An value in the XDM data model. A value is a sequence of zero or more items, * each item being either an atomic value or a node. * *

An XdmValue is immutable.

* *

A sequence consisting of a single item may be represented as an instance of {@link XdmItem}, * which is a subtype of XdmValue. However, there is no guarantee that a sequence of length one * will always be an instance of XdmItem.

* *

Similarly, a zero-length sequence may be represented as an instance of {@link XdmEmptySequence}, * but there is no guarantee that every sequence of length zero will always be an instance of * XdmEmptySequence.

* * @since 9.0 */ public class XdmValue implements Iterable { private ValueRepresentation value; // this must be a materialized value protected XdmValue() { // must be followed by setValue() } /** * Create an XdmValue as a sequence of XdmItem objects * @param items a sequence of XdmItem objects. Note that if this is supplied as a list or similar * collection, subsequent changes to the list/collection will have no effect on the XdmValue. * @since 9.0.0.4 */ public XdmValue(Iterable items) { List values = new ArrayList(); for (XdmItem item : items) { values.add((Item)item.getUnderlyingValue()); } value = new SequenceExtent(values); } protected XdmValue(ValueRepresentation value) { this.value = value; } protected void setValue(ValueRepresentation value) { this.value = value; } /*@Nullable*/ protected static XdmValue wrap(ValueRepresentation value) { if (value == null) { return null; } else if (value instanceof NodeInfo) { return new XdmNode((NodeInfo)value); } else if (value instanceof AtomicValue) { return new XdmAtomicValue((AtomicValue)value); } else if (value instanceof EmptySequence) { return XdmEmptySequence.getInstance(); } else if (value instanceof FunctionItem) { return new XdmFunctionItem((FunctionItem)value); } else { return new XdmValue(value); } } /** * Create a new XdmValue by concatenating the contents of this XdmValue and another * XdmValue. The two input XdmValue objects are unaffected by this operation * @param otherValue the value to be appended * @return a new XdmValue containing the concatenation of the two input XdmValue objects * @since 9.2 */ public XdmValue append(XdmValue otherValue) { List values = new ArrayList(); for (XdmItem item : this) { values.add((Item)item.getUnderlyingValue()); } for (XdmItem item : otherValue) { values.add((Item)item.getUnderlyingValue()); } return new XdmValue(new SequenceExtent(values)); } /** * Get the number of items in the sequence * @return the number of items in the value * @throws SaxonApiUncheckedException if the value is lazily evaluated and the delayed * evaluation fails with a dynamic error. */ public int size() { try { if (value instanceof Value) { return ((Value)value).getLength(); } else { return 1; } } catch (XPathException err) { throw new SaxonApiUncheckedException(err); } } /** * Get the n'th item in the value, counting from zero. * @param n the item that is required, counting the first item in the sequence as item zero * @return the n'th item in the sequence making up the value, counting from zero * @throws IndexOutOfBoundsException if n is less than zero or greater than or equal to the number * of items in the value * @throws SaxonApiUncheckedException if the value is lazily evaluated and the delayed * evaluation fails with a dynamic error. */ public XdmItem itemAt(int n) throws IndexOutOfBoundsException, SaxonApiUncheckedException { if (n < 0 || n >= size()) { throw new IndexOutOfBoundsException(""+n); } if (value instanceof Value) { try { Item item = ((Value) value).itemAt(n); return (XdmItem)XdmItem.wrap(item); } catch (XPathException e) { throw new SaxonApiUncheckedException(e); } } else { return (XdmNode)XdmNode.wrap(value); } } /** * Get an iterator over the items in this value. * @return an Iterator over the items in this value. * @throws SaxonApiUncheckedException if the value is lazily evaluated and the delayed * evaluation fails with a dynamic error. */ public XdmSequenceIterator iterator() throws SaxonApiUncheckedException { try { ValueRepresentation v = getUnderlyingValue(); if (v instanceof Value) { return new XdmSequenceIterator(((Value)v).iterate()); } else { return new XdmSequenceIterator(SingletonIterator.makeIterator((NodeInfo)v)); } } catch (XPathException e) { throw new SaxonApiUncheckedException(e); } } /** * Get the underlying implementation object representing the value. This method allows * access to lower-level Saxon functionality, including classes and methods that offer * no guarantee of stability across releases. * @return the underlying implementation object representing the value */ public ValueRepresentation getUnderlyingValue() { return value; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/BuildingStreamWriterImpl.java0000644000175000017500000000375111671711573027031 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.event.Builder; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.StreamWriterToReceiver; import net.sf.saxon.trans.XPathException; /** * This class is an implementation of {@link javax.xml.stream.XMLStreamWriter}, allowing * a document to be constructed by means of a series of XMLStreamWriter method calls such * as writeStartElement(), writeAttribute(), writeCharacters(), and writeEndElement(). * *

The detailed way in which this class is packaged is carefully designed to ensure that * if the functionality is not used, the DocumentBuilder is still usable under * JDK 1.5 (which does not include javax.xml.stream interfaces).

*/ public class BuildingStreamWriterImpl extends StreamWriterToReceiver implements BuildingStreamWriter { Builder builder; public BuildingStreamWriterImpl(Receiver receiver, Builder builder) { super(receiver); this.builder = builder; builder.open(); } /*@Nullable*/ public XdmNode getDocumentNode() throws SaxonApiException { try { builder.close(); } catch (XPathException e) { throw new SaxonApiException(e); } return new XdmNode(builder.getCurrentRoot()); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): // saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XdmFunctionItem.java0000644000175000017500000000627611671711573025163 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.expr.XPathContext; import net.sf.saxon.om.FunctionItem; import net.sf.saxon.om.SequenceIterator; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceExtent; import net.sf.saxon.value.Value; /** * The class XdmFunctionItem represents a function item */ public class XdmFunctionItem extends XdmItem { protected XdmFunctionItem(FunctionItem fi) { super(fi); } /** * Get the name of the function * @return the function name, as a QName, or null for an anonymous inline function item */ public QName getName() { FunctionItem fi = (FunctionItem)getUnderlyingValue(); StructuredQName sq = fi.getFunctionName(); return (sq == null ? null : new QName(sq)); } /** * Get the arity of the function * @return the arity of the function, that is, the number of arguments in the function's signature */ public int getArity() { FunctionItem fi = (FunctionItem)getUnderlyingValue(); return fi.getArity(); } /** * Determine whether the item is an atomic value * @return false, the item is not an atomic value, it is a function item */ @Override public boolean isAtomicValue() { return false; } /** * Call the function * @param arguments the values to be supplied as arguments to the function * @param processor the s9api Processor * @return the result of calling the function */ public XdmValue call(XdmValue[] arguments, Processor processor) throws SaxonApiException { if (arguments.length != getArity()) { throw new SaxonApiException("Supplied " + arguments.length + " arguments, required " + getArity()); } try { FunctionItem fi = (FunctionItem)getUnderlyingValue(); SequenceIterator[] argIters = new SequenceIterator[arguments.length]; for (int i=0; i *

Note that this is XML serialization in the sense of the W3C XSLT and XQuery specifications. * This has nothing to do with the serialization of Java objects, or the {@link java.io.Serializable} * interface.

*

*

The serialization may be influenced by a number of serialization parameters. A parameter has a name, * which is an instance of {@link Serializer.Property}, and a value, which is expressed as a string. * The effect of most of the properties is as described in the W3C specification * XSLT 2.0 and XQuery 1.0 Serialization. * Saxon supports all the serialization parameters defined in that specification, together with some * additional parameters, whose property names are prefixed "SAXON_". *

*

Serialization parameters defined via this interface take precedence over any serialization parameters * defined within the source of the query or stylesheet. */ @SuppressWarnings({"ForeachStatement"}) public class Serializer implements Destination { private Configuration config; // Beware: this will often be null private Map properties = new HashMap(10); private StreamResult result = new StreamResult(); private boolean mustClose = false; /** * Enumerator over the defined serialization properties */ public enum Property { /** * Serialization method: xml, html, xhtml, or text */ METHOD(OutputKeys.METHOD), /** * Version of output method, for example "1.0" or "1.1" for XML */ VERSION(OutputKeys.VERSION), /** * Character encoding of output stream */ ENCODING(OutputKeys.ENCODING), /** * Set to "yes" if the XML declaration is to be omitted from the output file */ OMIT_XML_DECLARATION(OutputKeys.OMIT_XML_DECLARATION), /** * Set to "yes", "no", or "omit" to indicate the required value of the standalone attribute * in the XML declaration of the output file */ STANDALONE(OutputKeys.STANDALONE), /** * Set to any string to indicate that the output is to include a DOCTYPE declaration with this public id */ DOCTYPE_PUBLIC(OutputKeys.DOCTYPE_PUBLIC), /** * Set to any string to indicate that the output is to include a DOCTYPE declaration with this system id */ DOCTYPE_SYSTEM(OutputKeys.DOCTYPE_SYSTEM), /** * Space-separated list of QNames (in Clark form) of elements * whose content is to be wrapped in CDATA sections */ CDATA_SECTION_ELEMENTS(OutputKeys.CDATA_SECTION_ELEMENTS), /** * Set to "yes" or "no" to indicate whether indentation is required */ INDENT(OutputKeys.INDENT), /** * Set to indicate the media type (MIME type) of the output */ MEDIA_TYPE(OutputKeys.MEDIA_TYPE), /** * List of names of character maps to be used. Character maps can only be specified in an XSLT * stylesheet. */ USE_CHARACTER_MAPS(SaxonOutputKeys.USE_CHARACTER_MAPS), /** * For HTML and XHTML, set to "yes" or "no" to indicate whether a <meta> element is to be * written to indicate the content type and encoding */ INCLUDE_CONTENT_TYPE(SaxonOutputKeys.INCLUDE_CONTENT_TYPE), /** * Set to "yes" or "no" to indicate (for XML 1.1) whether namespace that go out of scope should * be undeclared */ UNDECLARE_PREFIXES(SaxonOutputKeys.UNDECLARE_PREFIXES), /** * Set to "yes" or "no" to indicate (for HTML and XHTML) whether URI-valued attributes should be * percent-encoded */ ESCAPE_URI_ATTRIBUTES(SaxonOutputKeys.ESCAPE_URI_ATTRIBUTES), /** * Set to "yes" or "no" to indicate whether a byte order mark is to be written */ BYTE_ORDER_MARK(SaxonOutputKeys.BYTE_ORDER_MARK), /** * Set to the name of a Unicode normalization form: "NFC", "NFD", "NFKC", or "NFKD", or * "none" to indicate no normalization */ NORMALIZATION_FORM(SaxonOutputKeys.NORMALIZATION_FORM), /** * Saxon extension: set to an integer (represented as a string) giving the number of spaces * by which each level of nesting should be indented. Default is 3. */ SAXON_INDENT_SPACES(SaxonOutputKeys.INDENT_SPACES), /** * Saxon extension: set to an integer (represented as a string) giving the desired maximum * length of lines when indenting. Default is 80. */ SAXON_LINE_LENGTH(SaxonOutputKeys.LINE_LENGTH), /** * Saxon extension: set to a space-separated list of element names, in Clark notation, * within which no content is to be indented. This is typically because the element contains * mixed content in which whitespace is significant. */ SAXON_SUPPRESS_INDENTATION(SaxonOutputKeys.SUPPRESS_INDENTATION), /** * Saxon extension: set to a space-separated list of element names, in Clark notation, * representing elements that will be preceded by an extra blank line in the output in addition * to normal indentation. */ SAXON_DOUBLE_SPACE(SaxonOutputKeys.DOUBLE_SPACE), /** * Saxon extension for internal use: used in XSLT to tell the serializer whether the * stylesheet used version="1.0" or version="2.0" */ SAXON_STYLESHEET_VERSION(SaxonOutputKeys.STYLESHEET_VERSION), /** * Saxon extension to indicate how characters outside the encoding should be represented, * for example "hex" for hexadecimal character references, "decimal" for decimal character references */ SAXON_CHARACTER_REPRESENTATION(SaxonOutputKeys.CHARACTER_REPRESENTATION), /** * Saxon extension to indicate that output should not be serialized, but should be further transformed. * The property gives the relative URI of a stylesheet to be applied. Note that the {@link Serializer} * class does not recognize this property. */ SAXON_NEXT_IN_CHAIN(SaxonOutputKeys.NEXT_IN_CHAIN), /** * Saxon extension, indicate the base URI against which {@link Property#SAXON_NEXT_IN_CHAIN} should be * resolved. */ SAXON_NEXT_IN_CHAIN_BASE_URI(SaxonOutputKeys.NEXT_IN_CHAIN_BASE_URI), /** * Saxon extension for use when writing to the text output method; this option causes the processing * instructions hex and b64 to be recognized containing hexBinary or base64 data respectively. */ SAXON_RECOGNIZE_BINARY(SaxonOutputKeys.RECOGNIZE_BINARY), /** * Saxon extension for use when output is sent to a SAX ContentHandler: indicates that the output * is required to be well-formed (exactly one top-level element) */ SAXON_REQUIRE_WELL_FORMED(SaxonOutputKeys.REQUIRE_WELL_FORMED), /** * Saxon extension, indicates that the output of a query is to be wrapped before serialization, * such that each item in the result sequence is enclosed in an element indicating its type */ SAXON_WRAP(SaxonOutputKeys.WRAP), /** * Saxon extension for internal use in XSLT, indicates that this output document is the implicitly * created result tree as distinct from a tree created using <xsl:result-document> */ SAXON_IMPLICIT_RESULT_DOCUMENT(SaxonOutputKeys.IMPLICIT_RESULT_DOCUMENT), /** * Saxon extension for interfacing with debuggers; indicates that the location information is * available for events in this output stream */ SAXON_SUPPLY_SOURCE_LOCATOR(SaxonOutputKeys.SUPPLY_SOURCE_LOCATOR); private String name; private Property(String name) { this.name = name; } /** * Get the name of the property expressed as a QName in Clark notation. * The namespace will be null for standard serialization properties, * and will be the Saxon namespace http://saxon.sf.net/ for Saxon extensions * * @return the name of the serialization property as a QName in Clark notation, {uri}local */ public String toString() { return name; } /** * Get the name of the property expressed as a QName. * The namespace will be null for standard serialization properties, * and will be the Saxon namespace http://saxon.sf.net/ for Saxon extensions * * @return the name of the serialization property as a QName */ public QName getQName() { return QName.fromClarkName(name); } } /** * Create a Serializer */ public Serializer() { } /** * Create a Serializer initialized to write to a given OutputStream. *

Closing the output stream after use is the responsibility of the caller.

* * @param stream The OutputStream to which the Serializer will write */ public Serializer(OutputStream stream) { setOutputStream(stream); } /** * Create a Serializer initialized to write to a given Writer. *

Closing the writer after use is the responsibility of the caller.

* * @param writer The Writer to which the Serializer will write */ public Serializer(Writer writer) { setOutputWriter(writer); } /** * Create a Serializer initialized to write to a given File. * * @param file The File to which the Serializer will write */ public Serializer(File file) { setOutputFile(file); } /** * Set the Processor associated with this Serializer. This will be called automatically if the * serializer is created using one of the Processor.newSerializer() methods. The Serializer * currently needs to know about the Processor only if the method {@link #getXMLStreamWriter} is called. * * @param processor the associated Processor * @since 9.3 */ public void setProcessor(Processor processor) { this.config = processor.getUnderlyingConfiguration(); } /** * Set the value of a serialization property. Any existing value of the property is overridden. * If the supplied value is null, any existing value of the property is removed. *

*

Example:

*

serializer.setOutputProperty(Serializer.Property.METHOD, "xml");

*

*

Any serialization properties supplied via this interface take precedence over serialization * properties defined in the source stylesheet or query.

* * @param property The name of the property to be set * @param value The value of the property, as a string. The format is generally as defined * in the xsl:output declaration in XSLT: this means that boolean properties, for * example, are represented using the strings "yes" and "no". Properties whose values are QNames, * such as cdata-section-elements are expressed using the Clark representation of * a QName, that is "{uri}local". Multi-valued properties (again, cdata-section-elements * is an example) are expressed as a space-separated list. * @throws IllegalArgumentException if the value of the property is invalid. The property is * validated individually; invalid combinations of properties will be detected only when the properties * are actually used to serialize an XML event stream. */ public void setOutputProperty(Property property, /*@Nullable*/ String value) { try { SaxonOutputKeys.checkOutputProperty(property.toString(), value, null); } catch (XPathException e) { throw new IllegalArgumentException(e.getMessage()); } if (value == null) { properties.remove(property); } else { properties.put(property, value); } } /** * Get the value of a serialization property * * @param property the name of the required property * @return the value of the required property as a string, or null if the property has * not been given any value. */ public String getOutputProperty(Property property) { return properties.get(property); } /** * Set the destination of the serialized output, as a Writer. *

*

Note that when this option is used, the serializer does not perform character * encoding. This also means that it never replaces special characters with XML numeric * character references. The final encoding is the responsibility of the supplied Writer.

*

*

Closing the writer after use is the responsibility of the caller.

*

*

Calling this method has the side-effect of setting the OutputStream and OutputFile to null.

* * @param writer the Writer to which the serialized XML output will be written. */ public void setOutputWriter(Writer writer) { result.setOutputStream(null); result.setSystemId((String) null); result.setWriter(writer); mustClose = false; } /** * Set the destination of the serialized output, as an OutputStream. *

*

Closing the output stream after use is the responsibility of the caller.

*

*

Calling this method has the side-effect of setting the OutputWriter and OutputFile to null.

* * @param stream the OutputStream to which the serialized XML output will be written. */ public void setOutputStream(OutputStream stream) { result.setWriter(null); result.setSystemId((String) null); result.setOutputStream(stream); mustClose = false; } /** * Set the destination of the serialized output, as a File. *

*

Calling this method has the side-effect of setting the current OutputWriter * and OutputStream to null.

* * @param file the File to which the serialized XML output will be written. */ public void setOutputFile(File file) { result.setOutputStream(null); result.setWriter(null); result.setSystemId(file); mustClose = true; } /** * Serialize an XdmNode to the selected output destination using this serializer * * @param node The node to be serialized * @throws IllegalStateException if no outputStream, Writer, or File has been supplied as the * destination for the serialized output * @throws SaxonApiException if a serialization error or I/O error occurs * @since 9.3 */ public void serializeNode(XdmNode node) throws SaxonApiException { StreamResult res = result; if (res.getOutputStream() == null && res.getWriter() == null && res.getSystemId() == null) { throw new IllegalStateException("Either an outputStream, or a Writer, or a File must be supplied"); } serializeNodeToResult(node, res); } /** * Serialize an arbitrary XdmValue to the selected output destination using this serializer. The supplied * sequence is first wrapped in a document node according to the rules given in section 2 (Sequence Normalization) of the * XSLT/XQuery serialization specification; the resulting * document nodes is then serialized using the serialization parameters defined in this serializer. * * @param value The value to be serialized * @throws IllegalStateException if no outputStream, Writer, or File has been supplied as the * destination for the serialized output, or if no Processor is associated with the serializer * @throws SaxonApiException if a serialization error or I/O error occurs * @since 9.3 */ public void serializeXdmValue(XdmValue value) throws SaxonApiException { if (value instanceof XdmNode) { serializeNode((XdmNode) value); } else { if (config == null) { throw new IllegalStateException("The serializer is not associated with any s9api Processor (need to call setProcessor())"); } try { QueryResult.serializeSequence(Value.asIterator(value.getUnderlyingValue()), config, result, getOutputProperties()); } catch (XPathException e) { throw new SaxonApiException(e); } } } /** * Serialize an XdmNode to a string using this serializer * * @param node The node to be serialized * @throws SaxonApiException if a serialization error occurs * @return the serialized representation of the node as lexical XML * @since 9.3 */ public String serializeNodeToString(XdmNode node) throws SaxonApiException { StringWriter sw = new StringWriter(); StreamResult sr = new StreamResult(sw); serializeNodeToResult(node, sr); return sw.toString(); } private void serializeNodeToResult(XdmNode node, Result res) throws SaxonApiException { try { QueryResult.serialize(node.getUnderlyingNode(), res, getOutputProperties()); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Get an XMLStreamWriter that can be used for writing application-generated XML * to be output via this serializer. * * @return a newly constructed XMLStreamWriter that pipes events into this Serializer * @throws IllegalStateException if no Processor has been set for this Serializer * @throws SaxonApiException if any other failure occurs * @since 9.3 */ public StreamWriterToReceiver getXMLStreamWriter() throws SaxonApiException { if (config == null) { throw new IllegalStateException("This method is available only if a Processor has been set"); } Receiver r = getReceiver(config); r = new NamespaceReducer(r); return new StreamWriterToReceiver(r); } /** * Get the current output destination. * * @return an OutputStream, Writer, or File, depending on the previous calls to * {@link #setOutputStream}, {@link #setOutputWriter}, or {@link #setOutputFile}; or * null, if no output destination has been set up. */ public Object getOutputDestination() { if (result.getOutputStream() != null) { return result.getOutputStream(); } if (result.getWriter() != null) { return result.getWriter(); } String systemId = result.getSystemId(); if (systemId != null) { try { return new File(new URI(systemId)); } catch (URISyntaxException e) { return null; } } else { return null; } } /** * Return a receiver to which Saxon will send events. This method is provided * primarily for internal use, though it could also be called by user applications * wanting to make use of the Saxon serializer. * * @param config The Saxon configuration. This is an internal implementation object * held within the {@link Processor} * @return a receiver to which XML events will be sent */ public Receiver getReceiver(Configuration config) throws SaxonApiException { try { SerializerFactory sf = config.getSerializerFactory(); PipelineConfiguration pipe = config.makePipelineConfiguration(); Properties props = getOutputProperties(); Receiver target = sf.getReceiver(result, pipe, props); if (target.getSystemId() == null) { target.setSystemId(result.getSystemId()); } return target; } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Return a receiver to which Saxon will send events. This method is provided * primarily for internal use, though it could also be called by user applications * wanting to make use of the Saxon serializer. * * @param executable The Saxon Executable for the transformation or query. The serialization * properties defined in this Serializer are supplemented by properties that have been * defined in the query or stylesheet associated with the Executable. The properties defined * in this Serializer take precedence over those in the stylesheet or query. * @return a receiver to which XML events will be sent * @throws SaxonApiException if any failure occurs */ protected Receiver getReceiver(Executable executable) throws SaxonApiException { try { Configuration config = executable.getConfiguration(); SerializerFactory sf = config.getSerializerFactory(); PipelineConfiguration pipe = config.makePipelineConfiguration(); Properties baseProps = executable.getDefaultOutputProperties(); for (Map.Entry entry : properties.entrySet()) { QName name = entry.getKey().getQName(); ResultDocument.setSerializationProperty( baseProps, name.getNamespaceURI(), name.getLocalName(), entry.getValue(), null, true, config); } Receiver target = sf.getReceiver(result, pipe, baseProps, executable.getCharacterMapIndex()); if (target.getSystemId() == null) { target.setSystemId(result.getSystemId()); } return target; } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Create a Properties object holding the defined serialization properties. This * will be in the same format as JAXP interfaces such as * {@link javax.xml.transform.Transformer#getOutputProperties()} * * @return a newly-constructed Properties object holding the declared serialization properties */ protected Properties getOutputProperties() { Properties props = new Properties(); for (Property p : properties.keySet()) { String value = properties.get(p); props.setProperty(p.toString(), value); } return props; } /** * Get the JAXP StreamResult object representing the output destination * of this serializer */ protected Result getResult() { return result; } /** * Close any resources associated with this destination. Note that this does not * close any user-supplied OutputStream or Writer; those must be closed explicitly * by the calling application. */ public void close() throws SaxonApiException { if (mustClose) { // This relies on the fact that the SerializerFactory sets the OutputStream OutputStream stream = result.getOutputStream(); if (stream != null) { try { stream.close(); } catch (java.io.IOException err) { throw new SaxonApiException("Failed while closing output file", err); } } Writer writer = result.getWriter(); // Path not used, but there for safety if (writer != null) { try { writer.close(); } catch (java.io.IOException err) { throw new SaxonApiException("Failed while closing output file", err); } } } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/DocumentBuilder.java0000644000175000017500000006006011720456615025160 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.*; import net.sf.saxon.expr.EarlyEvaluationContext; import net.sf.saxon.expr.JPConverter; import net.sf.saxon.expr.parser.PathMap; import net.sf.saxon.lib.AugmentedSource; import net.sf.saxon.lib.ParseOptions; import net.sf.saxon.lib.Validation; import net.sf.saxon.om.NodeInfo; import net.sf.saxon.om.TreeModel; import net.sf.saxon.query.XQueryExpression; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.Whitespace; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import java.io.File; import java.net.URI; /** * A document builder holds properties controlling how a Saxon document tree should be built, and * provides methods to invoke the tree construction. *

*

This class has no public constructor. Users should construct a DocumentBuilder * by calling the factory method {@link net.sf.saxon.s9api.Processor#newDocumentBuilder()}.

*

*

All documents used in a single Saxon query, transformation, or validation episode must * be built with the same {@link Configuration}. However, there is no requirement that they * should use the same DocumentBuilder.

*

*

Sharing of a DocumentBuilder across multiple threads is not recommended. However, * in the current implementation sharing a DocumentBuilder (once initialized) will only * cause problems if a SchemaValidator is used.

* * @since 9.0 */ public class DocumentBuilder { private Configuration config; private SchemaValidator schemaValidator; private boolean dtdValidation; private boolean lineNumbering; private TreeModel treeModel = TreeModel.TINY_TREE; private WhitespaceStrippingPolicy whitespacePolicy; private URI baseURI; private XQueryExecutable projectionQuery; // TODO: combine the functionality of this class with that of XdmDestination /** * Create a DocumentBuilder. This is a protected constructor. Users should construct a DocumentBuilder * by calling the factory method {@link net.sf.saxon.s9api.Processor#newDocumentBuilder()}. * * @param config the Saxon configuration */ protected DocumentBuilder(Configuration config) { this.config = config; } /** * Set the tree model to be used for documents constructed using this DocumentBuilder. * By default, the TinyTree is used (irrespective of the TreeModel set in the underlying * Configuration). * * @param model typically one of the constants {@link net.sf.saxon.om.TreeModel#TINY_TREE}, * {@link TreeModel#TINY_TREE_CONDENSED}, or {@link TreeModel#LINKED_TREE}. It can also be * an external object model such as {@link net.sf.saxon.option.xom.XOMObjectModel} * @since 9.2 */ public void setTreeModel(TreeModel model) { this.treeModel = model; } /** * Get the tree model to be used for documents constructed using this DocumentBuilder. * By default, the TinyTree is used (irrespective of the TreeModel set in the underlying * Configuration). * * @return the tree model in use: typically one of the constants {@link net.sf.saxon.om.TreeModel#TINY_TREE}, * {@link net.sf.saxon.om.TreeModel#TINY_TREE_CONDENSED}, or {@link TreeModel#LINKED_TREE}. However, in principle * a user-defined tree model can be used. * @since 9.2 */ public TreeModel getTreeModel() { return treeModel; } /** * Say whether line numbering is to be enabled for documents constructed using this DocumentBuilder. * This has the effect that the line number in the original source document is maintained in the constructed * tree, for each element node (and only for elements). The line number in question is generally the line number * on which the closing ">" of the element start tag appears. *

*

By default, line numbers are not maintained.

*

*

Errors relating to document parsing and validation will generally contain line numbers whether or not * this option is set, because such errors are detected during document construction.

*

*

Line numbering is not available for all kinds of source: for example, * it is not available when loading from an existing DOM Document.

*

*

The resulting line numbers are accessible to applications using the * XPath extension function saxon:line-number() applied to a node, or using the * Java method {@link net.sf.saxon.om.NodeInfo#getLineNumber()}

*

*

Line numbers are maintained only for element nodes; the line number * returned for any other node will be that of the most recent element. For an element node, the * line number is generally that of the closing angle bracket at the end of the start tag * (this is what a SAX parser notifies)

* * @param option true if line numbers are to be maintained, false otherwise. */ public void setLineNumbering(boolean option) { lineNumbering = option; } /** * Ask whether line numbering is enabled for documents loaded using this * DocumentBuilder. *

*

By default, line numbering is disabled.

*

*

Line numbering is not available for all kinds of source: in particular, * it is not available when loading from an existing XmlDocument.

*

*

The resulting line numbers are accessible to applications using the * extension function saxon:line-number() applied to a node, or using the * Java method {@link net.sf.saxon.om.NodeInfo#getLineNumber()}

*

*

Line numbers are maintained only for element nodes; the line number * returned for any other node will be that of the most recent element. For an element node, the * line number is generally that of the closing angle bracket at the end of the start tag * (this is what a SAX parser notifies)

* * @return true if line numbering is enabled */ public boolean isLineNumbering() { return lineNumbering; } /** * Set the schemaValidator to be used. This determines whether schema validation is applied to an input * document and whether type annotations in a supplied document are retained. If no schemaValidator * is supplied, then schema validation does not take place. *

*

This option requires the schema-aware version of the Saxon product (Saxon-EE).

*

*

Since a SchemaValidator is serially reusable but not thread-safe, using this * method is not appropriate when the DocumentBuilder is shared between threads.

* * @param validator the SchemaValidator to be used */ public void setSchemaValidator(SchemaValidator validator) { schemaValidator = validator; } /** * Get the SchemaValidator used to validate documents loaded using this * DocumentBuilder. * * @return the SchemaValidator if one has been set; otherwise null. */ public SchemaValidator getSchemaValidator() { return schemaValidator; } /** * Set whether DTD validation should be applied to documents loaded using this * DocumentBuilder. *

*

By default, no DTD validation takes place.

* * @param option true if DTD validation is to be applied to the document */ public void setDTDValidation(boolean option) { dtdValidation = option; } /** * Ask whether DTD validation is to be applied to documents loaded using this DocumentBuilder * * @return true if DTD validation is to be applied */ public boolean isDTDValidation() { return dtdValidation; } /** * Set the whitespace stripping policy applied when loading a document * using this DocumentBuilder. *

*

By default, whitespace text nodes appearing in element-only content * are stripped, and all other whitespace text nodes are retained.

* * @param policy the policy for stripping whitespace-only text nodes from * source documents */ public void setWhitespaceStrippingPolicy(WhitespaceStrippingPolicy policy) { whitespacePolicy = policy; } /** * Get the white whitespace stripping policy applied when loading a document * using this DocumentBuilder. * * @return the policy for stripping whitespace-only text nodes */ public WhitespaceStrippingPolicy getWhitespaceStrippingPolicy() { return whitespacePolicy; } /** * Set the base URI of a document loaded using this DocumentBuilder. *

*

This is used for resolving any relative URIs appearing * within the document, for example in references to DTDs and external entities.

*

*

This information is required when the document is loaded from a source that does not * provide an intrinsic URI, notably when loading from a Stream or a DOMSource. The value is * ignored when loading from a source that does have an intrinsic base URI.

* * @param uri the base URI of documents loaded using this DocumentBuilder. This * must be an absolute URI. * @throws IllegalArgumentException if the baseURI supplied is not an absolute URI */ public void setBaseURI(URI uri) { if (!uri.isAbsolute()) { throw new IllegalArgumentException("Supplied base URI must be absolute"); } baseURI = uri; } /** * Get the base URI of documents loaded using this DocumentBuilder when no other URI is available. * * @return the base URI to be used, or null if no value has been set. */ public URI getBaseURI() { return baseURI; } /** * Set a compiled query to be used for implementing document projection. The effect of using * this option is that the tree constructed by the DocumentBuilder contains only those parts * of the source document that are needed to answer this query. Running this query against * the projected document should give the same results as against the raw document, but the * projected document typically occupies significantly less memory. It is permissible to run * other queries against the projected document, but unless they are carefully chosen, they * will give the wrong answer, because the document being used is different from the original. *

The query should be written to use the projected document as its initial context item. * For example, if the query is //ITEM[COLOR='blue'), then only ITEM * elements and their COLOR children will be retained in the projected document.

*

This facility is only available in Saxon-EE; if the facility is not available, * calling this method has no effect.

* @param query the compiled query used to control document projection * @since 9.3 */ public void setDocumentProjectionQuery(XQueryExecutable query) { this.projectionQuery = query; } /** * Get the compiled query to be used for implementing document projection. * @return the query set using {@link #setDocumentProjectionQuery} if this * has been called, or null otherwise * @since 9.3. In 9.4 the unused and undocumented first argument is removed. */ public XQueryExecutable getDocumentProjectionQuery() { return this.projectionQuery; } /** * Load an XML document, to create a tree representation of the document in memory. * * @param source A JAXP Source object identifying the source of the document. This can always be * a {@link javax.xml.transform.stream.StreamSource} or a {@link javax.xml.transform.sax.SAXSource}. * Some kinds of Source are consumed by this method, and should only be used once. *

*

If a SAXSource is supplied, the XMLReader held within the SAXSource may be modified (by setting * features and properties) to reflect the options selected on this DocumentBuilder.

*

An instance of {@link javax.xml.transform.dom.DOMSource} is accepted provided that the Saxon support * code for DOM (in saxon9-dom.jar) is on the classpath.

*

*

If the source is an instance of {@link net.sf.saxon.om.NodeInfo} then the subtree rooted at this node * will be copied (applying schema validation if requested) to create a new tree.

*

*

Saxon also accepts an instance of {@link javax.xml.transform.stax.StAXSource} or * {@link net.sf.saxon.pull.PullSource}, which can be used to supply a document that is to be parsed * using a StAX parser.

*

(9.2) This method no longer accepts an instance of {@link net.sf.saxon.lib.AugmentedSource}, because of * confusion over interactions between the properties of the AugmentedSource and the properties * of this DocumentBuilder.

* @return An XdmNode. This will be * the document node at the root of the tree of the resulting in-memory document. * @throws NullPointerException if the source argument is null * @throws IllegalArgumentException if the kind of source is not recognized * @throws SaxonApiException if any other failure occurs building the document, for example * a parsing error */ public XdmNode build(/*@Nullable*/ Source source) throws SaxonApiException { if (source == null) { throw new NullPointerException("source"); } if (source instanceof AugmentedSource) { throw new IllegalArgumentException("AugmentedSource not accepted"); } ParseOptions options = new ParseOptions(config.getParseOptions()); options.setDTDValidationMode(dtdValidation ? Validation.STRICT : Validation.STRIP); if (schemaValidator != null) { options.setSchemaValidationMode(schemaValidator.isLax() ? Validation.LAX : Validation.STRICT); if (schemaValidator.getDocumentElementName() != null) { options.setTopLevelElement(schemaValidator.getDocumentElementName().getStructuredQName()); } if (schemaValidator.getDocumentElementType() != null) { options.setTopLevelType(schemaValidator.getDocumentElementType()); } } if (treeModel != null) { options.setModel(treeModel); } if (whitespacePolicy != null) { int option = whitespacePolicy.ordinal(); if (option == Whitespace.XSLT) { options.setStripSpace(Whitespace.NONE); options.addFilter(whitespacePolicy.makeStripper()); } else { options.setStripSpace(option); } } options.setLineNumbering(lineNumbering); if (source.getSystemId() == null && baseURI != null) { source.setSystemId(baseURI.toString()); } if (projectionQuery != null) { XQueryExpression exp = projectionQuery.getUnderlyingCompiledQuery(); PathMap map = exp.getPathMap(); PathMap.PathMapRoot contextRoot = map.getContextDocumentRoot(); if (contextRoot != null) { if (contextRoot.hasUnknownDependencies()) { // No action (no document projection takes place) } else { options.addFilter(config.makeDocumentProjector(contextRoot)); } } else { // No action, query does not access the context item } } try { NodeInfo doc = config.buildDocument(source, options); return new XdmNode(doc); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Build a document from a supplied XML file * @param file the supplied file * @return the XdmNode representing the root of the document tree * @throws SaxonApiException if any failure occurs retrieving or parsing the document */ public XdmNode build(File file) throws SaxonApiException { return build(new StreamSource(file)); } /** * Get an {@link org.xml.sax.ContentHandler} that may be used to build the document programmatically. * @return a newly constructed {@link BuildingContentHandler}, which implements the ContentHandler * interface. If schema validation has been requested for this DocumentBuilder, then the document constructed * using the ContentHandler will be validated as it is written. *

Note that the returned ContentHandler expects namespace scopes to be indicated * explicitly by calls to {@link org.xml.sax.ContentHandler#startPrefixMapping} and * {@link org.xml.sax.ContentHandler#endPrefixMapping}.

*

If the stream of events supplied to the ContentHandler does not constitute * a well formed (and namespace-well-formed) document, the effect is undefined; Saxon may fail * to detect the error, and construct an unusable tree.

* @throws SaxonApiException if any failure occurs * @since 9.3 */ public BuildingContentHandler newBuildingContentHandler() throws SaxonApiException { PipelineConfiguration pipe = config.makePipelineConfiguration(); Builder builder = treeModel.makeBuilder(pipe); builder.setLineNumbering(lineNumbering); Receiver r = builder; r = new NamespaceReducer(r); if (schemaValidator != null) { r = schemaValidator.getReceiver(config); r.setPipelineConfiguration(pipe); if (r instanceof ProxyReceiver) { ((ProxyReceiver)r).setUnderlyingReceiver(builder); } } return new BuildingContentHandlerImpl(r, builder); } /** * Private implementation of BuildingContentHandler */ private static class BuildingContentHandlerImpl extends ReceivingContentHandler implements BuildingContentHandler { private Builder builder; public BuildingContentHandlerImpl(Receiver r, Builder b) { setReceiver(r); setPipelineConfiguration(r.getPipelineConfiguration()); this.builder = b; } public XdmNode getDocumentNode() throws SaxonApiException { return new XdmNode(builder.getCurrentRoot()); } } /** * Get an {@link javax.xml.stream.XMLStreamWriter} that may be used to build the document programmatically. * @return a newly constructed {@link BuildingStreamWriter}, which implements the XMLStreamWriter * interface. If schema validation has been requested for this DocumentBuilder, then the document constructed * using the XMLStreamWriter will be validated as it is written. *

If the stream of events supplied to the XMLStreamWriter does not constitute * a well formed (and namespace-well-formed) document, the effect is undefined; Saxon may fail * to detect the error, and construct an unusable tree.

* @throws SaxonApiException if any failure occurs * @since 9.3 */ public BuildingStreamWriterImpl newBuildingStreamWriter() throws SaxonApiException { PipelineConfiguration pipe = config.makePipelineConfiguration(); Builder builder = treeModel.makeBuilder(pipe); builder.setLineNumbering(lineNumbering); Receiver r = builder; r = new NamespaceReducer(r); if (schemaValidator != null) { r = schemaValidator.getReceiver(config); r.setPipelineConfiguration(pipe); if (r instanceof ProxyReceiver) { ((ProxyReceiver)r).setUnderlyingReceiver(builder); } } return new BuildingStreamWriterImpl(r, builder); } /** * Create a node by wrapping a recognized external node from a supported object model. * *

If the supplied object implements the {@link net.sf.saxon.om.NodeInfo} interface then it * will be wrapped as an XdmNode without copying and without change. The NodeInfo * must have been created using a {@link net.sf.saxon.Configuration} compatible * with the one used by this Processor (specifically, one that uses the same * {@link net.sf.saxon.om.NamePool})

* *

To wrap nodes from other object models, such as DOM, the support module for the external object * model must be on the class path and registered with the Saxon configuration. The support modules * for DOM, JDOM, DOM4J and XOM are registered automatically if they can be found on the classpath.

* *

It is best to avoid calling this method repeatedly to wrap different nodes in the same document. * Each such wrapper conceptually creates a new XDM tree instance with its own identity. Although the * memory is shared, operations that rely on node identity might not have the expected result. It is * best to create a single wrapper for the document node, and then to navigate to the other nodes in the * tree using S9API interfaces.

* * @param node the node in the external tree representation. Either an instance of * {@link net.sf.saxon.om.NodeInfo}, or an instances of a node in an external object model. * Nodes in other object models (such as DOM, JDOM, etc) are recognized only if * the support module for the external object model is known to the Configuration. * @return the supplied node wrapped as an XdmNode * @throws IllegalArgumentException if the type of object supplied is not recognized. This may be because * node was created using a different Saxon Processor, or because the required code for the external * object model is not on the class path */ public XdmNode wrap(Object node) throws IllegalArgumentException { if (node instanceof NodeInfo) { NodeInfo nodeInfo = (NodeInfo)node; if (nodeInfo.getConfiguration().isCompatible(config)) { return new XdmNode((NodeInfo)node); } else { throw new IllegalArgumentException("Supplied NodeInfo was created using a different Configuration"); } } else { try { JPConverter converter = JPConverter.allocate(node.getClass(), config); NodeInfo nodeInfo = (NodeInfo)converter.convert(node, new EarlyEvaluationContext(config, null)); return (XdmNode)XdmItem.wrapItem(nodeInfo); } catch (XPathException e) { throw new IllegalArgumentException(e.getMessage()); } } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/SAXDestination.java0000644000175000017500000000561111671711573024733 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.ContentHandlerProxy; import net.sf.saxon.event.Receiver; import org.xml.sax.ContentHandler; /** * This class represents a Destination (for example, the destination of the output of a transformation) * in which events representing the XML document are sent to a user-supplied SAX2 ContentHandler, as * if the ContentHandler were receiving the document directly from an XML parser. */ public class SAXDestination implements Destination { private ContentHandler contentHandler; /** * Create a SAXDestination, supplying a SAX ContentHandler to which * events will be routed * @param handler the SAX ContentHandler that is to receive the output. If the * ContentHandler is also a {@link org.xml.sax.ext.LexicalHandler} then it will also receive * notification of events such as comments. */ public SAXDestination(ContentHandler handler) { contentHandler = handler; } /** * Return a Receiver. Saxon calls this method to obtain a Receiver, to which it then sends * a sequence of events representing the content of an XML document. * * @param config The Saxon configuration. This is supplied so that the destination can * use information from the configuration (for example, a reference to the name pool) * to construct or configure the returned Receiver. * @return the Receiver to which events are to be sent. * @throws net.sf.saxon.s9api.SaxonApiException * if the Receiver cannot be created */ /*@NotNull*/ public Receiver getReceiver(Configuration config) throws SaxonApiException { ContentHandlerProxy chp = new ContentHandlerProxy(); chp.setUnderlyingContentHandler(contentHandler); chp.setPipelineConfiguration(config.makePipelineConfiguration()); return chp; } /** * Close the destination, allowing resources to be released. Saxon calls this method when * it has finished writing to the destination. */ public void close() throws SaxonApiException { // no action } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/XPathSelector.java0000644000175000017500000002310011671711573024614 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.om.Item; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.ValueRepresentation; import net.sf.saxon.sxpath.XPathDynamicContext; import net.sf.saxon.sxpath.XPathExpression; import net.sf.saxon.sxpath.XPathVariable; import net.sf.saxon.trans.XPathException; import net.sf.saxon.value.SequenceExtent; import javax.xml.transform.URIResolver; import java.util.ArrayList; import java.util.Iterator; import java.util.List; /** * An XPathSelector represents a compiled and loaded XPath expression ready for execution. * The XPathSelector holds details of the dynamic evaluation context for the XPath expression. */ @SuppressWarnings({"ForeachStatement"}) public class XPathSelector implements Iterable { private XPathExpression exp; private XPathDynamicContext dynamicContext; private List declaredVariables; // protected constructor protected XPathSelector(XPathExpression exp, ArrayList declaredVariables) { this.exp = exp; this.declaredVariables = declaredVariables; dynamicContext = exp.createDynamicContext(); } /** * Set the context item for evaluating the XPath expression. * This may be either a node or an atomic value. Most commonly it will be a document node, * which might be constructed using the {@link DocumentBuilder#build} method. * * @param item The context item for evaluating the expression. Must not be null. * @throws SaxonApiException if an error occurs, for example because the type * of item supplied does not match the required item type * */ public void setContextItem(XdmItem item) throws SaxonApiException { if (item == null) { throw new NullPointerException("contextItem"); } try { dynamicContext.setContextItem((Item)item.getUnderlyingValue()); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Get the context item used for evaluating the XPath expression. * This may be either a node or an atomic value. Most commonly it will be a document node, * which might be constructed using the Build method of the DocumentBuilder object. * * @return The context item for evaluating the expression, or null if no context item * has been set. */ public XdmItem getContextItem() { return XdmItem.wrapItem(dynamicContext.getContextItem()); } /** * Set the value of a variable * * @param name The name of the variable. This must match the name of a variable * that was declared to the XPathCompiler. No error occurs if the expression does not * actually reference a variable with this name. * @param value The value to be given to the variable. * @throws SaxonApiException if the variable has not been declared or if the type of the value * supplied does not conform to the required type that was specified when the variable was declared */ public void setVariable(QName name, XdmValue value) throws SaxonApiException { XPathVariable var = null; StructuredQName qn = name.getStructuredQName(); for (XPathVariable v : declaredVariables) { if (v.getVariableQName().equals(qn)) { var = v; break; } } if (var == null) { throw new SaxonApiException( new XPathException("Variable has not been declared: " + name)); } try { dynamicContext.setVariable(var, value.getUnderlyingValue()); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Set an object that will be used to resolve URIs used in * fn:doc() and related functions. * * @param resolver An object that implements the URIResolver interface, or null. * @since 9.4 */ public void setURIResolver(URIResolver resolver) { dynamicContext.setURIResolver(resolver); } /** * Get the URI resolver. * * @return the user-supplied URI resolver if there is one, or the * system-defined one otherwise * @since 9.4 */ public URIResolver getURIResolver() { return dynamicContext.getURIResolver(); } /** * Evaluate the expression, returning the result as an XdmValue (that is, * a sequence of nodes and/or atomic values). * *

Note: Although a singleton result may be represented as an XdmItem, there is * no guarantee that this will always be the case. If you know that the expression will return at * most one node or atomic value, it is best to use the evaluateSingle method, which * does guarantee that an XdmItem (or null) will be returned.

* * @return An XdmValue representing the results of the expression. * @throws SaxonApiException if a dynamic error occurs during the expression evaluation. */ public XdmValue evaluate() throws SaxonApiException { ValueRepresentation value; try { value = SequenceExtent.makeSequenceExtent(exp.iterate(dynamicContext)); } catch (XPathException e) { throw new SaxonApiException(e); } return XdmValue.wrap(value); } /** * Evaluate the XPath expression, returning the result as an XdmItem (that is, * a single node or atomic value). * * @return an XdmItem representing the result of the expression, or null if the expression * returns an empty sequence. If the expression returns a sequence of more than one item, * any items after the first are ignored. * @throws SaxonApiException if a dynamic error occurs during the expression evaluation. */ public XdmItem evaluateSingle() throws SaxonApiException { try { Item i = exp.evaluateSingle(dynamicContext); if (i == null) { return null; } return (XdmItem) XdmValue.wrap(i); } catch (XPathException e) { throw new SaxonApiException(e); } } /** * Evaluate the expression, returning the result as an Iterator (that is, * an iterator over a sequence of nodes and/or atomic values). * *

Because an XPathSelector is an {@link Iterable}, it is possible to * iterate over the result using a Java 5 "for each" expression, for example:

* *

     * XPathCompiler compiler = processor.newXPathCompiler();
     * XPathSelector seq = compiler.compile("1 to 20").load();
     * for (XdmItem item : seq) {
     *   System.err.println(item);
     * }
     * 

* * @return An iterator over the sequence that represents the results of the expression. * Each object in this sequence will be an instance of XdmItem. Note * that the expression may be evaluated lazily, which means that a successful response * from this method does not imply that the expression has executed successfully: failures * may be reported later while retrieving items from the iterator. * @throws SaxonApiUncheckedException * if a dynamic error occurs during XPath evaluation that * can be detected at this point. It is also possible that an SaxonApiUncheckedException will * be thrown by the hasNext() method of the returned iterator. */ public Iterator iterator() throws SaxonApiUncheckedException { try { return new XdmSequenceIterator(exp.iterate(dynamicContext)); } catch (XPathException e) { throw new SaxonApiUncheckedException(e); } } /** * Evaluate the XPath expression, returning the effective boolean value of the result. * * @return a boolean representing the effective boolean value of the result of evaluating * the expression, as defined by the rules for the fn:boolean() function. * @throws SaxonApiException if a dynamic error occurs during the expression evaluation, or if the result * of the expression is a value whose effective boolean value is not defined (for example, a date or a * sequence of three integers) * @since 9.1 */ public boolean effectiveBooleanValue() throws SaxonApiException { try { return exp.effectiveBooleanValue(dynamicContext); } catch (XPathException e) { throw new SaxonApiException(e); } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/OccurrenceIndicator.java0000644000175000017500000000716611671711573026032 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.expr.StaticProperty; import net.sf.saxon.value.Cardinality; /** * Represents one of the possible occurrence indicators in a SequenceType. The four standard values are * ONE (no occurrence indicator), ZERO_OR_ONE (?), ZERO_OR_MORE (*), ONE_OR_MORE (+). In addition the * value ZERO is supported: this is used only in the type empty-sequence() which matches an empty sequence * and nothing else. */ public enum OccurrenceIndicator { ZERO, ZERO_OR_ONE, ZERO_OR_MORE, ONE, ONE_OR_MORE; protected int getCardinality() { switch(this) { case ZERO: return StaticProperty.EMPTY; case ZERO_OR_ONE: return StaticProperty.ALLOWS_ZERO_OR_ONE; case ZERO_OR_MORE: return StaticProperty.ALLOWS_ZERO_OR_MORE; case ONE: return StaticProperty.ALLOWS_ONE; case ONE_OR_MORE: return StaticProperty.ALLOWS_ONE_OR_MORE; default: return StaticProperty.EMPTY; } } protected static OccurrenceIndicator getOccurrenceIndicator(int cardinality) { switch (cardinality) { case StaticProperty.EMPTY: return ZERO; case StaticProperty.ALLOWS_ZERO_OR_ONE: return ZERO_OR_ONE; case StaticProperty.ALLOWS_ZERO_OR_MORE: return ZERO_OR_MORE; case StaticProperty.ALLOWS_ONE: return ONE; case StaticProperty.ALLOWS_ONE_OR_MORE: return ONE_OR_MORE; default: return ZERO_OR_MORE; } } /** * Ask whether this occurrence indicator permits an empty sequence. * @return true if the occurrence indicator is one of {@link #ZERO}, {@link #ZERO_OR_ONE}, * or {@link #ZERO_OR_MORE} * @since 9.2 */ public boolean allowsZero() { return Cardinality.allowsZero(getCardinality()); } /** * Ask whether this occurrence indicator permits a sequence containing more than one item. * @return true if the occurrence indicator is one of {@link #ZERO_OR_MORE} or {@link #ONE_OR_MORE} * @since 9.2 */ public boolean allowsMany() { return Cardinality.allowsMany(getCardinality()); } /** * Ask whether one occurrence indicator subsumes another. Specifically, * A.subsumes(B) is true if every sequence that satisfies the occurrence * indicator B also satisfies the occurrence indicator A. * @param other The other occurrence indicator * @return true if this occurrence indicator subsumes the other occurrence indicator * @since 9.1 */ public boolean subsumes(/*@NotNull*/ OccurrenceIndicator other) { return Cardinality.subsumes(getCardinality(), other.getCardinality()); } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/SchemaValidator.java0000644000175000017500000003445011671711573025147 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.Configuration; import net.sf.saxon.event.PipelineConfiguration; import net.sf.saxon.event.Receiver; import net.sf.saxon.event.Sender; import net.sf.saxon.event.Sink; import net.sf.saxon.lib.FeatureKeys; import net.sf.saxon.lib.ParseOptions; import net.sf.saxon.lib.Validation; import net.sf.saxon.trans.XPathException; import net.sf.saxon.type.SchemaType; import net.sf.saxon.value.Whitespace; import javax.xml.transform.ErrorListener; import javax.xml.transform.Source; /** * A SchemaValidator is an object that is used for validating instance documents against a schema. * The schema consists of the collection of schema components that are available within the schema * cache maintained by the SchemaManager, together with any additional schema components located * during the course of validation by means of an xsl:schemaLocation or xsi:noNamespaceSchemaLocation * attribute within the instance document. * *

If validation fails, an exception is thrown. If validation succeeds, the validated document * can optionally be written to a specified destination. This will be a copy of the original document, * augmented with default values for absent elements and attributes, and carrying type annotations * derived from the schema processing. Expansion of defaults can be suppressed by means of the method * {@link #setExpandAttributeDefaults(boolean)}.

* *

A SchemaValidator is serially resuable but not thread-safe. That is, it should normally * be used in the thread where it is created, but it can be used more than once, to validate multiple * input documents.

* *

A SchemaValidator is a Destination, which allows it to receive the output of a * query or transformation to be validated.

* *

Saxon does not deliver the full PSVI as described in the XML schema specifications, * only the subset of the PSVI properties featured in the XDM data model.

* */ public class SchemaValidator implements Destination { private Configuration config; private boolean lax; private ErrorListener errorListener; /*@Nullable*/ private Destination destination; private QName documentElementName; private SchemaType documentElementType; private boolean expandAttributeDefaults = true; private boolean useXsiSchemaLocation; // private Controller controller; // TODO: reinstate the saxon:param mechanism for parameterizing schema validation. protected SchemaValidator(Configuration config) { this.config = config; this.useXsiSchemaLocation = (Boolean) config.getConfigurationProperty( FeatureKeys.USE_XSI_SCHEMA_LOCATION); } /** * The validation mode may be either strict or lax. The default is strict; this method may be called * to indicate that lax validation is required. With strict validation, validation fails if no element * declaration can be located for the outermost element. With lax validation, the absence of an * element declaration results in the content being considered valid. * @param lax true if validation is to be lax, false if it is to be strict */ public void setLax(boolean lax) { this.lax = lax; } /** * Ask whether validation is to be in lax mode. * @return true if validation is to be in lax mode, false if it is to be in strict mode. */ public boolean isLax() { return lax; } /** * Set the ErrorListener to be used while validating instance documents. * @param listener The error listener to be used. This is notified of all errors detected during the * validation episode. */ public void setErrorListener(ErrorListener listener) { this.errorListener = listener; } /** * Get the ErrorListener being used while validating instance documents * @return listener The error listener in use. This is notified of all errors detected during the * validation episode. Returns null if no user-supplied ErrorListener has been set. */ public ErrorListener getErrorListener() { return errorListener; } /** * Say whether the schema processor is to take account of any xsi:schemaLocation and * xsi:noNamespaceSchemaLocation attributes encountered while validating an instance document * @param recognize true if these two attributes are to be recognized; false if they are to * be ignored. Default is true. */ public void setUseXsiSchemaLocation(boolean recognize) { useXsiSchemaLocation = recognize; } /** * Ask whether the schema processor is to take account of any xsi:schemaLocation and * xsi:noNamespaceSchemaLocation attributes encountered while validating an instance document * @return true if these two attributes are to be recognized; false if they are to * be ignored. Default is true. */ public boolean isUseXsiSchemaLocation() { return useXsiSchemaLocation; } /** * Set the Destination to receive the validated document. If no destination is supplied, the * validated document is discarded. * @param destination the destination to receive the validated document */ public void setDestination(/*@Nullable*/ Destination destination) { this.destination = destination; } /** * Get the Destination that will receive the validated document. Return null if no destination * has been set. * @return the destination to receive the validated document, or null if none has been supplied */ /*@Nullable*/ public Destination getDestination() { return destination; } /** * Set the name of the required top-level element of the document to be validated (that is, the * name of the outermost element of the document). If no value is supplied, there is no constraint * on the required element name * @param name the name of the document element, as a QName; or null to remove a previously-specified * value. */ public void setDocumentElementName(QName name) { documentElementName = name; } /** * Get the name of the required top-level element of the document to be validated. * @return the name of the required document element, or null if no value has been set. */ public QName getDocumentElementName() { return documentElementName; } /** * Set the name of the required type of the top-level element of the document to be validated. * If no value is supplied, there is no constraint on the required type * @param name the name of the type of the document element, as a QName; * or null to remove a previously-specified value. This must be the name of a type in the * schema (typically but not necessarily a complex type). * @throws SaxonApiException if there is no known type with this name */ public void setDocumentElementTypeName(QName name) throws SaxonApiException { int fp = config.getNamePool().allocate( "", name.getNamespaceURI(), name.getLocalName()); documentElementType = config.getSchemaType(fp); if (documentElementType == null) { throw new SaxonApiException("Unknown type " + name.getClarkName()); } } /** * Get the name of the required type of the top-level element of the document to be validated. * @return the name of the required type of the document element, or null if no value has been set. */ public QName getDocumentElementTypeName() { if (documentElementType == null) { return null; } else { int fp = documentElementType.getFingerprint(); return new QName(config.getNamePool().getStructuredQName(fp)); } } /** * Get the schema type against which the document element is to be validated * @return the schema type */ protected SchemaType getDocumentElementType() { return documentElementType; } /** * Set whether attribute defaults defined in a schema are to be expanded or not * (by default, fixed and default attribute values are expanded, that is, they are inserted * into the document during validation as if they were present in the instance being validated) * @param expand true if defaults are to be expanded, false if not */ public void setExpandAttributeDefaults(boolean expand) { expandAttributeDefaults = expand; } /** * Ask whether attribute defaults defined in a schema are to be expanded or not * (by default, fixed and default attribute values are expanded, that is, they are inserted * into the document during validation as if they were present in the instance being validated) * @return true if defaults are to be expanded, false if not */ public boolean isExpandAttributeDefaults() { return expandAttributeDefaults; } // /** // * Set the value of a schema parameter (a parameter defined in the schema using // * the saxon:param extension) // * @param name the name of the schema parameter, as a QName // * @param value the value of the schema parameter, or null to clear a previously set value // */ // // public void setParameter(QName name, XdmValue value) { // if (controller == null) { // controller = new Controller(config); // } // controller.setParameter(name.getStructuredQName(), // (value == null ? null : value.getUnderlyingValue())); // } // /** // * Get the value that has been set for a schema parameter (a parameter defined in the schema using // * the saxon:param extension) // * @param name the parameter whose name is required // * @return the value that has been set for the parameter, or null if no value has been set // */ // // public XdmValue getParameter(QName name) { // if (controller == null) { // return null; // } // Object oval = controller.getParameter(name.getClarkName()); // if (oval == null) { // return null; // } // if (oval instanceof ValueRepresentation) { // return XdmValue.wrap((ValueRepresentation)oval); // } // throw new IllegalStateException(oval.getClass().getName()); // } /** * Validate an instance document supplied as a Source object * @param source the instance document to be validated. The call getSystemId() applied to * this source object must return the base URI used for dereferencing any xsi:schemaLocation * or xsi:noNamespaceSchemaLocation attributes * @throws SaxonApiException if the source document is found to be invalid */ public void validate(Source source) throws SaxonApiException { Receiver receiver = getReceiver(config, source.getSystemId()); try { ParseOptions options = new ParseOptions(); options.setContinueAfterValidationErrors(true); Sender.send(source, receiver, options); if (destination != null) { destination.close(); } } catch (XPathException e) { throw new SaxonApiException(e); } } public Receiver getReceiver(Configuration config) throws SaxonApiException { return getReceiver(config, null); } private Receiver getReceiver(Configuration config, /*@Nullable*/ String systemId) throws SaxonApiException { PipelineConfiguration pipe = config.makePipelineConfiguration(); pipe.setExpandAttributeDefaults(expandAttributeDefaults); pipe.setUseXsiSchemaLocation(useXsiSchemaLocation); pipe.setRecoverFromValidationErrors(true); pipe.getParseOptions().setCheckEntityReferences(true); // if (controller != null) { // pipe.setController(controller); // //Executable exec = config.obtainSchemaExecutable(); // //controller.setExecutable(exec); // try { // controller.defineGlobalParameters(); // controller.getBindery().allocateGlobals(config.makeSlotManager()); // } catch (XPathException e) { // throw new SaxonApiException(e); // } // } Receiver output = (destination == null ? new Sink(pipe) : destination.getReceiver(config)); output.setPipelineConfiguration(pipe); int topLevelElement = -1; if (documentElementName != null) { topLevelElement = config.getNamePool().allocate( "", documentElementName.getNamespaceURI(), documentElementName.getLocalName()); } Receiver receiver = config.getDocumentValidator( output, systemId, (lax ? Validation.LAX : Validation.STRICT), Whitespace.NONE, documentElementType, topLevelElement); if (errorListener != null) { pipe.setErrorListener(errorListener); } return receiver; } /** * Close the destination, allowing resources to be released. Saxon calls this method when * it has finished writing to the destination. */ public void close() throws SaxonApiException { if (destination != null) { destination.close(); destination = null; } } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/Axis.java0000644000175000017500000000366511671711573023011 0ustar mathieumathieupackage net.sf.saxon.s9api; /** * This is an enumeration class containaing constants representing the thirteen XPath axes */ public enum Axis { ANCESTOR (net.sf.saxon.om.Axis.ANCESTOR), ANCESTOR_OR_SELF (net.sf.saxon.om.Axis.ANCESTOR_OR_SELF), ATTRIBUTE (net.sf.saxon.om.Axis.ATTRIBUTE), CHILD (net.sf.saxon.om.Axis.CHILD), DESCENDANT (net.sf.saxon.om.Axis.DESCENDANT), DESCENDANT_OR_SELF (net.sf.saxon.om.Axis.DESCENDANT_OR_SELF), FOLLOWING (net.sf.saxon.om.Axis.FOLLOWING), FOLLOWING_SIBLING (net.sf.saxon.om.Axis.FOLLOWING_SIBLING), PARENT (net.sf.saxon.om.Axis.PARENT), PRECEDING (net.sf.saxon.om.Axis.PRECEDING), PRECEDING_SIBLING (net.sf.saxon.om.Axis.PRECEDING_SIBLING), SELF (net.sf.saxon.om.Axis.SELF), NAMESPACE (net.sf.saxon.om.Axis.NAMESPACE); private byte number; /** * Create an Axis * @param number the internal axis number as defined in class {@link net.sf.saxon.om.Axis} */ private Axis(byte number) { this.number = number; } /** * Get the axis number, as defined in class {@link net.sf.saxon.om.Axis} * @return the axis number */ public byte getAxisNumber() { return number; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/s9api/ConstructedItemType.java0000644000175000017500000000762711671711573026065 0ustar mathieumathieupackage net.sf.saxon.s9api; import net.sf.saxon.lib.ConversionRules; import net.sf.saxon.om.Item; import net.sf.saxon.type.TypeHierarchy; /** * An item type constructed by the ItemTypeFactory (as distinct from one that is predefined) * * This class is not user-visible. */ class ConstructedItemType extends ItemType { private net.sf.saxon.type.ItemType underlyingType; private Processor processor; /** * Protected constructor * @param underlyingType the Saxon internal item type. Must not be null. * @param processor The s9api processor Must not be null */ protected ConstructedItemType(/*@Nullable*/ net.sf.saxon.type.ItemType underlyingType, Processor processor) { if (processor == null) { throw new NullPointerException("processor"); } if (underlyingType == null) { throw new NullPointerException("underlyingType"); } this.processor = processor; this.underlyingType = underlyingType; } /** * Get the conversion rules implemented by this type. The conversion rules reflect variations * between different versions of the W3C specifications, for example XSD 1.1 allows "+INF" as * a lexical representation of xs:double, while XSD 1.0 does not. * @return the conversion rules */ public ConversionRules getConversionRules() { return processor.getUnderlyingConfiguration().getConversionRules(); } /** * Determine whether this item type matches a given item. * * @param item the item to be tested against this item type * @return true if the item matches this item type, false if it does not match. */ public boolean matches(XdmItem item) { return underlyingType.matchesItem( (Item)item.getUnderlyingValue(), false, processor.getUnderlyingConfiguration()); } /** * Determine whether this ItemType subsumes another ItemType. Specifically, * A.subsumes(B) is true if every value that matches the ItemType B also matches * the ItemType A. * @param other the other ItemType * @return true if this ItemType subsumes the other ItemType. This includes the case where A and B * represent the same ItemType. * @since 9.1 */ public boolean subsumes(ItemType other) { TypeHierarchy th = processor.getUnderlyingConfiguration().getTypeHierarchy(); return th.isSubType(other.getUnderlyingItemType(), underlyingType); } /** * Method to get the underlying Saxon implementation object * *

This gives access to Saxon methods that may change from one release to another.

* @return the underlying Saxon implementation object */ public net.sf.saxon.type.ItemType getUnderlyingItemType() { return underlyingType; } /** * Get the underlying Processor * @return the processor used to create this ItemType. This will be null if the ItemType is one of the three * static constant item types {@link #ANY_ITEM}, {@link #ANY_NODE}, or {@link #ANY_ATOMIC_VALUE} */ protected Processor getProcessor() { return processor; } } // // 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 Saxonica Limited. // Portions created by ___ are Copyright (C) ___. All rights reserved. // // Contributor(s): //saxonhe-9.4.0.7/src/main/java/net/sf/saxon/PreparedStylesheet.java0000644000175000017500000006774412017130755024674 0ustar mathieumathieupackage net.sf.saxon; import net.sf.saxon.event.*; import net.sf.saxon.expr.CollationMap; import net.sf.saxon.expr.instruct.Executable; import net.sf.saxon.expr.instruct.Template; import net.sf.saxon.expr.instruct.UserFunction; import net.sf.saxon.functions.ExecutableFunctionLibrary; import net.sf.saxon.functions.FunctionLibrary; import net.sf.saxon.functions.FunctionLibraryList; import net.sf.saxon.lib.AugmentedSource; import net.sf.saxon.lib.NamespaceConstant; import net.sf.saxon.lib.ParseOptions; import net.sf.saxon.lib.Validation; import net.sf.saxon.om.StructuredQName; import net.sf.saxon.om.StylesheetSpaceStrippingRule; import net.sf.saxon.style.*; import net.sf.saxon.trace.ExpressionPresenter; import net.sf.saxon.trans.CompilerInfo; import net.sf.saxon.trans.DecimalFormatManager; import net.sf.saxon.trans.RuleManager; import net.sf.saxon.trans.XPathException; import net.sf.saxon.tree.linked.DocumentImpl; import net.sf.saxon.tree.linked.LinkedTreeBuilder; import net.sf.saxon.value.DecimalValue; import net.sf.saxon.value.Whitespace; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import javax.xml.transform.*; import javax.xml.transform.sax.SAXSource; import java.io.Serializable; import java.io.StringReader; import java.net.URI; import java.net.URISyntaxException; import java.util.*; /** * This PreparedStylesheet class represents a Stylesheet that has been * prepared for execution (or "compiled"). *

* Note that the PreparedStylesheet object does not contain a reference to the source stylesheet * tree (rooted at an XSLStyleSheet object). This allows the source tree to be garbage-collected * when it is no longer required. */ public class PreparedStylesheet extends Executable implements Templates, Serializable { private CompilerInfo compilerInfo; private transient StyleNodeFactory nodeFactory; private int errorCount = 0; private HashMap nextStylesheetCache; // cache for stylesheets named as "saxon:next-in-chain" // definitions of decimal formats private DecimalFormatManager decimalFormatManager; // definitions of template rules (XSLT only) private RuleManager ruleManager; // index of named templates. private HashMap namedTemplateTable; // a boolean flag indicating whether the stylesheet makes any use of tunnel parameters private boolean usesTunnel = false; /** * Constructor - deliberately protected * @param config The Configuration set up by the TransformerFactory * @param info Compilation options */ protected PreparedStylesheet(Configuration config, CompilerInfo info) { super(config); nodeFactory = config.makeStyleNodeFactory(); nodeFactory.setXsltProcessorVersion(info.getXsltVersion()); //executable = new Executable(config); //executable.setStyleNodeFactory(nodeFactory); RuleManager rm = new RuleManager(); rm.setRecoveryPolicy(info.getRecoveryPolicy()); setRuleManager(rm); setHostLanguage(Configuration.XSLT, info.getXsltVersion().equals(DecimalValue.THREE)); setCollationMap(new CollationMap(config.getCollationMap())); setSchemaAware(info.isSchemaAware()); compilerInfo = info; if (compilerInfo.getErrorListener() == null) { compilerInfo.setErrorListener(config.getErrorListener()); } } /** * Factory method to make a PreparedStylesheet * @param source the source of this principal stylesheet module * @param config the Saxon configuration * @param info compile-time options for this stylesheet compilation * @return the prepared stylesheet * @throws javax.xml.transform.TransformerConfigurationException if there is a static error in the stylesheet */ public static PreparedStylesheet compile(Source source, Configuration config, CompilerInfo info) throws TransformerConfigurationException { PreparedStylesheet pss = new PreparedStylesheet(config, info); pss.prepare(source); return pss; } /** * Make a Transformer from this Templates object. * @return the new Transformer (always a Controller) * @see net.sf.saxon.Controller */ public Transformer newTransformer() { Controller c = new Controller(getConfiguration(), this); c.setPreparedStylesheet(this); if (compilerInfo.getDefaultInitialTemplate() != null) { try { c.setInitialTemplate(compilerInfo.getDefaultInitialTemplate().getClarkName()); } catch (XPathException err) { // ignore error if there is no template with this name } } if (compilerInfo.getDefaultInitialMode() != null) { c.setInitialMode(compilerInfo.getDefaultInitialMode().getClarkName()); } return c; } /** * Set the configuration in which this stylesheet is compiled. * Intended for internal use. * @param config the configuration to be used. */ public void setConfiguration(Configuration config) { super.setConfiguration(config); this.compilerInfo = config.getDefaultXsltCompilerInfo(); } /** * Get the StyleNodeFactory in use. The StyleNodeFactory determines which subclass of StyleElement * to use for each element node in the stylesheet tree. * @return the StyleNodeFactory */ public StyleNodeFactory getStyleNodeFactory() { return nodeFactory; } /** * Set the DecimalFormatManager which handles decimal-format definitions * @param dfm the DecimalFormatManager containing the named xsl:decimal-format definitions */ public void setDecimalFormatManager(DecimalFormatManager dfm) { decimalFormatManager = dfm; } /** * Get the DecimalFormatManager which handles decimal-format definitions * @return the DecimalFormatManager containing the named xsl:decimal-format definitions */ public DecimalFormatManager getDecimalFormatManager() { if (decimalFormatManager == null) { decimalFormatManager = new DecimalFormatManager(); } return decimalFormatManager; } /** * Say that the stylesheet uses tunnel parameters. (This information is used by the bytecode generator, * which avoids generating code to pass tunnel parameters on every apply-templates call if there are no * tunnel parameters anywhere in the stylesheet). */ public void setUsesTunnelParameters() { usesTunnel = true; } /** * Ask whether the stylesheet uses tunnel parameters. (Called by the bytecode generator). * @return true if the stylesheet uses tunnel parameters. */ public boolean usesTunnelParameters() { return usesTunnel; } /** * Prepare a stylesheet from a Source document * @param styleSource the source document containing the stylesheet * @throws TransformerConfigurationException * if compilation of the * stylesheet fails for any reason */ protected void prepare(Source styleSource) throws TransformerConfigurationException { DocumentImpl doc; try { doc = loadStylesheetModule(styleSource); setStylesheetDocument(doc); } catch (XPathException e) { try { compilerInfo.getErrorListener().fatalError(e); } catch (TransformerException e2) { // ignore an exception thrown by the error handler } if (errorCount == 0) { errorCount++; } } if (errorCount > 0) { throw new TransformerConfigurationException( "Failed to compile stylesheet. " + errorCount + (errorCount == 1 ? " error " : " errors ") + "detected."); } } /** * Build the tree representation of a stylesheet module * @param styleSource the source of the module * @return the root Document node of the tree containing the stylesheet * module * @throws XPathException if XML parsing or tree * construction fails */ public DocumentImpl loadStylesheetModule(Source styleSource) throws XPathException { StyleNodeFactory nodeFactory = getStyleNodeFactory(); PipelineConfiguration pipe = getConfiguration().makePipelineConfiguration(); LinkedTreeBuilder styleBuilder = new LinkedTreeBuilder(pipe); pipe.setURIResolver(compilerInfo.getURIResolver()); styleBuilder.setSystemId(styleSource.getSystemId()); styleBuilder.setNodeFactory(nodeFactory); styleBuilder.setLineNumbering(true); UseWhenFilter useWhenFilter = new UseWhenFilter(styleBuilder); StartTagBuffer startTagBuffer = new StartTagBuffer(useWhenFilter); useWhenFilter.setStartTagBuffer(startTagBuffer); StylesheetSpaceStrippingRule rule = new StylesheetSpaceStrippingRule(getConfiguration().getNamePool()); Stripper styleStripper = new Stripper(rule, startTagBuffer); CommentStripper commentStripper = new CommentStripper(styleStripper); // build the stylesheet document DocumentImpl doc; ParseOptions options; if (styleSource instanceof AugmentedSource) { options = ((AugmentedSource)styleSource).getParseOptions(); styleSource = ((AugmentedSource)styleSource).getContainedSource(); } else { options = new ParseOptions(); } options.setSchemaValidationMode(Validation.STRIP); options.setDTDValidationMode(Validation.STRIP); options.setLineNumbering(true); options.setStripSpace(Whitespace.NONE); if (options.getXMLReader() == null && Configuration.getPlatform().isJava()) { XMLReader styleParser = getConfiguration().getStyleParser(); options.setXMLReader(styleParser); Sender.send(styleSource, commentStripper, options); getConfiguration().reuseStyleParser(styleParser); } else { Sender.send(styleSource, commentStripper, options); } doc = (DocumentImpl)styleBuilder.getCurrentRoot(); styleBuilder.reset(); if (options.isPleaseCloseAfterUse()) { ParseOptions.close(styleSource); } return doc; } /** * Create a PreparedStylesheet from a supplied DocumentInfo * Note: the document must have been built using the StyleNodeFactory * @param doc the document containing the stylesheet module * @throws XPathException if the document supplied * is not a stylesheet */ protected void setStylesheetDocument(DocumentImpl doc) throws XPathException { DocumentImpl styleDoc = doc; // If top-level node is a literal result element, stitch it into a skeleton stylesheet StyleElement topnode = (StyleElement)styleDoc.getDocumentElement(); if (topnode instanceof LiteralResultElement) { styleDoc = ((LiteralResultElement)topnode).makeStylesheet(this); } if (!(styleDoc.getDocumentElement() instanceof XSLStylesheet)) { throw new XPathException( "Outermost element of stylesheet is not xsl:stylesheet or xsl:transform or literal result element"); } XSLStylesheet top = (XSLStylesheet)styleDoc.getDocumentElement(); if (compilerInfo.isVersionWarning() && top.getEffectiveVersion().compareTo(getStyleNodeFactory().getXsltProcessorVersion()) != 0) { try { TransformerException w = new TransformerException( "Running an XSLT " + top.getEffectiveVersion() + " stylesheet with an XSLT " + getStyleNodeFactory().getXsltProcessorVersion() + " processor"); w.setLocator(topnode); getConfiguration().getErrorListener().warning(w); } catch (TransformerException e) { throw XPathException.makeXPathException(e); } } if (getStyleNodeFactory().getXsltProcessorVersion().compareTo(DecimalValue.TWO) > 0) { // The condition is checked again later in non-open code, but we can give a better error message here getConfiguration().checkLicensedFeature(Configuration.LicenseFeature.PROFESSIONAL_EDITION, "XSLT 3.0"); } PrincipalStylesheetModule psm = new PrincipalStylesheetModule(top, 0); psm.setPreparedStylesheet(this); psm.setVersion(top.getAttributeValue("version")); psm.createFunctionLibrary(compilerInfo); // Preprocess the stylesheet, performing validation and preparing template definitions //executable.setLocationMap(psm.getLocationMap()); top.setPrincipalStylesheetModule(psm); try { psm.preprocess(); } catch (XPathException e) { Throwable e2 = e.getException(); if (e2 instanceof XPathException) { try { compilerInfo.getErrorListener().fatalError((XPathException)e2); } catch (TransformerException e3) { // ignore an error thrown by the ErrorListener } } throw e; } // Compile the stylesheet, retaining the resulting executable psm.compileStylesheet(); } /** * Set the RuleManager that handles template rules * * @param rm the RuleManager containing details of all the template rules */ public void setRuleManager(RuleManager rm) { ruleManager = rm; } /** * Get the RuleManager which handles template rules * * @return the RuleManager registered with setRuleManager */ public RuleManager getRuleManager() { return ruleManager; } /** * Get the named template with a given name. * * @param qName The template name * @return The template (of highest import precedence) with this name if there is one; * null if none is found. */ /*@Nullable*/ public Template getNamedTemplate(StructuredQName qName) { if (namedTemplateTable == null) { return null; } return namedTemplateTable.get(qName); } /** * Register the named template with a given name * @param templateName the name of a named XSLT template * @param template the template */ public void putNamedTemplate(StructuredQName templateName, Template template) { if (namedTemplateTable == null) { namedTemplateTable = new HashMap(32); } namedTemplateTable.put(templateName, template); } /** * Iterate over all the named templates defined in this Executable * @return an iterator, the items returned being of class {@link net.sf.saxon.expr.instruct.Template} */ public Iterator