mirror of
https://github.com/golang/go
synced 2024-11-13 18:20:32 -07:00
encoding/xml: fix to allow xml declaration with EncodeToken
This changes allows the first token encoded to be a xml declaration. A ProcInst with target of xml. Any other ProcInst after that with a target of xml will fail Fixes #7380. LGTM=rsc R=golang-codereviews, rsc CC=golang-codereviews https://golang.org/cl/72410043
This commit is contained in:
parent
f16ee08ba8
commit
92440fb5bd
@ -184,10 +184,12 @@ var (
|
|||||||
// EncodeToken does not call Flush, because usually it is part of a larger operation
|
// EncodeToken does not call Flush, because usually it is part of a larger operation
|
||||||
// such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
|
// such as Encode or EncodeElement (or a custom Marshaler's MarshalXML invoked
|
||||||
// during those), and those will call Flush when finished.
|
// during those), and those will call Flush when finished.
|
||||||
//
|
|
||||||
// Callers that create an Encoder and then invoke EncodeToken directly, without
|
// Callers that create an Encoder and then invoke EncodeToken directly, without
|
||||||
// using Encode or EncodeElement, need to call Flush when finished to ensure
|
// using Encode or EncodeElement, need to call Flush when finished to ensure
|
||||||
// that the XML is written to the underlying writer.
|
// that the XML is written to the underlying writer.
|
||||||
|
//
|
||||||
|
// EncodeToken allows writing a ProcInst with Target set to "xml" only as the first token
|
||||||
|
// in the stream.
|
||||||
func (enc *Encoder) EncodeToken(t Token) error {
|
func (enc *Encoder) EncodeToken(t Token) error {
|
||||||
p := &enc.p
|
p := &enc.p
|
||||||
switch t := t.(type) {
|
switch t := t.(type) {
|
||||||
@ -210,7 +212,12 @@ func (enc *Encoder) EncodeToken(t Token) error {
|
|||||||
p.WriteString("-->")
|
p.WriteString("-->")
|
||||||
return p.cachedWriteError()
|
return p.cachedWriteError()
|
||||||
case ProcInst:
|
case ProcInst:
|
||||||
if t.Target == "xml" || !isNameString(t.Target) {
|
// First token to be encoded which is also a ProcInst with target of xml
|
||||||
|
// is the xml declaration. The only ProcInst where target of xml is allowed.
|
||||||
|
if t.Target == "xml" && p.Buffered() != 0 {
|
||||||
|
return fmt.Errorf("xml: EncodeToken of ProcInst xml target only valid for xml declaration, first token encoded")
|
||||||
|
}
|
||||||
|
if !isNameString(t.Target) {
|
||||||
return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
|
return fmt.Errorf("xml: EncodeToken of ProcInst with invalid Target")
|
||||||
}
|
}
|
||||||
if bytes.Contains(t.Inst, endProcInst) {
|
if bytes.Contains(t.Inst, endProcInst) {
|
||||||
|
@ -1203,7 +1203,7 @@ var encodeTokenTests = []struct {
|
|||||||
{Comment("foo"), "<!--foo-->", true},
|
{Comment("foo"), "<!--foo-->", true},
|
||||||
{Comment("foo-->"), "", false},
|
{Comment("foo-->"), "", false},
|
||||||
{ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
|
{ProcInst{"Target", []byte("Instruction")}, "<?Target Instruction?>", true},
|
||||||
{ProcInst{"xml", []byte("Instruction")}, "", false},
|
{ProcInst{"", []byte("Instruction")}, "", false},
|
||||||
{ProcInst{"Target", []byte("Instruction?>")}, "", false},
|
{ProcInst{"Target", []byte("Instruction?>")}, "", false},
|
||||||
{Directive("foo"), "<!foo>", true},
|
{Directive("foo"), "<!foo>", true},
|
||||||
{Directive("foo>"), "", false},
|
{Directive("foo>"), "", false},
|
||||||
@ -1230,3 +1230,37 @@ func TestEncodeToken(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProcInstEncodeToken(t *testing.T) {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
enc := NewEncoder(&buf)
|
||||||
|
|
||||||
|
if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err != nil {
|
||||||
|
t.Fatalf("enc.EncodeToken: expected to be able to encode xml target ProcInst as first token, %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := enc.EncodeToken(ProcInst{"Target", []byte("Instruction")}); err != nil {
|
||||||
|
t.Fatalf("enc.EncodeToken: expected to be able to add non-xml target ProcInst")
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := enc.EncodeToken(ProcInst{"xml", []byte("Instruction")}); err == nil {
|
||||||
|
t.Fatalf("enc.EncodeToken: expected to not be allowed to encode xml target ProcInst when not first token")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDecodeEncode(t *testing.T) {
|
||||||
|
var in, out bytes.Buffer
|
||||||
|
in.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<?Target Instruction?>
|
||||||
|
<root>
|
||||||
|
</root>
|
||||||
|
`)
|
||||||
|
dec := NewDecoder(&in)
|
||||||
|
enc := NewEncoder(&out)
|
||||||
|
for tok, err := dec.Token(); err == nil; tok, err = dec.Token() {
|
||||||
|
err = enc.EncodeToken(tok)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("enc.EncodeToken: Unable to encode token (%#v), %d", tok, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user