Merge: XSLT xsl:fallback (#81)
This commit is contained in:
commit
618bf170c8
@ -9,6 +9,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Added
|
||||
|
||||
- XSLT `xsl:fallback` (#81). An unrecognized XSLT element instantiates its
|
||||
`xsl:fallback` children in its place (forwards-compatible processing), or is
|
||||
dropped when it has none; a fallback under a supported instruction is ignored.
|
||||
- XSLT `xsl:apply-imports` (#81). Re-applies templates to the current node in the
|
||||
current mode, considering only templates of lower import precedence than the
|
||||
one being instantiated (so an overriding template can extend the imported one),
|
||||
|
||||
@ -67,6 +67,9 @@ public extension PureXML.XSLT {
|
||||
/// `xsl:apply-imports`: re-applies templates to the current node, in the
|
||||
/// current mode, considering only templates of lower import precedence.
|
||||
case applyImports
|
||||
/// The `xsl:fallback` content of an unrecognized XSLT element, instantiated
|
||||
/// in its place under forwards-compatible processing.
|
||||
case fallback(body: [Instruction])
|
||||
}
|
||||
|
||||
/// The `xsl:output` controls that shape serialization: the output method, and
|
||||
|
||||
@ -225,7 +225,11 @@ extension PureXML.XSLT {
|
||||
}
|
||||
|
||||
private static func xslInstruction(_ node: Tree) -> Instruction? {
|
||||
simpleInstruction(node) ?? structuralInstruction(node)
|
||||
if let known = simpleInstruction(node) ?? structuralInstruction(node) { return known }
|
||||
// An unrecognized XSLT element instantiates its xsl:fallback children
|
||||
// (forwards-compatible processing); with none, it is dropped.
|
||||
let fallback = XSLTNode.children(node, named: "fallback").flatMap(body)
|
||||
return fallback.isEmpty ? nil : .fallback(body: fallback)
|
||||
}
|
||||
|
||||
private static func simpleInstruction(_ node: Tree) -> Instruction? {
|
||||
|
||||
@ -121,9 +121,12 @@ extension PureXML.XSLT {
|
||||
var context = context
|
||||
for instruction in body {
|
||||
if termination.message != nil { break }
|
||||
if case let .variable(name, select, varBody) = instruction {
|
||||
switch instruction {
|
||||
case let .variable(name, select, varBody):
|
||||
context.variables[name] = variableValue(select, varBody, context)
|
||||
} else {
|
||||
case let .fallback(fallbackBody):
|
||||
items += instantiate(fallbackBody, context)
|
||||
default:
|
||||
items += evaluate(instruction, context)
|
||||
}
|
||||
}
|
||||
|
||||
44
Tests/XSLTFallbackTests.swift
Normal file
44
Tests/XSLTFallbackTests.swift
Normal file
@ -0,0 +1,44 @@
|
||||
@testable import PureXML
|
||||
import Testing
|
||||
|
||||
@Suite("XSLT xsl:fallback")
|
||||
struct XSLTFallbackTests {
|
||||
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)
|
||||
}
|
||||
|
||||
private func wrap(_ templateBody: String) -> String {
|
||||
"""
|
||||
<xsl:stylesheet version="1.0" \(xsl)>
|
||||
<xsl:output method="xml" omit-xml-declaration="yes"/>
|
||||
<xsl:template match="/"><out>\(templateBody)</out></xsl:template>
|
||||
</xsl:stylesheet>
|
||||
"""
|
||||
}
|
||||
|
||||
@Test("An unknown XSLT element instantiates its xsl:fallback")
|
||||
func test_unknownWithFallback() throws {
|
||||
let style = wrap("<xsl:future-thing><xsl:fallback>fb</xsl:fallback></xsl:future-thing>")
|
||||
#expect(try transform(style, "<x/>") == "<out>fb</out>")
|
||||
}
|
||||
|
||||
@Test("An unknown XSLT element with no fallback is dropped")
|
||||
func test_unknownNoFallback() throws {
|
||||
let style = wrap("<xsl:future-thing/>kept")
|
||||
#expect(try transform(style, "<x/>") == "<out>kept</out>")
|
||||
}
|
||||
|
||||
@Test("xsl:fallback under a supported instruction is ignored")
|
||||
func test_fallbackUnderSupported() throws {
|
||||
let style = wrap("<xsl:fallback>ignored</xsl:fallback>kept")
|
||||
#expect(try transform(style, "<x/>") == "<out>kept</out>")
|
||||
}
|
||||
|
||||
@Test("Fallback content may itself be an instruction sequence")
|
||||
func test_fallbackSequence() throws {
|
||||
let style = wrap("<xsl:future-thing><xsl:fallback><a/><xsl:value-of select=\"r/@v\"/></xsl:fallback></xsl:future-thing>")
|
||||
#expect(try transform(style, "<r v=\"7\"/>") == "<out><a/>7</out>")
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user