Skip to content

Commits on Source 3

saxonhe (9.9.0.2+dfsg-1) unstable; urgency=medium
* New upstream release.
-- Eugene Zhukov <eugene@debian.org> Tue, 20 Nov 2018 10:00:00 +0200
saxonhe (9.9.0.1+dfsg-1) unstable; urgency=medium
* New upstream release.
......
......@@ -8,7 +8,7 @@ Description: Add pom.xml for building and packaging
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>net.sf.saxon</groupId>
+ <artifactId>Saxon-HE</artifactId>
+ <version>9.9.0.1</version>
+ <version>9.9.0.2</version>
+ <packaging>jar</packaging>
+ <name>Saxon-HE</name>
+ <description>The XSLT and XQuery Processor</description>
......
......@@ -115,7 +115,7 @@ import java.util.function.IntPredicate;
public class Configuration implements SourceResolver, NotationSet {
protected static Set<Feature> booleanFeatures = new HashSet<Feature>(40);
protected static Set<Feature> booleanFeatures = new HashSet<>(40);
private transient ApiProvider apiProcessor = null;
private transient CharacterSetFactory characterSetFactory;
......@@ -131,7 +131,7 @@ public class Configuration implements SourceResolver, NotationSet {
protected transient StaticQueryContext defaultStaticQueryContext;
private StaticQueryContextFactory staticQueryContextFactory = new StaticQueryContextFactory();
protected OptimizerOptions optimizerOptions = OptimizerOptions.FULL_HE_OPTIMIZATION;
private CompilerInfo defaultXsltCompilerInfo = makeCompilerInfo();
protected CompilerInfo defaultXsltCompilerInfo = makeCompilerInfo();
private String label = null;
......@@ -148,7 +148,7 @@ public class Configuration implements SourceResolver, NotationSet {
private IntSet enabledProperties = new IntHashSet(64);
private List<ExternalObjectModel> externalObjectModels = new ArrayList<ExternalObjectModel>(4);
private List<ExternalObjectModel> externalObjectModels = new ArrayList<>(4);
private DocumentPool globalDocumentPool = new DocumentPool();
private IntegratedFunctionLibrary integratedFunctionLibrary = new IntegratedFunctionLibrary();
......@@ -463,6 +463,21 @@ public class Configuration implements SourceResolver, NotationSet {
return (Configuration) theClass.newInstance();
}
/**
* Ask if Java is being run with assertions enabled (-ea option)
* @return true if the -ea option is set
*/
public static boolean isAssertionsEnabled() {
// Highly devious logic here. If assertions are enabled, the assertion is false, and a deliberate side-effect
// of evaluating the assertion is that assertsEnabled is set to true. If assertions are not enabled, the assert
// statement is not executed, so assertsEnabled is left as false.
boolean assertsEnabled = false;
//noinspection AssertWithSideEffects
assert assertsEnabled = true;
return assertsEnabled;
}
/**
* Read the configuration file an construct a new Configuration (the real one)
......@@ -2388,7 +2403,7 @@ public class Configuration implements SourceResolver, NotationSet {
* @throws XPathException if (for example) a dynamic error occurs while priming the queue
*/
public <F extends Item, T extends Item> SequenceIterator<T> getMultithreadedItemMappingIterator(
public <F extends Item<?>, T extends Item<?>> SequenceIterator<T> getMultithreadedItemMappingIterator(
SequenceIterator<F> base, ItemMappingFunction<F, T> action) throws XPathException {
return new ItemMappingIterator<>(base, action);
}
......@@ -3013,7 +3028,7 @@ public class Configuration implements SourceResolver, NotationSet {
* @param baseURI the base URI of the instruction requesting the reading of the schema
* @param schemaLocation the location of the schema to be read
* @param expected The expected targetNamespace of the schema being read, or null if there is no expectation
* @return the target namespace of the schema; null if there is no expectation
* @return the target namespace of the schema; null if no schema has been read
* @throws UnsupportedOperationException when called in the non-schema-aware version of the product
* @throws net.sf.saxon.type.SchemaException if the schema cannot be read
*/
......@@ -3588,6 +3603,25 @@ public class Configuration implements SourceResolver, NotationSet {
return si;
}
/**
* Get a factory function that can be used to wrap a SequenceIterator in a FocusTrackingIterator. This
* is called by the {@link Controller} to get a default factory function; the value can be overridden
* by the application using {@link Controller#setFocusTrackerFactory(java.util.function.Function)}.
* The {@link FocusTrackingIterator} that is created by the factory must be thread-safe if it is
* to be used for iterating over a sequence where the items might be processed asynchronously using
* <code>xsl:result-document</code>; for this reason this method is overridden for a Saxon-EE configuration.
* @param exec the executable; supplied so that the factory can be sensitive to whether calls on xsl:result-document
* are possible
* @param multithreaded set to true to get a factory suitable for creating focus tracking iterators for a
* multi-threaded xsl:for-each instruction
* @return a suitable factory function
*/
public java.util.function.Function<SequenceIterator<?>, FocusTrackingIterator<?>> getFocusTrackerFactory(
Executable exec, boolean multithreaded) {
return FocusTrackingIterator::new;
}
/**
* Check the streamability of a template rule
*/
......@@ -3596,6 +3630,17 @@ public class Configuration implements SourceResolver, NotationSet {
// no action in Saxon-HE
}
/**
* Ask whether a given node is a streamed node
* @param node the node in question
* @return true if the node is a node in a streamed document
*/
public boolean isStreamedNode(NodeInfo node) {
return false; // streaming needs Saxon-EE
// TODO: make this a property of a node (or of a TreeInfo)
}
/**
* Get the optimization options in use
* @return the configured optimization options
......@@ -3707,10 +3752,10 @@ public class Configuration implements SourceResolver, NotationSet {
* @throws XPathException if a failure occurs constructing the Closure
*/
public Sequence makeClosure(Expression expression, int ref, XPathContext context) throws XPathException {
public Sequence<?> makeClosure(Expression expression, int ref, XPathContext context) throws XPathException {
if (getBooleanProperty(Feature.EAGER_EVALUATION)) {
// Using eager evaluation can make for easier debugging
SequenceIterator<? extends Item> iter = expression.iterate(context);
SequenceIterator<?> iter = expression.iterate(context);
return iter.materialize();
}
......@@ -3732,7 +3777,7 @@ public class Configuration implements SourceResolver, NotationSet {
* @throws XPathException if evaluation of the expression fails
*/
public GroundedValue makeSequenceExtent(Expression expression, int ref, XPathContext context) throws XPathException {
public GroundedValue<?> makeSequenceExtent(Expression expression, int ref, XPathContext context) throws XPathException {
return expression.iterate(context).materialize();
}
......@@ -4348,6 +4393,7 @@ public class Configuration implements SourceResolver, NotationSet {
throw new IllegalArgumentException("Unrecognized configuration feature: " + name);
}
} else {
//noinspection unchecked
setConfigurationProperty(feature, value);
}
}
......@@ -5011,7 +5057,7 @@ public class Configuration implements SourceResolver, NotationSet {
}
protected Object instantiateClassName(String propertyName, Object value, Class requiredClass) {
protected Object instantiateClassName(String propertyName, Object value, Class<?> requiredClass) {
if (!(value instanceof String)) {
throw new IllegalArgumentException(
propertyName + " must be a String");
......@@ -5037,6 +5083,7 @@ public class Configuration implements SourceResolver, NotationSet {
booleanFeatures.add(Feature.ASSERTIONS_CAN_SEE_COMMENTS);
booleanFeatures.add(Feature.COMPILE_WITH_TRACING);
booleanFeatures.add(Feature.DEBUG_BYTE_CODE);
booleanFeatures.add(Feature.DISABLE_XSL_EVALUATE);
booleanFeatures.add(Feature.DISPLAY_BYTE_CODE);
booleanFeatures.add(Feature.DTD_VALIDATION);
booleanFeatures.add(Feature.EAGER_EVALUATION);
......
......@@ -20,7 +20,6 @@ import net.sf.saxon.expr.parser.Location;
import net.sf.saxon.expr.parser.PathMap;
import net.sf.saxon.expr.sort.GroupIterator;
import net.sf.saxon.functions.AccessorFn;
import net.sf.saxon.functions.IriToUri;
import net.sf.saxon.lib.*;
import net.sf.saxon.om.*;
import net.sf.saxon.regex.RegexIterator;
......@@ -37,13 +36,13 @@ import net.sf.saxon.type.Type;
import net.sf.saxon.type.Untyped;
import net.sf.saxon.value.DateTimeValue;
import net.sf.saxon.value.SequenceType;
import net.sf.saxon.z.IntHashMap;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.URIResolver;
import javax.xml.transform.sax.SAXSource;
import java.io.File;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
......@@ -87,7 +86,7 @@ public class Controller implements ContextOriginator {
private Configuration config;
protected Executable executable;
protected Item globalContextItem;
protected Item<?> globalContextItem;
private boolean globalContextItemPreset;
private Map<PackageData, Bindery> binderies;
private GlobalParameterSet globalParameters;
......@@ -100,12 +99,12 @@ public class Controller implements ContextOriginator {
private URIResolver userURIResolver;
protected Receiver principalResult;
protected String principalResultURI;
private String cookedPrincipalResultURI;
private UnparsedTextURIResolver unparsedTextResolver;
private String defaultCollectionURI;
protected UnfailingErrorListener errorListener;
private TreeModel treeModel = TreeModel.TINY_TREE;
private DocumentPool sourceDocumentPool;
private IntHashMap<Map<Long, KeyIndex>> localIndexes;
private HashMap<String, Object> userDataTable;
private NodeInfo lastRememberedNode = null;
private int lastRememberedNumber = -1;
......@@ -121,8 +120,9 @@ public class Controller implements ContextOriginator {
public final static String ANONYMOUS_PRINCIPAL_OUTPUT_URI = "dummy:/anonymous/principal/result";
private StylesheetCache stylesheetCache = null;
private java.util.function.Function<SequenceIterator, FocusIterator> focusTrackerFactory =
FocusTrackingIterator::new;
private Function<SequenceIterator<?>, FocusTrackingIterator<?>> focusTrackerFactory = FocusTrackingIterator::new;
private Function<SequenceIterator<?>, FocusTrackingIterator<?>> multiThreadedFocusTrackerFactory;
/**
* Create a Controller and initialise variables. Note: XSLT applications should
......@@ -177,6 +177,8 @@ public class Controller implements ContextOriginator {
public void reset() {
globalParameters = new GlobalParameterSet();
focusTrackerFactory = config.getFocusTrackerFactory(executable, false);
multiThreadedFocusTrackerFactory = config.getFocusTrackerFactory(executable, true);
standardURIResolver = config.getSystemURIResolver();
userURIResolver = config.getURIResolver();
unparsedTextResolver = config.getUnparsedTextURIResolver();
......@@ -223,6 +225,7 @@ public class Controller implements ContextOriginator {
lastRememberedNode = null;
lastRememberedNumber = -1;
stylesheetCache = null;
localIndexes = null;
if (!globalContextItemPreset) {
globalContextItem = null;
}
......@@ -248,7 +251,7 @@ public class Controller implements ContextOriginator {
* even if there is a default defined in the stylesheet or query.
*/
public Sequence getParameter(StructuredQName name) {
public Sequence<?> getParameter(StructuredQName name) {
return globalParameters.get(name);
}
......@@ -264,9 +267,10 @@ public class Controller implements ContextOriginator {
* against the required type.
*/
public GroundedValue getConvertedParameter(StructuredQName name, SequenceType requiredType, XPathContext context)
public GroundedValue<?> getConvertedParameter(StructuredQName name, SequenceType requiredType, XPathContext context)
throws XPathException {
GroundedValue val = globalParameters.convertParameterValue(name, requiredType, convertParameters, context);
GroundedValue<?> val =
globalParameters.convertParameterValue(name, requiredType, convertParameters, context);
if (val != null) {
// Check that any nodes belong to the right configuration
......@@ -338,31 +342,6 @@ public class Controller implements ContextOriginator {
return principalResultURI;
}
/**
* Get the base output URI after processing. The processing consists of (a) defaulting
* to the current user directory if no base URI is available and if the stylesheet is trusted,
* and (b) applying IRI-to-URI escaping
*
* @return the base output URI after processing.
*/
/*@Nullable*/
public String getCookedBaseOutputURI() { // TODO: no longer used
if (cookedPrincipalResultURI == null) {
String base = getBaseOutputURI();
if (base == null && config.getBooleanProperty(Feature.ALLOW_EXTERNAL_FUNCTIONS)) {
// if calling external functions is allowed, then the stylesheet is trusted, so
// we allow it to write to files relative to the current directory
base = new File(System.getProperty("user.dir")).toURI().toString();
}
if (base != null) {
base = IriToUri.iriToUri(base).toString();
}
cookedPrincipalResultURI = base;
}
return cookedPrincipalResultURI;
}
/**
* Get the principal result destination.
* <p>This method is intended for internal use only. It is typically called by Saxon during the course
......@@ -390,17 +369,6 @@ public class Controller implements ContextOriginator {
return new SequenceOutputter(pipe, size);
}
/**
* Accept a SequenceOutputter that is now available for reuse
*
* @param out the SequenceOutputter that is available for reuse
*/
public void reuseSequenceOutputter(SequenceOutputter out) {
SequenceOutputter reusableSequenceOutputter = out;
}
///////////////////////////////////////////////////////////////////////////////
/**
......@@ -568,7 +536,7 @@ public class Controller implements ContextOriginator {
* @return the Bindery (in which values of all variables for the requested package are held)
*/
public Bindery getBindery(PackageData packageData) {
public synchronized Bindery getBindery(PackageData packageData) {
Bindery b = binderies.get(packageData);
if (b == null) {
b = new Bindery(packageData);
......@@ -649,7 +617,7 @@ public class Controller implements ContextOriginator {
*/
/*@Nullable*/
public Item getGlobalContextItem() {
public Item<?> getGlobalContextItem() {
return globalContextItem;
// See W3C bug 5224, which points out that the rules for XQuery 1.0 weren't clearly defined
}
......@@ -1168,7 +1136,8 @@ public class Controller implements ContextOriginator {
* users (it is done automatically when transform() is invoked). However, it is available as a low-level API
* especially for use with XQuery.
*
* @param params the values of stylesheet parameters. This must include static parameters as well as non-static parameters.
* @param params the values of stylesheet parameters. Changed in 9.9.0.2 so this no longer includes
* static parameters (which are already available in the {@link PreparedStylesheet}).
* @throws XPathException if an error occurs, for example if a required parameter is not supplied.
*/
......@@ -1182,7 +1151,7 @@ public class Controller implements ContextOriginator {
// if parameters were supplied, set them up
try {
executable.checkAllRequiredParamsArePresent(params);
executable.checkSuppliedParameters(params);
} catch (XPathException e) {
if (!e.hasBeenReported()) {
getErrorListener().fatalError(e);
......@@ -1226,7 +1195,7 @@ public class Controller implements ContextOriginator {
* @return the value of the required property
*/
public Object getUserData(Object key, String name) {
public synchronized Object getUserData(Object key, String name) {
String keyValue = key.hashCode() + " " + name;
// System.err.println("getUserData " + name + " on object returning " + userDataTable.get(key));
return userDataTable.get(keyValue);
......@@ -1247,7 +1216,7 @@ public class Controller implements ContextOriginator {
* for the key is removed.
*/
public void setUserData(Object key, String name, /*@Nullable*/ Object data) {
public synchronized void setUserData(Object key, String name, /*@Nullable*/ Object data) {
// System.err.println("setUserData " + name + " on object to " + data);
String keyVal = key.hashCode() + " " + name;
if (data == null) {
......@@ -1257,6 +1226,24 @@ public class Controller implements ContextOriginator {
}
}
/**
* Get the table of local indexes supporting xsl:key (or implicit keys created
* by the optimizer). Indexes are held at Controller level (rather than being
* shared across transformations) if the key definition is dependent on local
* information, for example stylesheet parameters.
* @return the index of indexes. The master index is created if it does not
* already exist. The master index is a two-level index: the first level is indexed
* by the integer fingerprint of the key name; the second level is indexed by
* the document number (a long) for the specific document or temporary tree.
*/
public synchronized IntHashMap<Map<Long, KeyIndex>> getLocalIndexes() {
if (localIndexes == null) {
localIndexes = new IntHashMap<>();
}
return localIndexes;
}
/**
* Set the last remembered node, for node numbering purposes.
* <p>This method is strictly for internal use only.</p>
......@@ -1322,6 +1309,7 @@ public class Controller implements ContextOriginator {
((SAXSource) source).setXMLReader(null);
}
Builder sourceBuilder = makeBuilder();
sourceBuilder.setUseEventLocation(true);
if (sourceBuilder instanceof TinyBuilder) {
((TinyBuilder) sourceBuilder).setStatistics(Statistics.SOURCE_DOCUMENT_STATISTICS);
}
......@@ -1563,25 +1551,42 @@ public class Controller implements ContextOriginator {
* Get the factory function that is used to create new instances of FocusTrackingIterator.
* The standard function for instantiating a FocusTrackingIterator can be overridden to deliver
* one with extra diagnostic capability for use in debuggers
* @param multithreaded true if the focus tracker must be suitable for executing a multi-threaded
* xsl:for-each iteration
* @return a factory function that is used to create FocusTrackingIterator instances
*/
public Function<SequenceIterator, FocusIterator> getFocusTrackerFactory() {
return focusTrackerFactory;
public Function<SequenceIterator<?>, FocusTrackingIterator<?>> getFocusTrackerFactory(boolean multithreaded) {
return multithreaded && multiThreadedFocusTrackerFactory != null ?
multiThreadedFocusTrackerFactory :
focusTrackerFactory;
}
/**
* Set a factory function that will be used to create new instances of FocusTrackingIterator.
* The standard function for instantiating a FocusTrackingIterator can be overridden to deliver
* one with extra diagnostic capability for use in debuggers
* one with extra diagnostic capability for use in debuggers.
*
* @param focusTrackerFactory a factory function that is used to create FocusTrackingIterator instances
*/
public void setFocusTrackerFactory(Function<SequenceIterator, FocusIterator> focusTrackerFactory) {
public void setFocusTrackerFactory(Function<SequenceIterator<?>, FocusTrackingIterator<?>> focusTrackerFactory) {
this.focusTrackerFactory = focusTrackerFactory;
}
/**
* Set a factory function that will be used to create new instances of FocusTrackingIterator for
* multithreaded operation.
* The standard function for instantiating a FocusTrackingIterator can be overridden to deliver
* one with extra diagnostic capability for use in debuggers.
*
* @param focusTrackerFactory a factory function that is used to create FocusTrackingIterator instances
*/
public void setMultithreadedFocusTrackerFactory(Function<SequenceIterator<?>, FocusTrackingIterator<?>> focusTrackerFactory) {
this.multiThreadedFocusTrackerFactory = focusTrackerFactory;
}
/**
* Set the focus tracker factory function to a function that creates a memoizing focus tracker, which
* has the effect that all items read by the focus iterator are accessible to a debugger at any stage
......@@ -1590,16 +1595,19 @@ public class Controller implements ContextOriginator {
public void setMemoizingFocusTrackerFactory() {
setFocusTrackerFactory(base -> {
FocusTrackingIterator<?> fti;
if ((base.getProperties() & GROUNDED) == 0 &&
!(base instanceof GroupIterator) && !(base instanceof RegexIterator)) {
try {
return new FocusTrackingIterator(new MemoSequence(base).iterate());
MemoSequence<?> ms = new MemoSequence<>(base);
fti = FocusTrackingIterator.track(ms.iterate());
} catch (XPathException e) {
return new FocusTrackingIterator(base);
fti = FocusTrackingIterator.track(base);
}
} else {
return new FocusTrackingIterator(base);
fti = FocusTrackingIterator.track(base);
}
return fti;
});
}
......
......@@ -138,6 +138,44 @@ public class PreparedStylesheet extends Executable {
return compileTimeParams;
}
/**
* Check that all required parameters have been supplied. Also checks that the supplied
* parameters dynamically do not conflict with parameters supplied statically. Used in XSLT only.
*
* @param params the set of parameters that have been supplied dynamically to the transformer
* (null represents an empty set).
* @throws XPathException if there is a required parameter for which no value has been supplied
*/
@Override
public void checkSuppliedParameters(GlobalParameterSet params) throws XPathException {
for (Map.Entry<StructuredQName, GlobalParam> entry : getGlobalParameters().entrySet()) {
if (entry.getValue().isRequiredParam()) {
StructuredQName req = entry.getKey();
if (getCompileTimeParams().get(req) == null && (params == null || params.get(req) == null)) {
XPathException err = new XPathException("No value supplied for required parameter " +
req.getDisplayName());
err.setErrorCode(getHostLanguage() == Configuration.XQUERY ? "XPDY0002" : "XTDE0050");
throw err;
}
}
}
for (StructuredQName name : params.getKeys()) {
GlobalParam decl = getGlobalParameter(name);
if (decl != null && decl.isStatic()) {
throw new XPathException("Parameter $" + name.getDisplayName() +
" cannot be supplied dynamically because it is declared as static");
}
if (compileTimeParams.containsKey(name)) {
throw new XPathException("Parameter $" + name.getDisplayName() +
" cannot be supplied dynamically because a value was already supplied at compile time");
}
}
for (StructuredQName name : compileTimeParams.getKeys()) {
params.put(name, compileTimeParams.get(name));
}
}
@Override
public StylesheetPackage getTopLevelPackage() {
return (StylesheetPackage)super.getTopLevelPackage();
......
......@@ -7,6 +7,7 @@
package net.sf.saxon;
import net.sf.saxon.expr.instruct.Executable;
import net.sf.saxon.expr.instruct.GlobalContextRequirement;
import net.sf.saxon.expr.instruct.TerminationException;
import net.sf.saxon.lib.*;
......@@ -72,12 +73,9 @@ public class Transform {
* <p>This program applies the XSL style sheet in style-file to the source XML document in source-file.</p>
*
* @param args List of arguments supplied on operating system command line
* @throws java.lang.Exception Indicates that a compile-time or
* run-time error occurred
*/
public static void main(String args[])
throws java.lang.Exception {
public static void main(String args[]) {
// the real work is delegated to another routine so that it can be used in a subclass
new Transform().doTransform(args, "java net.sf.saxon.Transform");
}
......@@ -475,14 +473,19 @@ public class Transform {
value = options.getOptionValue("Tlevel");
if (value != null && traceListener instanceof AbstractTraceListener) {
if (value.equals("none")) {
switch (value) {
case "none":
((AbstractTraceListener) traceListener).setLevelOfDetail(0);
} else if (value.equals("low")) {
break;
case "low":
((AbstractTraceListener) traceListener).setLevelOfDetail(1);
} else if (value.equals("normal")) {
break;
case "normal":
((AbstractTraceListener) traceListener).setLevelOfDetail(2);
} else if (value.equals("high")) {
break;
case "high":
((AbstractTraceListener) traceListener).setLevelOfDetail(3);
break;
}
}
}
......@@ -499,7 +502,7 @@ public class Transform {
processor.setConfigurationProperty(Feature.TRACE_LISTENER, traceListener);
processor.setConfigurationProperty(Feature.LINE_NUMBERING, true);
compiler.getUnderlyingCompilerInfo().setCodeInjector(new TimingCodeInjector());
if (value.length() > 0) {
if (!value.isEmpty()) {
traceListener.setOutputDestination(
new StandardLogger(new File(value)));
}
......@@ -511,15 +514,20 @@ public class Transform {
traceDestination = config.getLogger();
}
} else {
if (value.equals("#err")) {
switch (value) {
case "#err":
traceDestination = new StandardLogger();
} else if (value.equals("#out")) {
break;
case "#out":
traceDestination = new StandardLogger(System.out);
} else if (value.equals("#null")) {
break;
case "#null":
traceDestination = null;
} else {
break;
default:
traceDestination = new StandardLogger(new File(value));
closeTraceDestination = true;
break;
}
}
......@@ -624,7 +632,7 @@ public class Transform {
CommandLineOptions.loadAdditionalSchemas(config, additionalSchemas);
}
List<Source> sources = new ArrayList<Source>();
List<Source> sources = new ArrayList<>();
if (sourceFileName != null) {
boolean useSAXSource = sourceParserName != null || dtdValidation;
wholeDirectory = CommandLineOptions.loadDocuments(sourceFileName, useURLs, processor, useSAXSource, sources);
......@@ -812,14 +820,9 @@ public class Transform {
} catch (SaxonApiException err) {
//err.printStackTrace();
quit(err.getMessage(), 2);
} catch (TransformerException err) {
//err.printStackTrace();
quit("Transformation failed: " + err.getMessage(), 2);
} catch (TransformerFactoryConfigurationError err) {
} catch (TransformerException | LicenseException | TransformerFactoryConfigurationError err) {
//err.printStackTrace();
quit("Transformation failed: " + err.getMessage(), 2);
} catch (LicenseException err) {
quit("Transformation failed: " + err.getMessage(), 2);
} catch (Exception err2) {
err2.printStackTrace();
quit("Fatal error during transformation: " + err2.getClass().getName() + ": " +
......@@ -1054,13 +1057,8 @@ public class Transform {
protected Xslt30Transformer newTransformer(
XsltExecutable sheet, CommandLineOptions options, Logger traceDestination) throws SaxonApiException {
final Xslt30Transformer transformer = sheet.load30();
final Map<QName, XdmValue> params = new HashMap<QName, XdmValue>();
options.setParams(processor, new CommandLineOptions.ParamSetter() {
public void setParam(QName qName, XdmValue value) {
params.put(qName, value);
}
});
transformer.setStylesheetParameters(params);
final Map<QName, XdmValue> params = new HashMap<>();
Executable exec = transformer.getUnderlyingController().getExecutable();
transformer.setTraceFunctionDestination(traceDestination);
String initialMode = options.getOptionValue("im");
if (initialMode != null) {
......
......@@ -13,10 +13,10 @@ package net.sf.saxon;
public final class Version {
private static final int[] STRUCTURED_VERSION = {9, 9, 0, 1};
private static final String VERSION = "9.9.0.1";
private static final String BUILD = "092715"; //mmddhh
private static final String RELEASE_DATE = "2018-09-27";
private static final int[] STRUCTURED_VERSION = {9, 9, 0, 2};
private static final String VERSION = "9.9.0.2";
private static final String BUILD = "110716"; //mmddhh
private static final String RELEASE_DATE = "2018-11-07";
private static final String MAJOR_RELEASE_DATE = "2018-09-27";
private Version() {
......
......@@ -75,16 +75,16 @@ public class DOMEnvelope implements ExternalObjectModel {
return XPathConstants.DOM_OBJECT_MODEL;
}
public PJConverter getPJConverter(Class targetClass) {
public PJConverter getPJConverter(Class<?> targetClass) {
if (NodeOverNodeInfo.class.isAssignableFrom(targetClass)) {
return new PJConverter() {
public Object convert(Sequence value, Class targetClass, XPathContext context) throws XPathException {
public Object convert(Sequence<?> value, Class<?> targetClass, XPathContext context) throws XPathException {
return DOMObjectModel.convertXPathValueToObject(value, targetClass);
}
};
} else if (NodeList.class.isAssignableFrom(targetClass)) {
return new PJConverter() {
public Object convert(Sequence value, Class targetClass, XPathContext context) throws XPathException {
public Object convert(Sequence<?> value, Class<?> targetClass, XPathContext context) throws XPathException {
return DOMObjectModel.convertXPathValueToObject(value, targetClass);
}
};
......@@ -97,7 +97,7 @@ public class DOMEnvelope implements ExternalObjectModel {
if (NodeOverNodeInfo.class.isAssignableFrom(sourceClass)) {
return new JPConverter() {
/*@Nullable*/
public Sequence convert(Object object, XPathContext context) {
public Sequence<?> convert(Object object, XPathContext context) {
return convertObjectToXPathValue(object);
}
......@@ -207,7 +207,7 @@ public class DOMEnvelope implements ExternalObjectModel {
* @return the value after conversion
*/
private Sequence convertObjectToXPathValue(Object object) {
private Sequence<?> convertObjectToXPathValue(Object object) {
if (object instanceof NodeList) {
// NodeList needs great care, because Xerces element nodes implement the NodeList interface,
// with the actual list being the children of the node in question. So we only recognize a
......
......@@ -107,16 +107,16 @@ public class DOMObjectModel extends TreeModel implements ExternalObjectModel {
* otherwise null
*/
public PJConverter getPJConverter(Class targetClass) {
public PJConverter getPJConverter(Class<?> targetClass) {
if (Node.class.isAssignableFrom(targetClass) && !NodeOverNodeInfo.class.isAssignableFrom(targetClass)) {
return new PJConverter() {
public Object convert(Sequence value, Class targetClass, XPathContext context) throws XPathException {
public Object convert(Sequence<?> value, Class<?> targetClass, XPathContext context) throws XPathException {
return convertXPathValueToObject(value, targetClass);
}
};
} else if (NodeList.class == targetClass) {
return new PJConverter() {
public Object convert(Sequence value, Class targetClass, XPathContext context) throws XPathException {
public Object convert(Sequence<?> value, Class<?> targetClass, XPathContext context) throws XPathException {
return convertXPathValueToObject(value, targetClass);
}
};
......@@ -129,7 +129,7 @@ public class DOMObjectModel extends TreeModel implements ExternalObjectModel {
public JPConverter getJPConverter(Class sourceClass, Configuration config) {
if (Node.class.isAssignableFrom(sourceClass) && !NodeOverNodeInfo.class.isAssignableFrom(sourceClass)) {
return new JPConverter() {
public Sequence convert(Object obj, XPathContext context) {
public Sequence<?> convert(Object obj, XPathContext context) {
return wrapOrUnwrapNode((Node) obj, context.getConfiguration());
}
......@@ -139,7 +139,7 @@ public class DOMObjectModel extends TreeModel implements ExternalObjectModel {
};
} else if (NodeList.class.isAssignableFrom(sourceClass)) {
return new JPConverter() {
public Sequence convert(Object obj, XPathContext context) {
public Sequence<?> convert(Object obj, XPathContext context) {
Configuration config = context.getConfiguration();
NodeList list = (NodeList) obj;
final int len = list.getLength();
......@@ -147,7 +147,7 @@ public class DOMObjectModel extends TreeModel implements ExternalObjectModel {
for (int i = 0; i < len; i++) {
nodes[i] = wrapOrUnwrapNode(list.item(i), config);
}
return new SequenceExtent(nodes);
return new SequenceExtent<>(nodes);
}
public ItemType getItemType() {
......@@ -160,7 +160,7 @@ public class DOMObjectModel extends TreeModel implements ExternalObjectModel {
};
} else if (DOMSource.class.isAssignableFrom(sourceClass)) {
return new JPConverter() {
public Sequence convert(Object obj, XPathContext context) {
public Sequence<?> convert(Object obj, XPathContext context) {
return unravel((DOMSource) obj, context.getConfiguration());
}
......@@ -170,7 +170,7 @@ public class DOMObjectModel extends TreeModel implements ExternalObjectModel {
};
} else if (DocumentWrapper.class == sourceClass) {
return new JPConverter() {
public Sequence convert(Object obj, XPathContext context) {
public Sequence<?> convert(Object obj, XPathContext context) {
return ((DocumentWrapper) obj).getRootNode();
}
......@@ -201,7 +201,7 @@ public class DOMObjectModel extends TreeModel implements ExternalObjectModel {
(node instanceof VirtualNode && ((VirtualNode) node).getRealNode() instanceof Node)) {
return new PJConverter() {
/*@Nullable*/
public Object convert(Sequence value, Class targetClass, XPathContext context) throws XPathException {
public Object convert(Sequence<?> value, Class<?> targetClass, XPathContext context) throws XPathException {
return convertXPathValueToObject(value, NodeList.class);
}
};
......@@ -383,7 +383,7 @@ public class DOMObjectModel extends TreeModel implements ExternalObjectModel {
* supplied value cannot be converted to the appropriate class
*/
public static Object convertXPathValueToObject(Sequence value, Class<?> target) throws XPathException {
public static Object convertXPathValueToObject(Sequence<?> value, Class<?> target) throws XPathException {
// We accept the object if (a) the target class is Node, Node[], or NodeList,
// or (b) the supplied object is a node, or sequence of nodes, that wrap DOM nodes,
// provided that the target class is Object or a collection class
......
......@@ -8,11 +8,14 @@
package net.sf.saxon.event;
import net.sf.saxon.Configuration;
import net.sf.saxon.expr.parser.Location;
import net.sf.saxon.om.NamePool;
import net.sf.saxon.om.NodeInfo;
import net.sf.saxon.om.NodeName;
import net.sf.saxon.trans.CommandLineOptions;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.tiny.TinyDocumentImpl;
import net.sf.saxon.type.SchemaType;
/**
* The abstract Builder class is responsible for taking a stream of SAX events
......@@ -59,6 +62,7 @@ public abstract class Builder implements Receiver {
protected String baseURI;
protected NodeInfo currentRoot;
protected boolean lineNumbering = false;
protected boolean useEventLocation = true;
protected boolean started = false;
protected boolean timing = false;
......@@ -116,6 +120,39 @@ public abstract class Builder implements Receiver {
return null;
}
/**
* Say that the system IDs of constructed nodes (especially element nodes) are to be
* taken from the system ID property of the {@link Location} object passed as a parameter to
* the {@link #startElement(NodeName, SchemaType, Location, int)} event. This property
* should be set to true when building a document from events originating with an XML parser,
* because the {@link Location} object in this case will have a system ID that changes
* as external entities are processed. The base URI of a node in this case is determined
* by the system ID, modified by any <code>xml:base</code> attributes. If the property
* is set to false, all nodes in the tree have the same system ID, this being supplied
* as the systemID property of the builder. This will typically be the static base URI
* of the instruction in the query or stylesheet that was used to construct the root node;
* in the case of <code>xsl:result-document</code>, it will be the absolutized value of the
* <code>href</code> attribute of the instruction.
* @param useEventLocation true if the system ID is to be taken from the Location parameter of
* each event. The default value is true.
*/
public void setUseEventLocation(boolean useEventLocation) {
this.useEventLocation = useEventLocation;
}
/**
* Ask whether the system IDs of constructed nodes (especially element nodes) are to be
* taken from the system ID property of the {@link Location} object passed as a parameter to
* the {@link #startElement(NodeName, SchemaType, Location, int)} event.
* @return true if the system ID is to be taken from the Location parameter of
* each event. The default value is true.
*/
public boolean isUseEventLocation() {
return useEventLocation;
}
/**
* 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.
......
......@@ -131,7 +131,7 @@ public class NamespaceReducer extends ProxyReceiver implements NamespaceResolver
if (isNeeded(ns)) {
addToStack(ns);
countStack[depth - 1]++;
nextReceiver.namespace(namespaceBindings, properties);
nextReceiver.namespace(ns, properties);
}
}
}
......
......@@ -9,16 +9,15 @@ package 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.ParseOptions;
import net.sf.saxon.lib.SchemaURIResolver;
import net.sf.saxon.lib.UnfailingErrorListener;
import net.sf.saxon.om.Item;
import javax.xml.transform.ErrorListener;
import javax.xml.transform.URIResolver;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
/**
* A PipelineConfiguration sets options that apply to all the operations in a pipeline.
......@@ -31,11 +30,10 @@ public class PipelineConfiguration {
private URIResolver uriResolver;
private SchemaURIResolver schemaURIResolver;
private Controller controller;
private Stack<Item> currentApplyStack;
private ParseOptions parseOptions;
private int hostLanguage = Configuration.XSLT;
private Map<String, Object> components;
private boolean locationIsCodeLocation = false;
private XPathContext context;
/**
* Create a PipelineConfiguration. Note: the normal way to create
......@@ -69,8 +67,7 @@ public class PipelineConfiguration {
if (p.components != null) {
components = new HashMap<>(p.components);
}
locationIsCodeLocation = p.locationIsCodeLocation;
currentApplyStack = null;
context = p.context;
}
/**
......@@ -244,39 +241,6 @@ public class PipelineConfiguration {
return controller;
}
/**
* Set the context item. Used only for diagnostics, to indicate
* what part of the source document is being processed. Maintained
* only by xsl:apply-templates
*
* @param item the context item
*/
public void pushCurrentAppliedItem(Item item) {
// TODO: this stack is only used by ValidatingFilter, and it's not clear that it's useful there.
if (currentApplyStack == null) {
currentApplyStack = new Stack<>();
}
currentApplyStack.push(item);
}
public void popCurrentAppliedItem() {
currentApplyStack.pop();
}
public Item peekCurrentAppliedItem() {
if (currentApplyStack != null && !currentApplyStack.isEmpty()) {
return currentApplyStack.peek();
} else {
return null;
}
}
public Stack<Item> getAppliedItemStack() {
return currentApplyStack;
}
/**
* Set the Controller associated with this pipelineConfiguration
*
......@@ -348,12 +312,25 @@ public class PipelineConfiguration {
}
}
public boolean isLocationIsCodeLocation() {
return locationIsCodeLocation;
/**
* Set the XPathContext. Used during validation, for diagnostics, to identify the source node that was
* being processed at the time a validation error in the result document was found
* @param context the XPath dynamic context.
*/
public void setXPathContext(XPathContext context) {
this.context = context;
}
public void setLocationIsCodeLocation(boolean locationIsCodeLocation) {
this.locationIsCodeLocation = locationIsCodeLocation;
/**
* Get the XPathContext. Used during validation, for diagnostics, to identify the source node that was
* being processed at the time a validation error in the result document was found
*
* @return the XPath dynamic context.
*/
public XPathContext getXPathContext() {
return context;
}
}
......
......@@ -93,7 +93,6 @@ public class RegularSequenceChecker extends ProxyReceiver {
static {
edge(State.Initial, "open", State.Open);
//edge(State.Open, "open", State.Open); // TODO: we're only allowing this because it happens...
edge(State.Open, "append", State.Open);
edge(State.Open, "text", State.Open);
edge(State.Open, "comment", State.Open);
......@@ -112,7 +111,7 @@ public class RegularSequenceChecker extends ProxyReceiver {
edge(State.Content, "endElement", State.Content); // or Open if the stack is empty
edge(State.Content, "endDocument", State.Open);
edge(State.Open, "close", State.Final);
edge(State.Final, "close", State.Final); // TODO: another concession to poor practice...
//edge(State.Final, "close", State.Final); // This was a concession to poor practice, but apparently no longer needed
}
private void transition(String event) {
......@@ -138,7 +137,8 @@ public class RegularSequenceChecker extends ProxyReceiver {
}
/**
* Append an arbitrary item (node or atomic value) to the output
* Append an arbitrary item (node or atomic value) to the output. In a regular sequence, append
* events occur only at the top level, that is, when the document / element stack is empty.
*
* @param item the item to be appended
* @param locationId the location of the calling instruction, for diagnostics
......@@ -154,8 +154,36 @@ public class RegularSequenceChecker extends ProxyReceiver {
}
/**
* Notify an attribute. Attributes are notified after the startElement event, and before any
* children. Namespaces and attributes may be intermingled.
* Notify an attribute. An attribute is either free-standing attribute, or a parented attribute. A free-standing
* attribute is one that occurs when the startElement / startDocument stack is empty; a parented attribute
* occurs between a startElement event and a startContent event.
* <p>
* All attributes must satisfy the following constraints:
* <ol>
* <li>The namespace prefix and URI must either both be present (non-zero-length) or both absent</li>
* <li>The prefix "xml" and the URI "http://www.w3.org/XML/1998/namespace"
* are allowed only in combination.</li>
* <li>The namespace URI "http://www.w3.org/2000/xmlns/" is not allowed.</li>
* <li>The namespace prefix "xmlns" is not allowed.</li>
* <li>The local name "xmlns" is not allowed in the absence of a namespace prefix and URI.</li>
* </ol>
* <p>
* For a parented attribute, the following additional constraints apply to the set of attributes between
* a startElement event and the next startContent event:
* <ol>
* <li>No two attributes may have the same (local-name, namespace URI) combination.</li>
* <li>No namespace prefix may be used in conjunction with more than one namespace URI.</li>
* <li>Every (namespace prefix, namespace URI) combination must correspond to an in-scope namespace:
* that is, unless the (prefix, URI) pair is ("", "") or ("xml", "http://www.w3.org/XML/1998/namespace"),
* it must be the subject of a {@link #namespace(NamespaceBindingSet, int)} event applicable to this
* element or to some parent element, that has not been cancelled by a namespace undeclaration on
* an inner element. If the namespace event appears on the same element as the attribute event then they
* may arrive in either order.</li>
* </ol>
* <p>
* These constraints are not currently enforced by this class.
* </p>
*
*
* @param nameCode The name of the attribute
* @param typeCode The type of the attribute
......@@ -175,11 +203,16 @@ public class RegularSequenceChecker extends ProxyReceiver {
}
/**
* Character data
* Character data (corresponding to a text node). For character data within content (that is, events occurring
* when the startDocument / startElement stack is non-empty), character data events will never be consecutive
* and will never be zero-length.
*/
public void characters(CharSequence chars, Location locationId, int properties) throws XPathException {
transition("text");
if (chars.length() == 0 && !stack.isEmpty()) {
throw new IllegalStateException("Zero-length text nodes not allowed within document/element content");
}
nextReceiver.characters(chars, locationId, properties);
}
......
......@@ -29,7 +29,7 @@ public class SequenceCopier {
* @throws XPathException if a failure occurs reading the input or writing the output
*/
public static void copySequence(SequenceIterator<? extends Item> in, Receiver out) throws XPathException {
public static void copySequence(SequenceIterator<?> in, Receiver out) throws XPathException {
out.open();
in.forEachOrFail(out::append);
out.close();
......
......@@ -39,7 +39,7 @@ import java.util.List;
public final class SequenceOutputter extends SequenceWriter {
private List<Item> list;
private List<Item<?>> list;
/**
......@@ -96,7 +96,7 @@ public final class SequenceOutputter extends SequenceWriter {
* @return the value (sequence of items) that have been written to this SequenceOutputter
*/
public Sequence<? extends Item> getSequence() {
public Sequence<?> getSequence() {
switch (list.size()) {
case 0:
return EmptySequence.getInstance();
......@@ -114,7 +114,7 @@ public final class SequenceOutputter extends SequenceWriter {
* @return an iterator over the items that have been written to this SequenceOutputter
*/
public SequenceIterator<Item> iterate() {
public SequenceIterator<Item<?>> iterate() {
if (list.isEmpty()) {
return EmptyIterator.emptyIterator();
} else {
......@@ -128,7 +128,7 @@ public final class SequenceOutputter extends SequenceWriter {
* @return the list of items that have been written to this SequenceOutputter
*/
public List<Item> getList() {
public List<Item<?>> getList() {
return list;
}
......
......@@ -145,7 +145,7 @@ public abstract class SequenceReceiver implements Receiver {
*/
protected void flatten(ArrayItem array, Location locationId, int copyNamespaces) throws XPathException {
for (Sequence<? extends Item> member : array.members()) {
for (Sequence<?> member : array.members()) {
member.iterate().forEachOrFail(it -> append(it, locationId, copyNamespaces));
}
}
......@@ -177,7 +177,7 @@ public abstract class SequenceReceiver implements Receiver {
} else {
NodeInfo node = (NodeInfo)item;
if (node instanceof Orphan && ((Orphan) node).isDisableOutputEscaping()) {
// see test case doe-0185 - needed for output buffered within try/catch // TODO: is this still used?
// see test case doe-0801, -2 -3 - needed for output buffered within try/catch, xsl:fork etc
characters(item.getStringValueCS(), locationId, ReceiverOptions.DISABLE_ESCAPING);
previousAtomic = false;
} else if (node.getNodeKind() == Type.DOCUMENT) {
......
......@@ -109,6 +109,7 @@ public abstract class SequenceWriter extends SequenceReceiver {
builder.setSystemId(systemId);
builder.setBaseURI(systemId);
builder.setTiming(false);
builder.setUseEventLocation(false);
NamespaceReducer reducer = new NamespaceReducer(builder);
......
......@@ -99,9 +99,9 @@ public class SignificantItemDetector extends ProxyReceiver {
if (((ArrayItem) item).isEmpty()) {
return true;
} else {
for (Sequence mem : ((ArrayItem) item).members()) {
for (Sequence<?> mem : ((ArrayItem) item).members()) {
try {
SequenceIterator memIter = mem.iterate();
SequenceIterator<?> memIter = mem.iterate();
Item it;
while ((it = memIter.next()) != null) {
if (isSignificant(it)) {
......
......@@ -754,7 +754,7 @@ public class StreamWriterToReceiver implements XMLStreamWriter {
public javax.xml.namespace.NamespaceContext getNamespaceContext() {
return new NamespaceContext() {
final NamespaceContext rootNamespaceContext = StreamWriterToReceiver.this.rootNamespaceContext;
final Map<String, String> bindings = new HashMap<String, String>();
final Map<String, String> bindings = new HashMap<>();
{
for (List<NamespaceBinding> list : setPrefixes) {
......@@ -781,16 +781,16 @@ public class StreamWriterToReceiver implements XMLStreamWriter {
return rootNamespaceContext.getPrefix(namespaceURI);
}
public Iterator getPrefixes(String namespaceURI) {
List<String> prefixes = new ArrayList<String>();
public Iterator<String> getPrefixes(String namespaceURI) {
List<String> prefixes = new ArrayList<>();
for (Map.Entry<String, String> entry : bindings.entrySet()) {
if (entry.getValue().equals(namespaceURI)) {
prefixes.add(entry.getKey());
}
}
Iterator<String> root = rootNamespaceContext.getPrefixes(namespaceURI);
Iterator root = rootNamespaceContext.getPrefixes(namespaceURI);
while (root.hasNext()) {
prefixes.add(root.next());
prefixes.add((String)root.next());
}
return prefixes.iterator();
}
......
......@@ -38,6 +38,7 @@ public class TransformerReceiver extends ProxyReceiver {
super(controller.makeBuilder());
this.controller = controller;
this.builder = (Builder) getNextReceiver();
this.builder.setUseEventLocation(false);
}
/**
......