@tradik/xslt3 0.0.0-stage → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +28 -0
- package/README.md +98 -2
- package/package.json +43 -4
- package/src/errors.js +20 -0
- package/src/functions/aggregates.js +144 -0
- package/src/functions/arraySort.js +33 -0
- package/src/functions/arrays.js +181 -0
- package/src/functions/attributeTypes.js +58 -0
- package/src/functions/baseUris.js +82 -0
- package/src/functions/collations.js +127 -0
- package/src/functions/collections.js +84 -0
- package/src/functions/context.js +83 -0
- package/src/functions/core.js +167 -0
- package/src/functions/datetime.js +203 -0
- package/src/functions/deepEqual.js +132 -0
- package/src/functions/diagnostics.js +88 -0
- package/src/functions/focus.js +34 -0
- package/src/functions/format/dateComponents.js +176 -0
- package/src/functions/format/datePicture.js +115 -0
- package/src/functions/format/decimalFormat.js +65 -0
- package/src/functions/format/digitPattern.js +145 -0
- package/src/functions/format/formatDateTime.js +204 -0
- package/src/functions/format/formatInteger.js +109 -0
- package/src/functions/format/formatNumber.js +165 -0
- package/src/functions/format/fractionFormat.js +80 -0
- package/src/functions/format/germanWords.js +89 -0
- package/src/functions/format/numberLanguages.js +41 -0
- package/src/functions/format/numberPicture.js +202 -0
- package/src/functions/format/numberWords.js +155 -0
- package/src/functions/format/place.js +74 -0
- package/src/functions/format/timezoneFormat.js +89 -0
- package/src/functions/higherOrder.js +106 -0
- package/src/functions/ids.js +127 -0
- package/src/functions/json/index.js +17 -0
- package/src/functions/json/jsonChars.js +110 -0
- package/src/functions/json/jsonParser.js +203 -0
- package/src/functions/json/jsonStrings.js +116 -0
- package/src/functions/json/jsonToXml.js +116 -0
- package/src/functions/json/parseJson.js +119 -0
- package/src/functions/json/xmlRepresentation.js +103 -0
- package/src/functions/json/xmlToJson.js +147 -0
- package/src/functions/library.js +47 -0
- package/src/functions/mapArrayEqual.js +41 -0
- package/src/functions/maps.js +152 -0
- package/src/functions/math.js +73 -0
- package/src/functions/nodePaths.js +181 -0
- package/src/functions/nodes.js +199 -0
- package/src/functions/numeric.js +148 -0
- package/src/functions/options.js +58 -0
- package/src/functions/parseIetfDate.js +104 -0
- package/src/functions/parseXml.js +77 -0
- package/src/functions/qnames.js +68 -0
- package/src/functions/random.js +128 -0
- package/src/functions/regex/analyzeString.js +144 -0
- package/src/functions/regex/charClass.js +112 -0
- package/src/functions/regex/compile.js +81 -0
- package/src/functions/regex/escapes.js +109 -0
- package/src/functions/regex/parser.js +169 -0
- package/src/functions/regex/reader.js +37 -0
- package/src/functions/regex/regexFunctions.js +140 -0
- package/src/functions/regex/translate.js +102 -0
- package/src/functions/regex/unicodeBlocks.js +194 -0
- package/src/functions/registry.js +140 -0
- package/src/functions/sequences.js +173 -0
- package/src/functions/serializeFunction.js +53 -0
- package/src/functions/signatures.js +105 -0
- package/src/functions/sort.js +102 -0
- package/src/functions/stringMatch.js +45 -0
- package/src/functions/strings.js +194 -0
- package/src/functions/stringsCore.js +66 -0
- package/src/functions/support.js +106 -0
- package/src/functions/textDecoding.js +117 -0
- package/src/functions/ucaCollation.js +127 -0
- package/src/functions/unparsedText.js +71 -0
- package/src/functions/uri.js +166 -0
- package/src/functions/xqueryModule.js +24 -0
- package/src/index.js +38 -0
- package/src/items/array.js +84 -0
- package/src/items/function.js +45 -0
- package/src/items/map.js +120 -0
- package/src/items/mapKey.js +82 -0
- package/src/serialize/index.js +129 -0
- package/src/serialize/markup/content.js +74 -0
- package/src/serialize/markup/dialect.js +178 -0
- package/src/serialize/markup/htmlData.js +70 -0
- package/src/serialize/markup/namespaces.js +145 -0
- package/src/serialize/markup/prolog.js +91 -0
- package/src/serialize/markup/writer.js +183 -0
- package/src/serialize/methods/adaptive.js +131 -0
- package/src/serialize/methods/json.js +158 -0
- package/src/serialize/methods/text.js +43 -0
- package/src/serialize/output/buffer.js +48 -0
- package/src/serialize/output/encoding.js +146 -0
- package/src/serialize/output/expander.js +204 -0
- package/src/serialize/params/fromElement.js +141 -0
- package/src/serialize/params/fromMap.js +128 -0
- package/src/serialize/params/names.js +69 -0
- package/src/serialize/params/settings.js +153 -0
- package/src/serialize/params/values.js +163 -0
- package/src/serialize/sequence.js +111 -0
- package/src/xdm/arithmetic.js +155 -0
- package/src/xdm/atomic.js +142 -0
- package/src/xdm/binary.js +92 -0
- package/src/xdm/calendar.js +71 -0
- package/src/xdm/cast.js +176 -0
- package/src/xdm/compare.js +192 -0
- package/src/xdm/datetime.js +206 -0
- package/src/xdm/decimal.js +200 -0
- package/src/xdm/duration.js +128 -0
- package/src/xdm/generalCompare.js +152 -0
- package/src/xdm/index.js +47 -0
- package/src/xdm/lexical.js +126 -0
- package/src/xdm/nodes.js +170 -0
- package/src/xdm/numeric.js +122 -0
- package/src/xdm/qname.js +65 -0
- package/src/xdm/strings.js +52 -0
- package/src/xdm/temporalArithmetic.js +180 -0
- package/src/xdm/timeline.js +68 -0
- package/src/xdm/types.js +178 -0
- package/src/xpath/eval/atomics.js +45 -0
- package/src/xpath/eval/axes.js +212 -0
- package/src/xpath/eval/calls.js +168 -0
- package/src/xpath/eval/coercion.js +146 -0
- package/src/xpath/eval/compiler.js +71 -0
- package/src/xpath/eval/constructors.js +129 -0
- package/src/xpath/eval/decimalFormats.js +93 -0
- package/src/xpath/eval/descendantMemo.js +77 -0
- package/src/xpath/eval/documentOrder.js +142 -0
- package/src/xpath/eval/domNodes.js +174 -0
- package/src/xpath/eval/dynamicCall.js +27 -0
- package/src/xpath/eval/dynamicContext.js +161 -0
- package/src/xpath/eval/flow.js +115 -0
- package/src/xpath/eval/functionItems.js +194 -0
- package/src/xpath/eval/groupedChildren.js +88 -0
- package/src/xpath/eval/inline.js +71 -0
- package/src/xpath/eval/namespaceNodes.js +90 -0
- package/src/xpath/eval/nodeTests.js +164 -0
- package/src/xpath/eval/operators.js +190 -0
- package/src/xpath/eval/paths.js +163 -0
- package/src/xpath/eval/positional.js +81 -0
- package/src/xpath/eval/predicates.js +56 -0
- package/src/xpath/eval/primary.js +99 -0
- package/src/xpath/eval/resources.js +149 -0
- package/src/xpath/eval/scope.js +108 -0
- package/src/xpath/eval/sequenceType.js +193 -0
- package/src/xpath/eval/staticContext.js +142 -0
- package/src/xpath/eval/steps.js +98 -0
- package/src/xpath/eval/subtype.js +154 -0
- package/src/xpath/eval/typeExprs.js +147 -0
- package/src/xpath/eval/typeNames.js +101 -0
- package/src/xpath/eval/uris.js +21 -0
- package/src/xpath/eval/values.js +64 -0
- package/src/xpath/index.js +217 -0
- package/src/xpath/syntax/ast.js +130 -0
- package/src/xpath/syntax/chars.js +58 -0
- package/src/xpath/syntax/constructors.js +144 -0
- package/src/xpath/syntax/expressions.js +107 -0
- package/src/xpath/syntax/index.js +44 -0
- package/src/xpath/syntax/kindTests.js +134 -0
- package/src/xpath/syntax/lexer.js +220 -0
- package/src/xpath/syntax/operators.js +111 -0
- package/src/xpath/syntax/paths.js +102 -0
- package/src/xpath/syntax/postfix.js +91 -0
- package/src/xpath/syntax/primaries.js +149 -0
- package/src/xpath/syntax/steps.js +146 -0
- package/src/xpath/syntax/syntaxError.js +31 -0
- package/src/xpath/syntax/tokenStream.js +163 -0
- package/src/xpath/syntax/typeAst.js +76 -0
- package/src/xpath/syntax/typeOperators.js +127 -0
- package/src/xpath/syntax/types.js +158 -0
- package/src/xslt/api.js +153 -0
- package/src/xslt/compiler/acceptance.js +178 -0
- package/src/xslt/compiler/accumulatorDecl.js +146 -0
- package/src/xslt/compiler/attributeValues.js +174 -0
- package/src/xslt/compiler/attributes.js +211 -0
- package/src/xslt/compiler/avt.js +103 -0
- package/src/xslt/compiler/body.js +154 -0
- package/src/xslt/compiler/children.js +105 -0
- package/src/xslt/compiler/compatibility.js +130 -0
- package/src/xslt/compiler/components.js +179 -0
- package/src/xslt/compiler/contextItem.js +95 -0
- package/src/xslt/compiler/decimalFormats.js +132 -0
- package/src/xslt/compiler/declarationKinds.js +82 -0
- package/src/xslt/compiler/elementInfo.js +246 -0
- package/src/xslt/compiler/expressions.js +175 -0
- package/src/xslt/compiler/globalContextItem.js +92 -0
- package/src/xslt/compiler/globals.js +209 -0
- package/src/xslt/compiler/linker.js +134 -0
- package/src/xslt/compiler/miscDecl.js +171 -0
- package/src/xslt/compiler/modeDecl.js +88 -0
- package/src/xslt/compiler/moduleLoading.js +111 -0
- package/src/xslt/compiler/modules.js +158 -0
- package/src/xslt/compiler/outputDecl.js +209 -0
- package/src/xslt/compiler/overrideLinks.js +141 -0
- package/src/xslt/compiler/packageChecks.js +84 -0
- package/src/xslt/compiler/packageRegistry.js +95 -0
- package/src/xslt/compiler/packageTable.js +181 -0
- package/src/xslt/compiler/packageVersions.js +143 -0
- package/src/xslt/compiler/packages.js +138 -0
- package/src/xslt/compiler/registry.js +234 -0
- package/src/xslt/compiler/staticStage.js +197 -0
- package/src/xslt/compiler/staticVariables.js +93 -0
- package/src/xslt/compiler/stylesheet.js +205 -0
- package/src/xslt/compiler/tailPosition.js +74 -0
- package/src/xslt/compiler/templatesDecl.js +180 -0
- package/src/xslt/compiler/useAccumulators.js +76 -0
- package/src/xslt/compiler/useWhen.js +94 -0
- package/src/xslt/compiler/visibility.js +160 -0
- package/src/xslt/index.js +11 -0
- package/src/xslt/instructions/analyzeString.js +137 -0
- package/src/xslt/instructions/assert.js +72 -0
- package/src/xslt/instructions/attributeSets.js +115 -0
- package/src/xslt/instructions/conditional.js +99 -0
- package/src/xslt/instructions/control.js +123 -0
- package/src/xslt/instructions/copy.js +151 -0
- package/src/xslt/instructions/elements.js +161 -0
- package/src/xslt/instructions/evaluate.js +189 -0
- package/src/xslt/instructions/fork.js +35 -0
- package/src/xslt/instructions/grouping.js +106 -0
- package/src/xslt/instructions/index.js +94 -0
- package/src/xslt/instructions/iterate.js +182 -0
- package/src/xslt/instructions/literal.js +142 -0
- package/src/xslt/instructions/maps.js +72 -0
- package/src/xslt/instructions/merge.js +190 -0
- package/src/xslt/instructions/number.js +205 -0
- package/src/xslt/instructions/output.js +102 -0
- package/src/xslt/instructions/params.js +110 -0
- package/src/xslt/instructions/resultDocument.js +143 -0
- package/src/xslt/instructions/sort.js +114 -0
- package/src/xslt/instructions/sourceDocument.js +73 -0
- package/src/xslt/instructions/templates.js +153 -0
- package/src/xslt/instructions/text.js +151 -0
- package/src/xslt/instructions/try.js +186 -0
- package/src/xslt/instructions/variables.js +119 -0
- package/src/xslt/names.js +204 -0
- package/src/xslt/patterns/axisOrigins.js +121 -0
- package/src/xslt/patterns/compile.js +151 -0
- package/src/xslt/patterns/general.js +132 -0
- package/src/xslt/patterns/grammar.js +190 -0
- package/src/xslt/patterns/modes.js +153 -0
- package/src/xslt/patterns/paths.js +130 -0
- package/src/xslt/patterns/patternChecks.js +29 -0
- package/src/xslt/patterns/steps.js +162 -0
- package/src/xslt/processor.js +178 -0
- package/src/xslt/runtime/accumulatorFunctions.js +48 -0
- package/src/xslt/runtime/accumulators.js +174 -0
- package/src/xslt/runtime/apply.js +153 -0
- package/src/xslt/runtime/atomicKeys.js +36 -0
- package/src/xslt/runtime/availability.js +162 -0
- package/src/xslt/runtime/baseUri.js +64 -0
- package/src/xslt/runtime/compilerHook.js +27 -0
- package/src/xslt/runtime/conditional.js +110 -0
- package/src/xslt/runtime/context.js +106 -0
- package/src/xslt/runtime/copy.js +123 -0
- package/src/xslt/runtime/copyFunctions.js +71 -0
- package/src/xslt/runtime/copyOrigins.js +60 -0
- package/src/xslt/runtime/defaultMethod.js +42 -0
- package/src/xslt/runtime/documentContent.js +93 -0
- package/src/xslt/runtime/dynamicXPath.js +90 -0
- package/src/xslt/runtime/functionCache.js +65 -0
- package/src/xslt/runtime/functionCall.js +57 -0
- package/src/xslt/runtime/functions.js +191 -0
- package/src/xslt/runtime/groups.js +108 -0
- package/src/xslt/runtime/invocation.js +156 -0
- package/src/xslt/runtime/iteration.js +107 -0
- package/src/xslt/runtime/keys.js +141 -0
- package/src/xslt/runtime/lazy.js +97 -0
- package/src/xslt/runtime/locations.js +86 -0
- package/src/xslt/runtime/machine.js +137 -0
- package/src/xslt/runtime/merging.js +167 -0
- package/src/xslt/runtime/namespaceScope.js +141 -0
- package/src/xslt/runtime/numberFormat.js +89 -0
- package/src/xslt/runtime/numbering.js +168 -0
- package/src/xslt/runtime/params.js +59 -0
- package/src/xslt/runtime/properties.js +103 -0
- package/src/xslt/runtime/rawResults.js +82 -0
- package/src/xslt/runtime/sequenceReceiver.js +102 -0
- package/src/xslt/runtime/snapshot.js +66 -0
- package/src/xslt/runtime/sortKeys.js +119 -0
- package/src/xslt/runtime/streamAvailable.js +60 -0
- package/src/xslt/runtime/strip.js +102 -0
- package/src/xslt/runtime/transformFunction.js +169 -0
- package/src/xslt/runtime/transformation.js +168 -0
- package/src/xslt/runtime/transformationContext.js +85 -0
- package/src/xslt/runtime/treeReceiver.js +194 -0
- package/src/xslt/runtime/values.js +92 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xsl:for-each-group (XSLT 3.0 section 14): group-by, group-adjacent,
|
|
3
|
+
* group-starting-with and group-ending-with, then the groups processed
|
|
4
|
+
* in order (or sorted), each with its current group and grouping key.
|
|
5
|
+
*
|
|
6
|
+
* @module @tradik/xslt3/xslt/instructions/grouping
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { getCollation } from "../../functions/collations.js";
|
|
10
|
+
import { compileBody } from "../compiler/body.js";
|
|
11
|
+
import { required, yesNo } from "../compiler/attributes.js";
|
|
12
|
+
import { derive, evaluate } from "../runtime/context.js";
|
|
13
|
+
import { groupByKeys, groupByPattern } from "../runtime/groups.js";
|
|
14
|
+
import { avtEvaluator } from "../runtime/values.js";
|
|
15
|
+
import { attr, xsltError } from "../names.js";
|
|
16
|
+
import { compilePattern } from "../patterns/compile.js";
|
|
17
|
+
import { BodyFrame, LoopFrame } from "../runtime/machine.js";
|
|
18
|
+
import { compileSorts, splitSorts } from "./sort.js";
|
|
19
|
+
|
|
20
|
+
const METHODS = [
|
|
21
|
+
"group-by",
|
|
22
|
+
"group-adjacent",
|
|
23
|
+
"group-starting-with",
|
|
24
|
+
"group-ending-with",
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* xsl:for-each-group.
|
|
29
|
+
* @param {Element} element
|
|
30
|
+
* @param {object} cx
|
|
31
|
+
* @param {object} scope
|
|
32
|
+
* @returns {Function}
|
|
33
|
+
*/
|
|
34
|
+
export function compileForEachGroup(element, cx, scope) {
|
|
35
|
+
const select = cx.exprs.xpath(
|
|
36
|
+
required(element, "select"),
|
|
37
|
+
element,
|
|
38
|
+
scope.vars,
|
|
39
|
+
);
|
|
40
|
+
const present = METHODS.filter((name) => attr(element, name) !== undefined);
|
|
41
|
+
if (present.length !== 1) {
|
|
42
|
+
throw xsltError("XTSE1080", "xsl:for-each-group needs one grouping method");
|
|
43
|
+
}
|
|
44
|
+
const method = present[0];
|
|
45
|
+
const text = attr(element, method);
|
|
46
|
+
const byPattern = method.endsWith("with");
|
|
47
|
+
const keys = byPattern ? null : cx.exprs.xpath(text, element, scope.vars);
|
|
48
|
+
const pattern = byPattern
|
|
49
|
+
? compilePattern(text, element, cx, scope.vars)
|
|
50
|
+
: null;
|
|
51
|
+
const collationText = attr(element, "collation");
|
|
52
|
+
if (collationText !== undefined && byPattern) {
|
|
53
|
+
throw xsltError("XTSE1090", "collation needs group-by or group-adjacent");
|
|
54
|
+
}
|
|
55
|
+
const collation =
|
|
56
|
+
collationText === undefined
|
|
57
|
+
? null
|
|
58
|
+
: avtEvaluator(cx.exprs.avt(collationText, element, scope.vars));
|
|
59
|
+
const { sorts, rest } = splitSorts(cx.children(element));
|
|
60
|
+
const sort = compileSorts(sorts, cx, scope);
|
|
61
|
+
const body = compileBody(element, cx, scope, rest);
|
|
62
|
+
const composite = yesNo(element, "composite", false);
|
|
63
|
+
return (xc, out, machine) => {
|
|
64
|
+
const items = evaluate(select, xc);
|
|
65
|
+
let collationObject = getCollation(undefined, xc.tx.dyn);
|
|
66
|
+
if (collation) {
|
|
67
|
+
const uri = collation(xc);
|
|
68
|
+
try {
|
|
69
|
+
collationObject = getCollation(uri, xc.tx.dyn);
|
|
70
|
+
} catch {
|
|
71
|
+
throw xsltError("XTDE1110", `Unknown collation ${uri}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
const groups = byPattern
|
|
75
|
+
? groupByPattern(items, pattern, xc, method === "group-starting-with")
|
|
76
|
+
: groupByKeys(items, (focus) => evaluate(keys, focus), xc, {
|
|
77
|
+
adjacent: method === "group-adjacent",
|
|
78
|
+
collation: collationObject,
|
|
79
|
+
composite,
|
|
80
|
+
});
|
|
81
|
+
const order = sort.order(
|
|
82
|
+
groups.map((group) => group.items[0]),
|
|
83
|
+
xc,
|
|
84
|
+
machine,
|
|
85
|
+
(focus, i) =>
|
|
86
|
+
derive(focus, { group: groups[i].items, groupKey: groups[i].key }),
|
|
87
|
+
);
|
|
88
|
+
const ordered = order.map((i) => groups[i]);
|
|
89
|
+
const size = ordered.length;
|
|
90
|
+
if (size === 0 || body.length === 0) return;
|
|
91
|
+
const base = derive(xc, { rule: null });
|
|
92
|
+
machine.push(
|
|
93
|
+
new LoopFrame(size, (i) => {
|
|
94
|
+
const group = ordered[i];
|
|
95
|
+
const context = derive(base, {
|
|
96
|
+
item: group.items[0],
|
|
97
|
+
position: i + 1,
|
|
98
|
+
size,
|
|
99
|
+
group: group.items,
|
|
100
|
+
groupKey: group.key,
|
|
101
|
+
});
|
|
102
|
+
machine.push(new BodyFrame(body, context, out));
|
|
103
|
+
}),
|
|
104
|
+
);
|
|
105
|
+
};
|
|
106
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The compilers of the XSLT instructions, by local name. Each takes the
|
|
3
|
+
* instruction element, the stylesheet compiler and the scope, and returns
|
|
4
|
+
* a step of the sequence constructor (see runtime/machine.js) or null.
|
|
5
|
+
*
|
|
6
|
+
* @module @tradik/xslt3/xslt/instructions
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { compileAnalyzeString } from "./analyzeString.js";
|
|
10
|
+
import { compileAssert } from "./assert.js";
|
|
11
|
+
import { compileChoose, compileForEach, compileIf } from "./control.js";
|
|
12
|
+
import {
|
|
13
|
+
compileCopy,
|
|
14
|
+
compileCopyOf,
|
|
15
|
+
compileDocument,
|
|
16
|
+
compilePerformSort,
|
|
17
|
+
} from "./copy.js";
|
|
18
|
+
import { compileAttribute, compileElement } from "./elements.js";
|
|
19
|
+
import {
|
|
20
|
+
compileOnEmpty,
|
|
21
|
+
compileOnNonEmpty,
|
|
22
|
+
compileWherePopulated,
|
|
23
|
+
} from "./conditional.js";
|
|
24
|
+
import { compileEvaluate } from "./evaluate.js";
|
|
25
|
+
import { compileFork } from "./fork.js";
|
|
26
|
+
import { compileForEachGroup } from "./grouping.js";
|
|
27
|
+
import {
|
|
28
|
+
compileBreak,
|
|
29
|
+
compileIterate,
|
|
30
|
+
compileNextIteration,
|
|
31
|
+
} from "./iterate.js";
|
|
32
|
+
import { compileMerge } from "./merge.js";
|
|
33
|
+
import { compileNumber } from "./number.js";
|
|
34
|
+
import { compileMap, compileMapEntry } from "./maps.js";
|
|
35
|
+
import { compileMessage } from "./output.js";
|
|
36
|
+
import { compileResultDocument } from "./resultDocument.js";
|
|
37
|
+
import { compileSourceDocument } from "./sourceDocument.js";
|
|
38
|
+
import {
|
|
39
|
+
compileApplyImports,
|
|
40
|
+
compileApplyTemplates,
|
|
41
|
+
compileCallTemplate,
|
|
42
|
+
} from "./templates.js";
|
|
43
|
+
import { compileTry } from "./try.js";
|
|
44
|
+
import {
|
|
45
|
+
compileComment,
|
|
46
|
+
compileNamespace,
|
|
47
|
+
compileProcessingInstruction,
|
|
48
|
+
compileSequence,
|
|
49
|
+
compileText,
|
|
50
|
+
compileValueOf,
|
|
51
|
+
} from "./text.js";
|
|
52
|
+
|
|
53
|
+
/** @type {Record<string, Function>} */
|
|
54
|
+
export const instructionCompilers = {
|
|
55
|
+
"analyze-string": compileAnalyzeString,
|
|
56
|
+
"apply-imports": compileApplyImports,
|
|
57
|
+
"apply-templates": compileApplyTemplates,
|
|
58
|
+
attribute: compileAttribute,
|
|
59
|
+
"call-template": compileCallTemplate,
|
|
60
|
+
choose: compileChoose,
|
|
61
|
+
comment: compileComment,
|
|
62
|
+
copy: compileCopy,
|
|
63
|
+
"copy-of": compileCopyOf,
|
|
64
|
+
document: compileDocument,
|
|
65
|
+
element: compileElement,
|
|
66
|
+
"for-each": compileForEach,
|
|
67
|
+
"for-each-group": compileForEachGroup,
|
|
68
|
+
if: compileIf,
|
|
69
|
+
message: compileMessage,
|
|
70
|
+
namespace: compileNamespace,
|
|
71
|
+
"next-match": compileApplyImports,
|
|
72
|
+
number: compileNumber,
|
|
73
|
+
"perform-sort": compilePerformSort,
|
|
74
|
+
"processing-instruction": compileProcessingInstruction,
|
|
75
|
+
"result-document": compileResultDocument,
|
|
76
|
+
map: compileMap,
|
|
77
|
+
"map-entry": compileMapEntry,
|
|
78
|
+
try: compileTry,
|
|
79
|
+
sequence: compileSequence,
|
|
80
|
+
text: compileText,
|
|
81
|
+
"value-of": compileValueOf,
|
|
82
|
+
// XSLT 3.0 instructions of task 0031
|
|
83
|
+
break: compileBreak,
|
|
84
|
+
iterate: compileIterate,
|
|
85
|
+
"next-iteration": compileNextIteration,
|
|
86
|
+
"on-empty": compileOnEmpty,
|
|
87
|
+
"on-non-empty": compileOnNonEmpty,
|
|
88
|
+
"where-populated": compileWherePopulated,
|
|
89
|
+
fork: compileFork,
|
|
90
|
+
"source-document": compileSourceDocument,
|
|
91
|
+
merge: compileMerge,
|
|
92
|
+
evaluate: compileEvaluate,
|
|
93
|
+
assert: compileAssert,
|
|
94
|
+
};
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xsl:iterate, xsl:next-iteration, xsl:break and xsl:on-completion
|
|
3
|
+
* (XSLT 3.0 section 7.2). The iterations run on the work stack (see
|
|
4
|
+
* runtime/iteration.js); xsl:next-iteration and xsl:break record their
|
|
5
|
+
* effect in the iteration state of the context, read before the next
|
|
6
|
+
* item is processed.
|
|
7
|
+
*
|
|
8
|
+
* @module @tradik/xslt3/xslt/instructions/iterate
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { compileBody } from "../compiler/body.js";
|
|
12
|
+
import { checkAttributes, required } from "../compiler/attributes.js";
|
|
13
|
+
import { isWhitespaceText, splitLeading } from "../compiler/children.js";
|
|
14
|
+
import { checkTailPosition } from "../compiler/tailPosition.js";
|
|
15
|
+
import { evaluate } from "../runtime/context.js";
|
|
16
|
+
import { IterateFrame } from "../runtime/iteration.js";
|
|
17
|
+
import { BodyFrame } from "../runtime/machine.js";
|
|
18
|
+
import { attr, isXsl, XSL_NS, xsltError } from "../names.js";
|
|
19
|
+
import { compileParams, compileWithParams } from "./params.js";
|
|
20
|
+
|
|
21
|
+
/** @type {WeakMap<Element, object[]>} the parameters of each xsl:iterate */
|
|
22
|
+
const iterateParams = new WeakMap();
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Compiles the select attribute or the content of xsl:break or
|
|
26
|
+
* xsl:on-completion.
|
|
27
|
+
* @param {Element} element
|
|
28
|
+
* @param {object} cx
|
|
29
|
+
* @param {object} scope
|
|
30
|
+
* @returns {import("../runtime/machine.js").Body}
|
|
31
|
+
*/
|
|
32
|
+
function compileContent(element, cx, scope) {
|
|
33
|
+
const select = attr(element, "select");
|
|
34
|
+
const children = cx.children(element).filter((c) => !isXsl(c, "fallback"));
|
|
35
|
+
if (select === undefined) return compileBody(element, cx, scope, children);
|
|
36
|
+
if (children.length > 0) {
|
|
37
|
+
throw xsltError(
|
|
38
|
+
"XTSE3125",
|
|
39
|
+
`xsl:${element.localName} has select and content`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
const expr = cx.exprs.xpath(select, element, scope.vars);
|
|
43
|
+
return [
|
|
44
|
+
(xc, out) => {
|
|
45
|
+
for (const item of evaluate(expr, xc)) out.item(item);
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Checks that a parameter of xsl:iterate without initial value accepts
|
|
52
|
+
* the empty sequence.
|
|
53
|
+
* @param {object} param
|
|
54
|
+
* @throws {import("../../errors.js").XPathError} XTSE3520
|
|
55
|
+
*/
|
|
56
|
+
function checkOptional(param) {
|
|
57
|
+
try {
|
|
58
|
+
param.convert([]);
|
|
59
|
+
} catch {
|
|
60
|
+
throw xsltError(
|
|
61
|
+
"XTSE3520",
|
|
62
|
+
`The parameter ${param.key} of xsl:iterate needs an initial value`,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Checks that the xsl:on-completion elements near an xsl:iterate (its
|
|
69
|
+
* siblings and descendants) are children of an xsl:iterate.
|
|
70
|
+
* @param {Element} element - xsl:iterate
|
|
71
|
+
* @throws {import("../../errors.js").XPathError} XTSE0010
|
|
72
|
+
*/
|
|
73
|
+
function checkCompletions(element) {
|
|
74
|
+
const nodes = [
|
|
75
|
+
...element.parentNode.childNodes,
|
|
76
|
+
...element.getElementsByTagNameNS(XSL_NS, "on-completion"),
|
|
77
|
+
];
|
|
78
|
+
for (const node of nodes) {
|
|
79
|
+
if (isXsl(node, "on-completion") && !isXsl(node.parentNode, "iterate")) {
|
|
80
|
+
throw xsltError("XTSE0010", "xsl:on-completion must be in xsl:iterate");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* xsl:iterate.
|
|
87
|
+
* @param {Element} element
|
|
88
|
+
* @param {object} cx
|
|
89
|
+
* @param {object} scope
|
|
90
|
+
* @returns {Function}
|
|
91
|
+
*/
|
|
92
|
+
export function compileIterate(element, cx, scope) {
|
|
93
|
+
const select = cx.exprs.xpath(
|
|
94
|
+
required(element, "select"),
|
|
95
|
+
element,
|
|
96
|
+
scope.vars,
|
|
97
|
+
);
|
|
98
|
+
checkCompletions(element);
|
|
99
|
+
const { leading, rest } = splitLeading(cx.children(element), "param");
|
|
100
|
+
const { params, scope: inner } = compileParams(leading, cx, scope);
|
|
101
|
+
leading.forEach((param, i) => {
|
|
102
|
+
const implicit =
|
|
103
|
+
attr(param, "select") === undefined && cx.children(param).length === 0;
|
|
104
|
+
if (implicit && params[i].type) checkOptional(params[i]);
|
|
105
|
+
});
|
|
106
|
+
iterateParams.set(element, params);
|
|
107
|
+
let body = rest;
|
|
108
|
+
let completion = [];
|
|
109
|
+
const first = rest.find((child) => !isWhitespaceText(child));
|
|
110
|
+
if (first && isXsl(first, "on-completion")) {
|
|
111
|
+
checkAttributes(first);
|
|
112
|
+
completion = compileContent(first, cx, inner);
|
|
113
|
+
body = rest.filter((child) => child !== first);
|
|
114
|
+
}
|
|
115
|
+
if (body.some((c) => isXsl(c, "param") || isXsl(c, "on-completion"))) {
|
|
116
|
+
throw xsltError(
|
|
117
|
+
"XTSE0010",
|
|
118
|
+
"xsl:param, then xsl:on-completion, must come first in xsl:iterate",
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
const steps = compileBody(element, cx, inner, body);
|
|
122
|
+
return (xc, out, machine) => {
|
|
123
|
+
const items = evaluate(select, xc);
|
|
124
|
+
machine.push(
|
|
125
|
+
new IterateFrame({ items, params, steps, completion, xc, out }),
|
|
126
|
+
);
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* The innermost xsl:iterate ancestor of an element.
|
|
132
|
+
* @param {Element} element
|
|
133
|
+
* @returns {Element}
|
|
134
|
+
*/
|
|
135
|
+
function enclosingIterate(element) {
|
|
136
|
+
let node = element.parentNode;
|
|
137
|
+
while (!isXsl(node, "iterate")) node = node.parentNode;
|
|
138
|
+
return node;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* xsl:next-iteration.
|
|
143
|
+
* @param {Element} element
|
|
144
|
+
* @param {object} cx
|
|
145
|
+
* @param {object} scope
|
|
146
|
+
* @returns {Function}
|
|
147
|
+
*/
|
|
148
|
+
export function compileNextIteration(element, cx, scope) {
|
|
149
|
+
checkTailPosition(element, cx);
|
|
150
|
+
const children = cx.children(element);
|
|
151
|
+
if (!children.every((c) => isXsl(c, "with-param") || isXsl(c, "fallback"))) {
|
|
152
|
+
throw xsltError("XTSE0010", "xsl:next-iteration contains xsl:with-param");
|
|
153
|
+
}
|
|
154
|
+
const withParams = compileWithParams(children, cx, scope);
|
|
155
|
+
const declared = iterateParams.get(enclosingIterate(element));
|
|
156
|
+
const keys = new Set(declared.map((param) => param.key));
|
|
157
|
+
for (const name of withParams.names) {
|
|
158
|
+
if (!keys.has(name)) {
|
|
159
|
+
throw xsltError("XTSE3130", `xsl:iterate has no parameter ${name}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return (xc, out, machine) => {
|
|
163
|
+
const { params } = withParams.evaluate(xc, machine);
|
|
164
|
+
xc.iteration.next = params;
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* xsl:break.
|
|
170
|
+
* @param {Element} element
|
|
171
|
+
* @param {object} cx
|
|
172
|
+
* @param {object} scope
|
|
173
|
+
* @returns {Function}
|
|
174
|
+
*/
|
|
175
|
+
export function compileBreak(element, cx, scope) {
|
|
176
|
+
checkTailPosition(element, cx);
|
|
177
|
+
const body = compileContent(element, cx, scope);
|
|
178
|
+
return (xc, out, machine) => {
|
|
179
|
+
xc.iteration.broken = true;
|
|
180
|
+
if (body.length > 0) machine.push(new BodyFrame(body, xc, out));
|
|
181
|
+
};
|
|
182
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Literal result elements (XSLT 3.0 section 11.1): the element is copied
|
|
3
|
+
* with its namespace nodes (less the XSLT namespace and the excluded
|
|
4
|
+
* ones, with namespace aliases applied) and its attributes, whose values
|
|
5
|
+
* are attribute value templates; its content is a sequence constructor.
|
|
6
|
+
*
|
|
7
|
+
* @module @tradik/xslt3/xslt/instructions/literal
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { compileBody } from "../compiler/body.js";
|
|
11
|
+
import { infoOf } from "../compiler/elementInfo.js";
|
|
12
|
+
import { isNamespaceDeclaration } from "../../xpath/eval/domNodes.js";
|
|
13
|
+
import { markConstructed } from "../runtime/baseUri.js";
|
|
14
|
+
import { BodyFrame } from "../runtime/machine.js";
|
|
15
|
+
import { avtEvaluator } from "../runtime/values.js";
|
|
16
|
+
import { XSL_NS, xslAttr, xsltError } from "../names.js";
|
|
17
|
+
import { attributeSetNames, applyAttributeSets } from "./attributeSets.js";
|
|
18
|
+
|
|
19
|
+
/** Attributes in the XSLT namespace allowed on literal result elements. */
|
|
20
|
+
const LRE_ATTRIBUTES = new Set([
|
|
21
|
+
"version",
|
|
22
|
+
"exclude-result-prefixes",
|
|
23
|
+
"extension-element-prefixes",
|
|
24
|
+
"xpath-default-namespace",
|
|
25
|
+
"default-collation",
|
|
26
|
+
"default-mode",
|
|
27
|
+
"default-validation",
|
|
28
|
+
"expand-text",
|
|
29
|
+
"use-attribute-sets",
|
|
30
|
+
"use-when",
|
|
31
|
+
"type",
|
|
32
|
+
"validation",
|
|
33
|
+
"inherit-namespaces",
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* The result name of a stylesheet name after namespace aliasing.
|
|
38
|
+
* @param {string} uri
|
|
39
|
+
* @param {string} prefix
|
|
40
|
+
* @param {string} local
|
|
41
|
+
* @param {Map<string, {uri: string, prefix: string}>} aliases
|
|
42
|
+
* @returns {{uri: string, qname: string}}
|
|
43
|
+
*/
|
|
44
|
+
export function aliasedName(uri, prefix, local, aliases) {
|
|
45
|
+
const alias = aliases.get(uri);
|
|
46
|
+
if (!alias) return { uri, qname: prefix ? `${prefix}:${local}` : local };
|
|
47
|
+
const resultPrefix = alias.uri === "" ? "" : alias.prefix;
|
|
48
|
+
return {
|
|
49
|
+
uri: alias.uri,
|
|
50
|
+
qname: resultPrefix ? `${resultPrefix}:${local}` : local,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The namespace nodes a literal result element copies.
|
|
56
|
+
* @param {Element} element
|
|
57
|
+
* @param {Map<string, object>} aliases
|
|
58
|
+
* @returns {Array<[string, string]>} prefix, URI pairs
|
|
59
|
+
*/
|
|
60
|
+
function copiedNamespaces(element, aliases) {
|
|
61
|
+
const info = infoOf(element);
|
|
62
|
+
const result = [];
|
|
63
|
+
for (const [prefix, uri] of info.namespaces) {
|
|
64
|
+
if (prefix === "xml" || uri === XSL_NS) continue;
|
|
65
|
+
if (aliases.has(uri) || info.excluded.has(uri)) continue;
|
|
66
|
+
if (uri === "" && prefix !== "") continue;
|
|
67
|
+
result.push([prefix, uri]);
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Compiles a literal result element.
|
|
74
|
+
* @param {Element} element
|
|
75
|
+
* @param {object} cx - Stylesheet compiler
|
|
76
|
+
* @param {import("../compiler/body.js").Scope} scope
|
|
77
|
+
* @returns {Function} the step
|
|
78
|
+
*/
|
|
79
|
+
export function compileLiteralElement(element, cx, scope) {
|
|
80
|
+
const { uri, qname } = aliasedName(
|
|
81
|
+
element.namespaceURI ?? "",
|
|
82
|
+
element.prefix ?? "",
|
|
83
|
+
element.localName,
|
|
84
|
+
cx.aliases,
|
|
85
|
+
);
|
|
86
|
+
const namespaces = copiedNamespaces(element, cx.aliases);
|
|
87
|
+
const compatible = infoOf(element).version < 2;
|
|
88
|
+
const attributes = [];
|
|
89
|
+
const forwards = infoOf(element).version > 3;
|
|
90
|
+
for (const attribute of element.attributes) {
|
|
91
|
+
if (isNamespaceDeclaration(attribute)) continue;
|
|
92
|
+
if (attribute.namespaceURI === XSL_NS) {
|
|
93
|
+
if (!forwards && !LRE_ATTRIBUTES.has(attribute.localName)) {
|
|
94
|
+
throw xsltError(
|
|
95
|
+
"XTSE0805",
|
|
96
|
+
`Unknown attribute ${attribute.name} on a literal result element`,
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
// a non-schema-aware processor (XTSE1660)
|
|
100
|
+
const local = attribute.localName;
|
|
101
|
+
if (
|
|
102
|
+
local === "type" ||
|
|
103
|
+
(local === "validation" && attribute.value.trim() === "strict")
|
|
104
|
+
) {
|
|
105
|
+
throw xsltError(
|
|
106
|
+
"XTSE1660",
|
|
107
|
+
`xsl:${local} needs a schema-aware processor`,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const name = aliasedName(
|
|
113
|
+
attribute.namespaceURI ?? "",
|
|
114
|
+
attribute.prefix ?? "",
|
|
115
|
+
attribute.localName,
|
|
116
|
+
cx.aliases,
|
|
117
|
+
);
|
|
118
|
+
const parts = cx.exprs.avt(attribute.value, element, scope.vars);
|
|
119
|
+
attributes.push({ ...name, value: avtEvaluator(parts, compatible) });
|
|
120
|
+
}
|
|
121
|
+
const sets = attributeSetNames(
|
|
122
|
+
xslAttr(element, "use-attribute-sets"),
|
|
123
|
+
element,
|
|
124
|
+
cx,
|
|
125
|
+
);
|
|
126
|
+
const body = compileBody(element, cx, scope);
|
|
127
|
+
// its own xml:base is copied: the base URI it applies to is the parent's
|
|
128
|
+
const parent = element.parentNode;
|
|
129
|
+
const base = infoOf(parent?.nodeType === 1 ? parent : element).baseUri;
|
|
130
|
+
return (xc, out, machine) => {
|
|
131
|
+
const content = out.element(uri, qname);
|
|
132
|
+
markConstructed(content, base);
|
|
133
|
+
for (const [prefix, namespace] of namespaces) {
|
|
134
|
+
content.declareExplicit(prefix, namespace);
|
|
135
|
+
}
|
|
136
|
+
if (sets.length > 0) applyAttributeSets(sets, xc, content, machine, cx);
|
|
137
|
+
for (const attribute of attributes) {
|
|
138
|
+
content.attribute(attribute.uri, attribute.qname, attribute.value(xc));
|
|
139
|
+
}
|
|
140
|
+
if (body.length > 0) machine.push(new BodyFrame(body, xc, content));
|
|
141
|
+
};
|
|
142
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* xsl:map and xsl:map-entry (XSLT 3.0 section 21.4): maps built from
|
|
3
|
+
* instructions.
|
|
4
|
+
*
|
|
5
|
+
* @module @tradik/xslt3/xslt/instructions/maps
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { XdmMap } from "../../items/map.js";
|
|
9
|
+
import { isMap } from "../../xdm/atomic.js";
|
|
10
|
+
import { atomize } from "../../xdm/nodes.js";
|
|
11
|
+
import { compileBody } from "../compiler/body.js";
|
|
12
|
+
import { required } from "../compiler/attributes.js";
|
|
13
|
+
import { evaluate } from "../runtime/context.js";
|
|
14
|
+
import { bodySequence } from "../runtime/values.js";
|
|
15
|
+
import { attr, xsltError } from "../names.js";
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* xsl:map.
|
|
19
|
+
* @param {Element} element
|
|
20
|
+
* @param {object} cx
|
|
21
|
+
* @param {object} scope
|
|
22
|
+
* @returns {Function}
|
|
23
|
+
*/
|
|
24
|
+
export function compileMap(element, cx, scope) {
|
|
25
|
+
const body = compileBody(element, cx, scope);
|
|
26
|
+
return (xc, out, machine) => {
|
|
27
|
+
const pairs = [];
|
|
28
|
+
for (const item of bodySequence(body, xc, machine)) {
|
|
29
|
+
if (!isMap(item)) {
|
|
30
|
+
throw xsltError("XTTE3375", "xsl:map content must be maps");
|
|
31
|
+
}
|
|
32
|
+
for (const { key, value } of item.entries.values()) {
|
|
33
|
+
pairs.push([key, value]);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
out.item(
|
|
37
|
+
XdmMap.from(pairs, () => {
|
|
38
|
+
throw xsltError("XTDE3365", "Duplicate key in xsl:map");
|
|
39
|
+
}),
|
|
40
|
+
);
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* xsl:map-entry.
|
|
46
|
+
* @param {Element} element
|
|
47
|
+
* @param {object} cx
|
|
48
|
+
* @param {object} scope
|
|
49
|
+
* @returns {Function}
|
|
50
|
+
*/
|
|
51
|
+
export function compileMapEntry(element, cx, scope) {
|
|
52
|
+
const key = cx.exprs.xpath(required(element, "key"), element, scope.vars);
|
|
53
|
+
const select = attr(element, "select");
|
|
54
|
+
const body = compileBody(element, cx, scope);
|
|
55
|
+
if (select !== undefined && body.length > 0) {
|
|
56
|
+
throw xsltError("XTSE3280", "xsl:map-entry has select and content");
|
|
57
|
+
}
|
|
58
|
+
const value =
|
|
59
|
+
select === undefined
|
|
60
|
+
? (xc, machine) => bodySequence(body, xc, machine)
|
|
61
|
+
: (
|
|
62
|
+
(expr) => (xc) =>
|
|
63
|
+
evaluate(expr, xc)
|
|
64
|
+
)(cx.exprs.xpath(select, element, scope.vars));
|
|
65
|
+
return (xc, out, machine) => {
|
|
66
|
+
const keys = atomize(evaluate(key, xc));
|
|
67
|
+
if (keys.length !== 1) {
|
|
68
|
+
throw xsltError("XPTY0004", "A map key must be a single atomic value");
|
|
69
|
+
}
|
|
70
|
+
out.item(XdmMap.from([[keys[0], value(xc, machine)]]));
|
|
71
|
+
};
|
|
72
|
+
}
|