PureXML/Sources/XSLT/XSLTDocumentCache.swift
Mihaela Mihaljevic cff26b255d feat(xslt): attribute-set merging, copied namespaces, html booleans, loader entities
Same-name xsl:attribute-set declarations merge as ordered definitions
per 7.1.4, each expanding its used sets before its own attributes with
later definitions winning; xsl:copy carries the source element's
in-scope namespace nodes per 7.5; the namespace fixup lets a carried
attribute prefix shadow an inherited binding unless the element's own
name relies on it; the html method minimizes boolean attributes whose
value repeats their name; and external DTDs and entities in the
stylesheet or source resolve through the transform's document loader.
Four unit tests pin the behaviors. Xalan baseline 174 -> 159
(attribset 13 -> 4, copy 12 -> 7).
2026-06-10 16:11:02 +02:00

34 lines
1.4 KiB
Swift

extension PureXML.XSLT {
/// Wraps a transform's document loader as an entity resolver, so external
/// DTDs and entities referenced by the stylesheet or source resolve
/// through the same channel as document(). The loader is used from a
/// single thread for the duration of one parse.
static func loaderResolver(_ loader: @escaping (String) -> String?) -> PureXML.Parsing.EntityResolver {
let box = LoaderBox(load: loader)
return PureXML.Parsing.EntityResolver(
resolveEntity: { _, id in box.load(id.resolvedSystemID) },
resolveExternalSubset: { id in box.load(id.resolvedSystemID) },
)
}
/// A single-threaded loader carried into the resolver's Sendable
/// closures; XSLT transforms are confined to one thread.
private struct LoaderBox: @unchecked Sendable {
let load: (String) -> String?
}
/// The key indexes a transform has built, one per document root.
final class KeyIndexCache {
var indexes: [ObjectIdentifier: KeyIndex] = [:]
}
/// The documents a transform has loaded, keyed by URI: per the XSLT
/// `document()` definition the same reference returns the identical
/// document, so node identity (and `generate-id()`) is stable across
/// calls within one transform.
final class DocumentCache {
var trees: [String: PureXML.Model.TreeNode] = [:]
var sources: [String: PureXML.Model.Node] = [:]
}
}