The six worked examples of the C14N 1.0 Recommendation's section 3 run as input/expected-output tests. They exposed and fixed: top-level siblings now separated by single line feeds in the canonical form; superfluous empty default-namespace declarations dropped in inclusive mode (xmlns="" renders only when undeclaring a rendered non-empty default); and scalar-level escape loops, so a CR clustered with a following LF still escapes to 
. Escaping split to its own file for the length caps. Closes #132
40 lines
1.4 KiB
Swift
40 lines
1.4 KiB
Swift
/// The C14N escaping rules, split from the canonicalizer body to keep it
|
|
/// under the length caps: text escapes & < > and CR; attribute values escape
|
|
/// & < " TAB LF CR. Both iterate Unicode scalars so a CR that clustered with
|
|
/// a following LF is still escaped.
|
|
extension PureXML.Canonical.Canonicalizer {
|
|
// MARK: Escaping
|
|
|
|
static func escapeText(_ value: String) -> String {
|
|
// Scalar-level: a CR that clustered with a following LF must still
|
|
// be escaped, so the loop cannot compare grapheme Characters.
|
|
var result = ""
|
|
for scalar in value.unicodeScalars {
|
|
switch scalar {
|
|
case "&": result += "&"
|
|
case "<": result += "<"
|
|
case ">": result += ">"
|
|
case "\r": result += "
"
|
|
default: result.unicodeScalars.append(scalar)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
static func escapeAttribute(_ value: String) -> String {
|
|
var result = ""
|
|
for scalar in value.unicodeScalars {
|
|
switch scalar {
|
|
case "&": result += "&"
|
|
case "<": result += "<"
|
|
case "\"": result += """
|
|
case "\t": result += "	"
|
|
case "\n": result += "
"
|
|
case "\r": result += "
"
|
|
default: result.unicodeScalars.append(scalar)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
}
|