因此,我已经获得了xml(行业标准)的特定格式,并且我尝试创建一个简单的程序,以便我们可以对此xml进行测试以测试我们的服务。我正在使用标准的Go XML库。
问题是XML格式化了。 这是它的简化版本:
<Document>
<SubDocument>
{other fields}
<component>
<section>
<id value="0" valueType="num"/> //This is the part that differentiates the type of the section
<title>Foo-Type Section</title>
{other fields you lot don't need to care about}
</section>
</component>
<component>
<section>
<id value="1" valueType="num"/>
<title>Bar-Type Section</title>
{more fields you don't need to care about, but most are different than above}
</section>
</component>
{more sections}
</SubDocument>
</Document>
我挣扎的是,在Go中,每个部分的标签如果是不同的结构类型,则必须是唯一的。
我有以下Go代码:
type HasID struct{
ID string `xml:"value,attr,omitempty"`
IDType string `xml:"valueType,attr,omitempty"`
}
type FooSection struct{
ID HasID `xml:"id,omitempty"`
Title string `xml:"title,omitempty"`
//Foo fields
}
type BarSection struct{
ID HasID `xml:"id,omitempty"`
Title string `xml:"title,omitempty"`
//Bar fields
}
type Document struct{
XMLName struct{} `xml:"Document,omitempty"`
//Other fields
Sections []interface{} `xml:"SubDocument>component>section,omitempty"`
}
我还尝试让Sections字段没有标记,并且FooSection和BarSection都有
XMLName struct{} `xml:"component>section,omitempty"`
标签,无济于事。此外,我尝试让Sections成为一个字符串数组,然后编组每个部分类型,将其转储并使用&#34;,innerxml&#34; tag,但它会逃脱innerxml的&#34;&lt;&#34;等。
有人知道在Go中这样做的方法吗?结构由我编写,如果需要,可以完全改变。
可能只是因为我在OO中根深蒂固而且我很难成为Go-like。
谢谢!
答案 0 :(得分:1)
我不知道这是否是一个完美的答案,但它是可行的。要点是在Component
类型上实现encoding/xml.Unmarshaler然后在UnmarshalXML
方法内部将该部分的原始数据解组为临时值并检查其ID,然后再决定是否要解组它变为FooSection
或BarSection
这些是我使用
的类型type ID struct {
Value int `xml:"value,attr,omitempty"`
Type string `xml:"valueType,attr,omitempty"`
}
type Document struct {
Components []Component `xml:"SubDocument>component"`
}
type Component struct {
Section interface{} `xml:"section"`
}
type FooSection struct {
ID ID `xml:"id"`
Title string `xml:"title"`
Foo string `xml:"foo"`
}
type BarSection struct {
ID ID `xml:"id"`
Title string `xml:"title"`
Bar string `xml:"bar"`
}
请注意,Component
仅将Section
存储为interface{}
。这有点令人讨厌,因为只要你想使用它就必须打开它,所以你可以用它做更好的事情。
然后UnmarshalXML
方法就在这里
func (c *Component) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
// tmp holds the data for this Component. We can only call d.DecodeElement
// once so we have to put it somewhere so it can be reused.
tmp := struct {
Data []byte `xml:",innerxml"`
}{}
if err := d.DecodeElement(&tmp, &start); err != nil {
return err
}
// which holds just enough information to tell us what kind of section to
// make. We'll unmarshal tmp.Data into this to inspect it
which := struct {
ID ID `xml:"id"`
}{}
if err := xml.Unmarshal(tmp.Data, &which); err != nil {
return err
}
switch which.ID.Value {
case 0:
var f FooSection
if err := xml.Unmarshal(tmp.Data, &f); err != nil {
return err
}
c.Section = f
case 1:
var b BarSection
if err := xml.Unmarshal(tmp.Data, &b); err != nil {
return err
}
c.Section = b
}
return nil
}
完整的工作代码on the playground。
编辑:这些类型也应该像您实际要求的那样生成XML字符串。当您构建每个Component
时,您应该选择要制作的部分,并将其粘贴在那里。因为它是interface{}
它可以容纳任何东西。我已经将我的游乐场链接更新为一个示例,该示例显示将这些类型转换回字符串按预期工作。