xsl:number implements all of XSLT 1.0 section 7.7: level single/multiple/any with count and from matched as patterns through the match cache, the value expression with the below-one bypass, and the format-token engine (punctuation, separator and token reuse, zero padding, alphabetic/roman/Greek sequences, digit grouping). An unmatched single/multiple count renders empty; level=any always yields a number. document() now caches per transform so repeated loads of the same URI return the identical document and generate-id() stays unique against live nodes (the idkey49 flake). Xalan baseline 557 -> 475 (numbering 84 -> 7).
61 lines
2.7 KiB
Swift
61 lines
2.7 KiB
Swift
extension PureXML.XSLT.XSLTParser {
|
|
static func structuralInstruction(_ node: XSLTTree) -> PureXML.XSLT.Instruction? {
|
|
switch XSLTNode.localName(node) {
|
|
case "for-each":
|
|
.forEach(select: XSLTNode.attribute(node, "select") ?? "", sorts: sorts(node), body: body(node))
|
|
case "if":
|
|
.ifInstruction(test: XSLTNode.attribute(node, "test") ?? "", body: body(node))
|
|
case "choose":
|
|
choose(node)
|
|
case "element":
|
|
.element(
|
|
name: valueTemplate(XSLTNode.attribute(node, "name") ?? ""),
|
|
namespace: XSLTNode.attribute(node, "namespace").map(valueTemplate),
|
|
namespaces: inScopeNamespaces(node),
|
|
useAttributeSets: useAttributeSets(node),
|
|
body: body(node),
|
|
)
|
|
case "attribute":
|
|
.attribute(
|
|
name: valueTemplate(XSLTNode.attribute(node, "name") ?? ""),
|
|
namespace: XSLTNode.attribute(node, "namespace").map(valueTemplate),
|
|
namespaces: inScopeNamespaces(node),
|
|
body: body(node),
|
|
)
|
|
case "number":
|
|
.number(PureXML.XSLT.NumberSpec(
|
|
level: XSLTNode.attribute(node, "level") ?? "single",
|
|
count: XSLTNode.attribute(node, "count"),
|
|
from: XSLTNode.attribute(node, "from"),
|
|
value: XSLTNode.attribute(node, "value"),
|
|
format: XSLTNode.attribute(node, "format") ?? "1",
|
|
groupingSeparator: XSLTNode.attribute(node, "grouping-separator"),
|
|
groupingSize: XSLTNode.attribute(node, "grouping-size").flatMap { Int($0) },
|
|
))
|
|
case "comment":
|
|
.comment(body: body(node))
|
|
case "processing-instruction":
|
|
.processingInstruction(name: valueTemplate(XSLTNode.attribute(node, "name") ?? ""), body: body(node))
|
|
default:
|
|
nil
|
|
}
|
|
}
|
|
|
|
/// The namespace bindings in scope at a stylesheet node, for resolving
|
|
/// the prefix of a created name (7.1.2/7.1.3: the QName in a name
|
|
/// attribute is expanded using the instruction's own declarations).
|
|
static func inScopeNamespaces(_ node: XSLTTree) -> [String: String] {
|
|
var bindings: [String: String] = [:]
|
|
var current: XSLTTree? = node
|
|
while let candidate = current {
|
|
for attribute in candidate.attributes where attribute.name.prefix == "xmlns" {
|
|
if bindings[attribute.name.localName] == nil {
|
|
bindings[attribute.name.localName] = attribute.value
|
|
}
|
|
}
|
|
current = candidate.parent
|
|
}
|
|
return bindings
|
|
}
|
|
}
|