Commit a9121a19 authored by Chris Jones's avatar Chris Jones Committed by Russ Cox

encoding/xml: Marshal ",any" fields

Fixes #3559.

This makes Marshal handle fields marked ",any" instead of ignoring
them. That makes Marshal more symmetrical with Unmarshal, which seems
to have been a design goal.

Note some test cases were changed, because this patch changes
marshalling behavior. I think the previous behavior was buggy, but
there's still a backward-compatibility question to consider.

R=rsc
CC=golang-dev, n13m3y3r
https://golang.org/cl/6938068
parent 9622f503
......@@ -273,7 +273,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
s := parentStack{printer: p}
for i := range tinfo.fields {
finfo := &tinfo.fields[i]
if finfo.flags&(fAttr|fAny) != 0 {
if finfo.flags&(fAttr) != 0 {
continue
}
vf := finfo.value(val)
......@@ -340,7 +340,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
continue
}
case fElement:
case fElement, fElement | fAny:
s.trim(finfo.parents)
if len(finfo.parents) > len(s.stack) {
if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() {
......
......@@ -188,6 +188,18 @@ type AnyTest struct {
AnyField AnyHolder `xml:",any"`
}
type AnyOmitTest struct {
XMLName struct{} `xml:"a"`
Nested string `xml:"nested>value"`
AnyField *AnyHolder `xml:",any,omitempty"`
}
type AnySliceTest struct {
XMLName struct{} `xml:"a"`
Nested string `xml:"nested>value"`
AnyField []AnyHolder `xml:",any"`
}
type AnyHolder struct {
XMLName Name
XML string `xml:",innerxml"`
......@@ -652,12 +664,43 @@ var marshalTests = []struct {
XML: "<sub>unknown</sub>",
},
},
UnmarshalOnly: true,
},
{
Value: &AnyTest{Nested: "known", AnyField: AnyHolder{XML: "<unknown/>"}},
ExpectXML: `<a><nested><value>known</value></nested></a>`,
MarshalOnly: true,
Value: &AnyTest{Nested: "known",
AnyField: AnyHolder{
XML: "<unknown/>",
XMLName: Name{Local: "AnyField"},
},
},
ExpectXML: `<a><nested><value>known</value></nested><AnyField><unknown/></AnyField></a>`,
},
{
ExpectXML: `<a><nested><value>b</value></nested></a>`,
Value: &AnyOmitTest{
Nested: "b",
},
},
{
ExpectXML: `<a><nested><value>b</value></nested><c><d>e</d></c><g xmlns="f"><h>i</h></g></a>`,
Value: &AnySliceTest{
Nested: "b",
AnyField: []AnyHolder{
{
XMLName: Name{Local: "c"},
XML: "<d>e</d>",
},
{
XMLName: Name{Space: "f", Local: "g"},
XML: "<h>i</h>",
},
},
},
},
{
ExpectXML: `<a><nested><value>b</value></nested></a>`,
Value: &AnySliceTest{
Nested: "b",
},
},
// Test recursive types.
......@@ -690,15 +733,17 @@ var marshalTests = []struct {
// Test escaping.
{
ExpectXML: `<a><nested><value>dquote: &#34;; squote: &#39;; ampersand: &amp;; less: &lt;; greater: &gt;;</value></nested></a>`,
ExpectXML: `<a><nested><value>dquote: &#34;; squote: &#39;; ampersand: &amp;; less: &lt;; greater: &gt;;</value></nested><empty></empty></a>`,
Value: &AnyTest{
Nested: `dquote: "; squote: '; ampersand: &; less: <; greater: >;`,
Nested: `dquote: "; squote: '; ampersand: &; less: <; greater: >;`,
AnyField: AnyHolder{XMLName: Name{Local: "empty"}},
},
},
{
ExpectXML: `<a><nested><value>newline: &#xA;; cr: &#xD;; tab: &#x9;;</value></nested></a>`,
ExpectXML: `<a><nested><value>newline: &#xA;; cr: &#xD;; tab: &#x9;;</value></nested><AnyField></AnyField></a>`,
Value: &AnyTest{
Nested: "newline: \n; cr: \r; tab: \t;",
Nested: "newline: \n; cr: \r; tab: \t;",
AnyField: AnyHolder{XMLName: Name{Local: "AnyField"}},
},
},
{
......
......@@ -279,7 +279,7 @@ func (p *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
saveComment = finfo.value(sv)
}
case fAny:
case fAny, fAny | fElement:
if !saveAny.IsValid() {
saveAny = finfo.value(sv)
}
......
......@@ -154,6 +154,9 @@ func structFieldInfo(typ reflect.Type, f *reflect.StructField) (*fieldInfo, erro
// This will also catch multiple modes in a single field.
valid = false
}
if finfo.flags&fMode == fAny {
finfo.flags |= fElement
}
if finfo.flags&fOmitEmpty != 0 && finfo.flags&(fElement|fAttr) == 0 {
valid = false
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment