mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
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
This commit is contained in:
parent
9622f5032e
commit
a9121a19f0
4 changed files with 59 additions and 11 deletions
|
|
@ -273,7 +273,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
|
||||||
s := parentStack{printer: p}
|
s := parentStack{printer: p}
|
||||||
for i := range tinfo.fields {
|
for i := range tinfo.fields {
|
||||||
finfo := &tinfo.fields[i]
|
finfo := &tinfo.fields[i]
|
||||||
if finfo.flags&(fAttr|fAny) != 0 {
|
if finfo.flags&(fAttr) != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
vf := finfo.value(val)
|
vf := finfo.value(val)
|
||||||
|
|
@ -340,7 +340,7 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
case fElement:
|
case fElement, fElement | fAny:
|
||||||
s.trim(finfo.parents)
|
s.trim(finfo.parents)
|
||||||
if len(finfo.parents) > len(s.stack) {
|
if len(finfo.parents) > len(s.stack) {
|
||||||
if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() {
|
if vf.Kind() != reflect.Ptr && vf.Kind() != reflect.Interface || !vf.IsNil() {
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,18 @@ type AnyTest struct {
|
||||||
AnyField AnyHolder `xml:",any"`
|
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 {
|
type AnyHolder struct {
|
||||||
XMLName Name
|
XMLName Name
|
||||||
XML string `xml:",innerxml"`
|
XML string `xml:",innerxml"`
|
||||||
|
|
@ -652,12 +664,43 @@ var marshalTests = []struct {
|
||||||
XML: "<sub>unknown</sub>",
|
XML: "<sub>unknown</sub>",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
UnmarshalOnly: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Value: &AnyTest{Nested: "known", AnyField: AnyHolder{XML: "<unknown/>"}},
|
Value: &AnyTest{Nested: "known",
|
||||||
ExpectXML: `<a><nested><value>known</value></nested></a>`,
|
AnyField: AnyHolder{
|
||||||
MarshalOnly: true,
|
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.
|
// Test recursive types.
|
||||||
|
|
@ -690,15 +733,17 @@ var marshalTests = []struct {
|
||||||
|
|
||||||
// Test escaping.
|
// Test escaping.
|
||||||
{
|
{
|
||||||
ExpectXML: `<a><nested><value>dquote: "; squote: '; ampersand: &; less: <; greater: >;</value></nested></a>`,
|
ExpectXML: `<a><nested><value>dquote: "; squote: '; ampersand: &; less: <; greater: >;</value></nested><empty></empty></a>`,
|
||||||
Value: &AnyTest{
|
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: 
; cr: 
; tab: 	;</value></nested></a>`,
|
ExpectXML: `<a><nested><value>newline: 
; cr: 
; tab: 	;</value></nested><AnyField></AnyField></a>`,
|
||||||
Value: &AnyTest{
|
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)
|
saveComment = finfo.value(sv)
|
||||||
}
|
}
|
||||||
|
|
||||||
case fAny:
|
case fAny, fAny | fElement:
|
||||||
if !saveAny.IsValid() {
|
if !saveAny.IsValid() {
|
||||||
saveAny = finfo.value(sv)
|
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.
|
// This will also catch multiple modes in a single field.
|
||||||
valid = false
|
valid = false
|
||||||
}
|
}
|
||||||
|
if finfo.flags&fMode == fAny {
|
||||||
|
finfo.flags |= fElement
|
||||||
|
}
|
||||||
if finfo.flags&fOmitEmpty != 0 && finfo.flags&(fElement|fAttr) == 0 {
|
if finfo.flags&fOmitEmpty != 0 && finfo.flags&(fElement|fAttr) == 0 {
|
||||||
valid = false
|
valid = false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue