Skip to content

Escape whitespace characters that XML parsers normalize - #140

Merged
zhengchun merged 1 commit into
antchfx:masterfrom
Shaisolaris:escape-whitespace-chars
Oct 14, 2026
Merged

zhengchun merged 1 commit into
antchfx:masterfrom
Shaisolaris:escape-whitespace-chars

Conversation

@Shaisolaris

Copy link
Copy Markdown
Contributor

OutputXML passes text and attribute values through html.EscapeString, which leaves tabs, newlines and carriage returns as they are. Parsers rewrite some of those raw characters, so the output no longer holds the same values when read back:

doc, _ := xmlquery.Parse(strings.NewReader(`<a x="tab&#9;nl&#10;cr&#13;end">one&#13;two</a>`))
fmt.Print(doc.OutputXML(true))
// <?xml version="1.0"?><a x="tab<TAB>nl<LF>cr<CR>end">one<CR>two</a>
  • Reading that output with xmlquery again, x comes back as "tab\tnl\ncr\nend" and the text as "one\ntwo", because the carriage returns are read as newlines.
  • lxml (libxml2) also applies attribute-value normalization, so it reads x as "tab nl cr end".

This change writes \r in text as &#13;, and \t, \n and \r in attribute values as &#9;, &#10; and &#13;. Everything html.EscapeString already escaped is unchanged, and newlines and tabs in text are still written raw, since they survive parsing.

Testing: TestOutputXMLKeepsWhitespaceCharacters parses the document above, writes it with OutputXML, parses it again, and compares the attribute and the text. It fails on master (both values differ) and passes with the change. go test . passes, and so does go vet .. I also checked the before and after output with lxml, which reads back the original values only after the change. I only ran this on Go 1.25.

OutputXML wrote carriage returns in text, and tabs, newlines and
carriage returns in attribute values, as raw characters. An XML parser
reads a raw carriage return back as a newline, and a conforming parser
reads a raw tab or newline in an attribute value as a space, so the
document no longer held the same values after a round trip.

Write them as character references instead.
@zhengchun
zhengchun merged commit de4185a into antchfx:master Oct 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants