Add PureXML.Emitting.Writer, the libxml2 xmlTextWriter model: emit a document with writeStartElement/writeAttribute/writeString/writeEndElement and friends, never building a tree. Escaping is extracted into a shared Emitting.Escaping helper used by both the writer and the serializer, so compact writer output is byte-identical to serializing the equivalent tree. Pretty mode indents element children (forward-only, so prefer compact for mixed content). Closes #32. Reimplemented from the libxml2 model; no upstream code copied. 6 tests; 90 total.
39 lines
1.4 KiB
Swift
39 lines
1.4 KiB
Swift
extension PureXML.Emitting {
|
|
/// The shared XML output escaping rules, used by both the tree serializer and
|
|
/// the incremental writer so their output is identical. Element content
|
|
/// escapes the markup characters; attribute values additionally escape the
|
|
/// quote and the whitespace characters as numeric references (matching
|
|
/// libxml2), so attributes survive attribute-value normalization.
|
|
enum Escaping {
|
|
static func text(_ value: String) -> String {
|
|
var result = ""
|
|
for character in value {
|
|
switch character {
|
|
case "&": result += "&"
|
|
case "<": result += "<"
|
|
case ">": result += ">"
|
|
default: result.append(character)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
static func attribute(_ value: String) -> String {
|
|
var result = ""
|
|
for character in value {
|
|
switch character {
|
|
case "&": result += "&"
|
|
case "<": result += "<"
|
|
case ">": result += ">"
|
|
case "\"": result += """
|
|
case "\t": result += "	"
|
|
case "\n": result += " "
|
|
case "\r": result += " "
|
|
default: result.append(character)
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
}
|