Few of the XML tags are not getting decoded while reading the request body
I have defined my nested struct with both json and xml tags, as I want to use the same schema for request and response in both json and xml.
var dataNewTestplans DataTestplan
err := xml.NewDecoder(r.Body).Decode(&dataNewTestplans)
xmlData, _ := xml.Marshal(dataNewTestplans)
fmt.Printf(string(xmlData))
DataTestplan struct:
type DataTestplan struct {
Data []Testplan `json:"data" xml:"data"`
}
Testplan struct:
type Testplan struct {
Group string `json:"group" xml:"group"`
Name string `json:"name" xml:"name"`
Parameters []Parameter `json:"parameters,omitempty" xml:"parameters,omitempty"`
Released bool `json:"released" xml:"released"`
Teststeps []Teststep `json:"teststeps,omitempty" xml:"teststeps,omitempty"`
Version int32 `json:"version" xml:"version"`
}
Parameter struct:
type Parameter struct {
XMLName xml.Name `xml:"parameters"`
Comment string `json:"comment" xml:"comment"`
Description string `json:"description,omitempty" xml:"description,omitempty"`
}
Teststep struct:
type Teststep struct {
XMLName xml.Name `xml:"teststeps"`
AslID string `json:"aslId,omitempty" xml:"aslID"`
Bin int32 `json:"bin,omitempty" xml:"bin"`
}
XML sent :
<root>
<data>
<element>
<group>TEST</group>
<name>TEST</name>
<parameters>
<element>
<comment>test</comment>
<description>test</description>
</element>
<element>
<comment>test1</comment>
</element>
</parameters>
<released>true</released>
<teststeps>
<element>
<bin>32</bin>
</element>
</teststeps>
<version>1</version>
</element>
</data>
</root>
XML decoded:
<DataTestplan>
<data>
<group></group>
<name></name>
<released>false</released>
<version>0</version>
</data>
</DataTestplan>
I understand missing tags are most probably because of miss tagging of xml in the struct definition but I am not sure why the decoded information is missing value for tags ? What's the trick with XML and JSON encoding ?
You can use >
in the tags.
https://golang.org/pkg/encoding/xml/#Unmarshal
If the XML element contains a sub-element whose name matches the prefix of a tag formatted as "a" or "a>b>c", unmarshal will descend into the XML structure looking for elements with the given names, and will map the innermost elements to that struct field. A tag starting with ">" is equivalent to one starting with the field name followed by ">".
https://golang.org/pkg/encoding/xml/#Marshal
If a field uses a tag "a>b>c", then the element c will be nested inside parent elements a and b. Fields that appear next to each other that name the same parent will be enclosed in one XML element.
For example:
type DataTestplan struct {
Data []Testplan `json:"data" xml:"data>element"`
}
There is no need to create a different struct for each tag. You can embed them all in one. For the xml parsing you are missing a few tags. You can avoid some code replication by using the >
in the xml tag. This will effectively "merge" two elements when you iterate them. Here is an example on a more concise implementation:
type Root struct {
XMLName xml.Name `xml:"root"`
Data []struct {
Group string `json:"group" xml:"group"`
Name string `json:"name" xml:"name"`
Parameters []struct {
Comment string `json:"comment" xml:"comment,omitempty"`
Description string `json:"description" xml:"description,omitempty"`
} `json:"parameters" xml:"parameters>element"`
Released bool `json:"released" xml:"released"`
Teststeps []struct {
Bin int32 `json:"bin" xml:"bin"`
} `xml:"teststeps>element,omitempty"`
Version int32 `json:"version" xml:"version"`
} `json:"data" xml:"data>element"`
}
By running:
var dataNewTestplans DataTestplan
err := xml.NewDecoder(r.Body).Decode(&dataNewTestplans)
xmlData, _ := xml.Marshal(dataNewTestplans)
fmt.Printf(string(xmlData))
you get:
<root><data><element><group>TEST</group><name>TEST</name><parameters><element><comment>test</comment><description>test</description></element><element><comment>test1</comment></element></parameters><released>true</released><teststeps><element><bin>32</bin></element></teststeps><version>1</version></element></data></root>