XSLT: template selection resolves each match pattern once per transform via a per-run MatchCache (the pattern's node set is computed once over the source tree; selection becomes an identity lookup), replacing per-(node, template) recompilation and full-tree re-walks. XSD identity validation: a per-run query cache compiles each selector/field XPath once instead of at every visited element. Schematron was verified to already store compiled queries. Behavior unchanged (all suites green); a multi-template shape test over 300 nodes guards the optimized path. MatchCache lives in its own file to keep the transformer under the length cap. Closes #112
27 lines
1.2 KiB
Swift
27 lines
1.2 KiB
Swift
extension PureXML.XSLT {
|
|
/// Caches, per transform, the node set each match pattern selects over the
|
|
/// source tree, so a pattern is compiled and evaluated once per document
|
|
/// rather than once per (node, template) pair during template selection.
|
|
final class MatchCache {
|
|
private var matched: [String: Set<ObjectIdentifier>] = [:]
|
|
|
|
/// The identities of the nodes `pattern` selects over `root`, computed and
|
|
/// cached on first use. A branch that fails to compile selects nothing.
|
|
func nodes(matching pattern: String, over root: PureXML.Model.TreeNode) -> Set<ObjectIdentifier> {
|
|
if let cached = matched[pattern] { return cached }
|
|
var result: Set<ObjectIdentifier> = []
|
|
for branch in pattern.split(separator: "|") {
|
|
let trimmed = branch.trimmingXMLWhitespace()
|
|
let path = trimmed.hasPrefix("/") ? trimmed : "//" + trimmed
|
|
if let query = try? PureXML.XPath.Query(path) {
|
|
for node in query.nodes(over: root) {
|
|
result.insert(ObjectIdentifier(node))
|
|
}
|
|
}
|
|
}
|
|
matched[pattern] = result
|
|
return result
|
|
}
|
|
}
|
|
}
|