PureXML/Tests/XSLTWhitespaceTests.swift
Mihaela Mihaljevic 10d9525e3e feat(xslt): implement xsl:strip-space and xsl:preserve-space
Whitespace-only text nodes are removed from the source tree for elements
named by strip-space before transformation, with preserve-space and a
more specific name test winning over *, and xml:space=preserve on a
source element or ancestor overriding the stripping. The name sets fold
across xsl:include/xsl:import. Refactors the stylesheet compile loop
through a Parts accumulator to absorb the new top-level elements within
the complexity budget.
2026-06-09 01:22:59 +02:00

68 lines
2.7 KiB
Swift

@testable import PureXML
import Testing
@Suite("XSLT strip-space / preserve-space")
struct XSLTWhitespaceTests {
private let xsl = "xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\""
private func transform(_ stylesheet: String, _ source: String) throws -> String {
try PureXML.XSLT.transform(stylesheet: stylesheet, source: source)
}
@Test("strip-space removes whitespace-only text nodes; a copy reflects it")
func test_stripSpace() throws {
let style = """
<xsl:stylesheet version="1.0" \(xsl)>
<xsl:strip-space elements="a"/>
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/"><xsl:copy-of select="a"/></xsl:template>
</xsl:stylesheet>
"""
let source = "<a>\n <b/>\n <b/>\n</a>"
// The indentation whitespace between <b/> elements is stripped.
#expect(try transform(style, source) == "<a><b/><b/></a>")
}
@Test("Without strip-space the whitespace is preserved")
func test_noStrip() throws {
let style = """
<xsl:stylesheet version="1.0" \(xsl)>
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/"><xsl:copy-of select="a"/></xsl:template>
</xsl:stylesheet>
"""
let source = "<a>\n <b/>\n</a>"
#expect(try transform(style, source).contains("\n "))
}
@Test("preserve-space overrides strip-space for a named element")
func test_preserveOverrides() throws {
let style = """
<xsl:stylesheet version="1.0" \(xsl)>
<xsl:strip-space elements="*"/>
<xsl:preserve-space elements="keep"/>
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/"><xsl:copy-of select="*"/></xsl:template>
</xsl:stylesheet>
"""
// strip-space="*" strips <drop>'s whitespace, but <keep> preserves its own.
let stripped = try transform(style, "<drop>\n <x/>\n</drop>")
#expect(stripped == "<drop><x/></drop>")
let kept = try transform(style, "<keep>\n <x/>\n</keep>")
#expect(kept.contains("\n "))
}
@Test("xml:space=preserve on a source element keeps its whitespace despite strip-space")
func test_xmlSpacePreserve() throws {
let style = """
<xsl:stylesheet version="1.0" \(xsl)>
<xsl:strip-space elements="a"/>
<xsl:output method="xml" omit-xml-declaration="yes"/>
<xsl:template match="/"><xsl:copy-of select="a"/></xsl:template>
</xsl:stylesheet>
"""
let source = "<a xml:space=\"preserve\">\n <b/>\n</a>"
#expect(try transform(style, source).contains("\n "))
}
}