![JAR search and dependency download from the Maven repository](/logo.png)
net.sf.saxon.style.XSLSourceDocument Maven / Gradle / Ivy
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2023 Saxonica Limited
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
package net.sf.saxon.style;
import net.sf.saxon.Configuration;
import net.sf.saxon.expr.Expression;
import net.sf.saxon.expr.Literal;
import net.sf.saxon.expr.accum.Accumulator;
import net.sf.saxon.expr.accum.AccumulatorRegistry;
import net.sf.saxon.expr.parser.ExpressionVisitor;
import net.sf.saxon.lib.ParseOptions;
import net.sf.saxon.lib.Validation;
import net.sf.saxon.om.*;
import net.sf.saxon.pattern.NodeKindTest;
import net.sf.saxon.str.StringView;
import net.sf.saxon.trans.SaxonErrorCode;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.value.Whitespace;
import java.util.HashSet;
import java.util.Set;
/**
* Handler for xsl:source-document element in XSLT 3.0 stylesheet.
*/
public class XSLSourceDocument extends StyleElement {
private Expression href = null;
private Set accumulators = new HashSet<>();
private boolean streaming = false;
private ParseOptions parseOptions;
/**
* Determine whether this node is an instruction.
*
* @return true - it is an instruction
*/
@Override
public boolean isInstruction() {
return true;
}
/**
* Determine whether this type of element is allowed to contain a sequence constructor
*
* @return true: yes, it may contain a sequence constructor
*/
@Override
protected boolean mayContainSequenceConstructor() {
return true;
}
@Override
protected boolean isWithinDeclaredStreamableConstruct() {
return true;
}
@Override
protected void prepareAttributes() {
parseOptions = getConfiguration().getParseOptions();
String hrefAtt = null;
String validationAtt = null;
String typeAtt = null;
String useAccumulatorsAtt = null;
for (AttributeInfo att : attributes()) {
NodeName attName = att.getNodeName();
StructuredQName name = attName.getStructuredQName();
String value = att.getValue();
String f = name.getClarkName();
if (f.equals("href")) {
hrefAtt = value;
href = makeAttributeValueTemplate(hrefAtt, att);
} else if (f.equals("validation")) {
validationAtt = Whitespace.trim(value);
} else if (f.equals("type")) {
typeAtt = Whitespace.trim(value);
} else if (f.equals("use-accumulators")) {
useAccumulatorsAtt = Whitespace.trim(value);
} else if (f.equals("streamable")) {
streaming = processStreamableAtt(value);
} else if (attName.hasURI(NamespaceUri.SAXON)) {
isExtensionAttributeAllowed(attName.getDisplayName());
String local = attName.getLocalPart();
switch (local) {
case "dtd-validation":
parseOptions = parseOptions.withDTDValidationMode(processBooleanAttribute(f, value) ? Validation.STRICT : Validation.SKIP);
break;
case "expand-attribute-defaults":
parseOptions = parseOptions.withExpandAttributeDefaults(processBooleanAttribute(f, value));
break;
case "line-numbering":
parseOptions = parseOptions.withLineNumbering(processBooleanAttribute(f, value));
break;
case "xinclude":
parseOptions = parseOptions.withXIncludeAware(processBooleanAttribute(f, value));
// } else if (local.equals("tree-model")) {
// List models = getConfiguration().getExternalObjectModels()
// parseOptions.setModel(processBooleanAttribute(f, value));
break;
case "validation-params":
// TODO
break;
case "strip-space":
switch (Whitespace.normalizeWhitespace(StringView.of(value)).toString()) {
case "#all":
parseOptions = parseOptions.withSpaceStrippingRule(AllElementsSpaceStrippingRule.getInstance());
break;
case "#none":
parseOptions = parseOptions.withSpaceStrippingRule(NoElementsSpaceStrippingRule.getInstance());
break;
case "#ignorable":
parseOptions = parseOptions.withSpaceStrippingRule(IgnorableSpaceStrippingRule.getInstance());
break;
case "#default":
parseOptions = parseOptions.withSpaceStrippingRule(null);
break;
default:
invalidAttribute("saxon:strip-space", "#all|#none|#ignorable|#default");
break;
}
break;
default:
checkUnknownAttribute(attName);
break;
}
} else {
checkUnknownAttribute(attName);
}
}
if (hrefAtt == null) {
reportAbsence("href");
}
if (validationAtt != null) {
int validation = validateValidationAttribute(validationAtt);
parseOptions = parseOptions.withSchemaValidationMode(validation);
}
if (typeAtt != null) {
if (!isSchemaAware()) {
compileError("The @type attribute is available only with a schema-aware XSLT processor", "XTSE1660");
}
parseOptions = parseOptions.withSchemaValidationMode(Validation.BY_TYPE);
parseOptions = parseOptions.withTopLevelType(getSchemaType(typeAtt));
}
if (typeAtt != null && validationAtt != null) {
compileError("The @validation and @type attributes are mutually exclusive", "XTSE1505");
}
if (useAccumulatorsAtt == null) {
useAccumulatorsAtt = "";
}
AccumulatorRegistry registry = getPrincipalStylesheetModule().getStylesheetPackage().getAccumulatorRegistry();
accumulators = registry.getUsedAccumulators(useAccumulatorsAtt, this);
}
@Override
public void validate(ComponentDeclaration decl) throws XPathException {
//checkParamComesFirst(false);
href = typeCheck("select", href);
if (!hasChildNodes()) {
issueWarning("An empty xsl:source-document instruction has no effect", SaxonErrorCode.SXWN9009);
}
}
/*@Nullable*/
@Override
public Expression compile(Compilation exec, ComponentDeclaration decl) throws XPathException {
Configuration config = getConfiguration();
if (parseOptions.getSpaceStrippingRule() == null) {
parseOptions = parseOptions.withSpaceStrippingRule(getPackageData().getSpaceStrippingRule());
}
parseOptions = parseOptions.withApplicableAccumulators(accumulators);
Expression action = compileSequenceConstructor(exec, decl, false);
if (action == null) {
// body of xsl:source-document is empty: it's a no-op.
return Literal.makeEmptySequence();
}
try {
ExpressionVisitor visitor = makeExpressionVisitor();
action = action.simplify();
action = action.typeCheck(visitor, config.makeContextItemStaticInfo(NodeKindTest.DOCUMENT, false));
return config.makeStreamInstruction(
href, action, streaming, parseOptions, null, allocateLocation(),
makeRetainedStaticContext());
} catch (XPathException err) {
compileError(err);
return null;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy