diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go index b8bce7170a..acfe36083f 100644 --- a/src/encoding/xml/marshal_test.go +++ b/src/encoding/xml/marshal_test.go @@ -602,6 +602,12 @@ var marshalTests = []struct { ExpectXML: ``, UnmarshalOnly: true, }, + // Check attribute value normalization (issue 20614). + { + Value: &Data{Bytes: []byte{}, Custom: MyBytes{}, Attr: []byte(" a b c d")}, + ExpectXML: "", + UnmarshalOnly: true, + }, // Check that []byte works, including named []byte types. { diff --git a/src/encoding/xml/xml.go b/src/encoding/xml/xml.go index 951676d403..63ae2beef6 100644 --- a/src/encoding/xml/xml.go +++ b/src/encoding/xml/xml.go @@ -1119,11 +1119,17 @@ Input: return nil } - // We must rewrite unescaped \r and \r\n into \n. - if b == '\r' { - d.buf.WriteByte('\n') + // We must rewrite unescaped \r and \r\n into \n outside quotes, + // and unescaped \r, \r\n, \n, and \t into space inside quotes. + if b >= ' ' { + d.buf.WriteByte(b) } else if b1 == '\r' && b == '\n' { // Skip \r\n--we already wrote \n. + } else if quote >= 0 && (b == '\r' || b == '\n' || b == '\t') { + // Normalize newline, CR, and tab into space + d.buf.WriteByte(' ') + } else if b == '\r' { + d.buf.WriteByte('\n') } else { d.buf.WriteByte(b) } diff --git a/src/encoding/xml/xml_test.go b/src/encoding/xml/xml_test.go index 10cefa068f..2ac53140a5 100644 --- a/src/encoding/xml/xml_test.go +++ b/src/encoding/xml/xml_test.go @@ -650,6 +650,30 @@ func TestIssue68387(t *testing.T) { } } +func TestIssue20614(t *testing.T) { + data := "" + dec := NewDecoder(strings.NewReader(data)) + var tok1, tok2, tok3 Token + var err error + if tok1, err = dec.RawToken(); err != nil { + t.Fatalf("RawToken() failed: %#v", err) + } + if tok2, err = dec.RawToken(); err != nil { + t.Fatalf("RawToken() failed: %#v", err) + } + if tok3, err = dec.RawToken(); err != io.EOF || tok3 != nil { + t.Fatalf("Missed EOF") + } + s := StartElement{Name{"", "item"}, []Attr{Attr{Name{"","b"}, " "}}} + if !reflect.DeepEqual(tok1.(StartElement), s) { + t.Error("Wrong start element") + } + e := EndElement{Name{"","item"}} + if tok2.(EndElement) != e { + t.Error("Wrong end element") + } +} + func TestIssue569(t *testing.T) { data := `abcd` var i item