PureXML/Tests/XSLTDocumentFunctionTests.swift
Mihaela Mihaljevic 7c24ada92b feat(xslt): document() fragments and base-URI resolution, completing #82
A document() reference with a #fragment selects a subset of the loaded
document via XPointer; a node-set first argument unions the documents
named by each node's string value; and a relative URI is resolved against
a caller-supplied baseURI (the loader is wrapped so xsl:include/xsl:import
resolve the same way). Closes the XSLT function/output audit.
2026-06-09 03:12:49 +02:00

74 lines
3.0 KiB
Swift

@testable import PureXML
import Testing
@Suite("XSLT document() fragments and base-URI resolution")
struct XSLTDocumentFunctionTests {
private let xsl = "xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\""
private func transform(_ stylesheet: String, _ source: String, baseURI: String = "", loader: @escaping (String) -> String?) throws -> String {
try PureXML.XSLT.transform(stylesheet: stylesheet, source: source, documentLoader: loader, baseURI: baseURI)
}
private let external = "<doc><section id=\"s1\">first</section><section id=\"s2\">second</section></doc>"
@Test("document() with no fragment loads the whole document")
func test_wholeDocument() throws {
let style = """
<xsl:stylesheet version="1.0" \(xsl)>
<xsl:output method="text"/>
<xsl:template match="/"><xsl:value-of select="count(document('ext.xml')//section)"/></xsl:template>
</xsl:stylesheet>
"""
let out = try transform(style, "<x/>") { $0 == "ext.xml" ? external : nil }
#expect(out == "2")
}
@Test("document() with an xpointer fragment selects a subset")
func test_xpointerFragment() throws {
let style = """
<xsl:stylesheet version="1.0" \(xsl)>
<xsl:output method="text"/>
<xsl:template match="/"><xsl:value-of select="document('ext.xml#xpointer(/doc/section[2])')"/></xsl:template>
</xsl:stylesheet>
"""
let out = try transform(style, "<x/>") { $0 == "ext.xml" ? external : nil }
#expect(out == "second")
}
@Test("A relative document() URI is resolved against the base URI")
func test_baseURI() throws {
let style = """
<xsl:stylesheet version="1.0" \(xsl)>
<xsl:output method="text"/>
<xsl:template match="/"><xsl:value-of select="count(document('ext.xml')//section)"/></xsl:template>
</xsl:stylesheet>
"""
var requested: [String] = []
let out = try transform(style, "<x/>", baseURI: "http://example.org/docs/") { uri in
requested.append(uri)
return uri == "http://example.org/docs/ext.xml" ? external : nil
}
#expect(out == "2")
#expect(requested.contains("http://example.org/docs/ext.xml"))
}
@Test("document() with a node-set argument unions the loaded documents")
func test_nodeSetArgument() throws {
let style = """
<xsl:stylesheet version="1.0" \(xsl)>
<xsl:output method="text"/>
<xsl:template match="/"><xsl:value-of select="count(document(//ref)//section)"/></xsl:template>
</xsl:stylesheet>
"""
let source = "<x><ref>a.xml</ref><ref>b.xml</ref></x>"
let out = try transform(style, source) { uri in
switch uri {
case "a.xml": "<doc><section>1</section></doc>"
case "b.xml": "<doc><section>2</section><section>3</section></doc>"
default: nil
}
}
#expect(out == "3")
}
}