test(xslt): decode non-UTF-8 conformance sources via the library's encoding detection (#261)
The Xalan harness read source and stylesheet files as UTF-8, so a UTF-16 source (output80) or other non-UTF-8 input (attribvaltemplate08) was refused as unreadable before the transform ran. Read them through PureXML's own ByteDecoder (BOM or XML-declaration detection, UTF-8 fallback), as the harness already does for gold files. The library round-trips them correctly, so both cases now pass. Closes Apache Xalan conformance cases output80 and attribvaltemplate08.
This commit is contained in:
parent
1ba6bf86e2
commit
c355daa00e
@ -52,6 +52,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
### Fixed
|
||||
|
||||
- The XSLT conformance harness now decodes source and stylesheet files through the library's own encoding detection (a BOM or the XML declaration) rather than assuming UTF-8, so a non-UTF-8 corpus input is fed to the transform instead of refused. This confirms the library round-trips a UTF-16 source correctly and closes Apache Xalan conformance cases `output80` (UTF-16) and `attribvaltemplate08`, which were unreadable by the harness, not library failures.
|
||||
|
||||
- The `html` output method now serializes an element whose expanded-name has a non-null namespace URI as XML rather than HTML (XSLT 1.0 16.2). When the result's document element is namespaced, the tree is serialized through the XML path (empty elements self-close, the namespace is declared once and inherited) while the html method still omits the XML declaration; previously such a tree was emitted as HTML, leaving empty namespaced elements unclosed and repeating the `xmlns` declaration on every element, which is not well-formed XML. A null-namespace tree is unchanged. The rule is applied at document-element granularity rather than per element, so a tree mixing null- and non-null-namespace elements follows its document element's path (the realistic result is all-null or all-namespaced). (Apache Xalan `output63` exercises this rule but remains baselined: its gold differs further only in attribute order, which is not normative.)
|
||||
|
||||
- The `html` output method now names the document type declaration `HTML` rather than the document element name (XSLT 1.0 16.2: "The name following the `<!DOCTYPE` should be HTML or html"). With `method="html"` and a `doctype-public` or `doctype-system`, the emitted declaration is `<!DOCTYPE HTML PUBLIC "...">` regardless of the result's root element; the `xml` method still uses the document element name (16.1). Closes Apache Xalan conformance cases `output40`, `output48`, and `output60`.
|
||||
|
||||
@ -2,7 +2,6 @@
|
||||
# one category/name per line, exact in both directions: a fixed case
|
||||
# must leave this list and a regression shows up as a new failure.
|
||||
attribset/attribset44
|
||||
attribvaltemplate/attribvaltemplate08
|
||||
axes/axes116
|
||||
conflictres/conflictres29
|
||||
conflictres/conflictres30
|
||||
@ -34,7 +33,6 @@ output/output70
|
||||
output/output72
|
||||
output/output73
|
||||
output/output75
|
||||
output/output80
|
||||
output/output86
|
||||
position/position106
|
||||
processorinfo/processorinfo03
|
||||
|
||||
@ -74,10 +74,21 @@ struct XalanConfSuiteTests {
|
||||
#expect(fixed.isEmpty, "\(fixed.count) baselined cases now pass (remove from xalan-baseline.txt): \(fixed.prefix(40))")
|
||||
}
|
||||
|
||||
/// Reads a file and decodes it through PureXML's own encoding detection (a
|
||||
/// BOM or the XML declaration), falling back to UTF-8, so a non-UTF-8 source
|
||||
/// is decoded rather than refused. nil when the file is missing.
|
||||
private static func decodeFile(_ path: String) -> String? {
|
||||
guard let data = FileManager.default.contents(atPath: path) else { return nil }
|
||||
return (try? PureXML.Parsing.ByteDecoder.decode([UInt8](data))) ?? String(data: data, encoding: .utf8)
|
||||
}
|
||||
|
||||
private func runCase(category: String, name: String, root: String, goldPath: String) -> String? {
|
||||
let directory = root + "/conf/" + category
|
||||
guard let stylesheet = try? String(contentsOfFile: directory + "/" + name + ".xsl", encoding: .utf8),
|
||||
let source = try? String(contentsOfFile: directory + "/" + name + ".xml", encoding: .utf8)
|
||||
// Decode inputs the way PureXML decodes any document, by detecting the
|
||||
// encoding (a BOM or the XML declaration) rather than assuming UTF-8, so
|
||||
// a UTF-16 or other non-UTF-8 source is fed to the transform, not refused.
|
||||
guard let stylesheet = Self.decodeFile(directory + "/" + name + ".xsl"),
|
||||
let source = Self.decodeFile(directory + "/" + name + ".xml")
|
||||
else {
|
||||
return "unreadable inputs"
|
||||
}
|
||||
@ -86,9 +97,7 @@ struct XalanConfSuiteTests {
|
||||
else {
|
||||
return "unreadable gold"
|
||||
}
|
||||
let loader: (String) -> String? = { uri in
|
||||
(try? String(contentsOfFile: directory + "/" + uri, encoding: .utf8))
|
||||
}
|
||||
let loader: (String) -> String? = { uri in Self.decodeFile(directory + "/" + uri) }
|
||||
let actual: String
|
||||
do {
|
||||
actual = try PureXML.XSLT.transform(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user