xml封送和解封xsi:type

时间:2019-10-06 13:19:51

标签: xml go marshalling unmarshalling

这与 xsi:type 属性有关,但是如果您有一个名为<< strong> soap:envelope ...>的元素,则可能在需要实现的地方出现类似的问题自定义取消编组功能。

下面是有问题的代码(在旅途中:https://play.golang.org/p/ORQsINYS-9o

type PayloadPublication struct {
    XMLName xml.Name `json:"xmlName"`
    XsiType xml.Attr `xml:"xsi type,attr" json:"xsiType"`
    Lang    xml.Attr `xml:"lang,attr" json:"lang"`
}

func main() {
    payload := PayloadPublication{}

    expectedXML := `<payloadPublication xmlns="http://datex2.eu/schema/2/2_0" xsi:type="MeasurementSiteTablePublication" lang="nl"></payloadPublication>`

    // 1. Unmarshal - 2. Marshal - 3. Compare
    err := xml.Unmarshal([]byte(expectedXML), &payload)
    if err != nil {
        fmt.Print(err.Error())
    }

    result, err := xml.Marshal(payload)
    if err != nil {
        fmt.Print(err.Error())
    }

    fmt.Printf("expected: %v\n", expectedXML)
    fmt.Printf("result:   %v\n", string(result))
}

结果

expected: <payloadPublication xmlns="http://datex2.eu/schema/2/2_0" xsi:type="MeasurementSiteTablePublication" lang="nl"></payloadPublication>
result:   <payloadPublication xmlns="http://datex2.eu/schema/2/2_0" xmlns:xsi="xsi" xsi:type="MeasurementSiteTablePublication" lang="nl"></payloadPublication>

如您所见,添加了属性 xmlns:xsi =“ xsi” ,这不是我想要的

一种解决方法是使用自定义拆组器,但这似乎不必要且复杂。 (下面的代码)。 有没有更简单的方法可以做到这一点?处理这种XML的常规方法是什么?

解决方法代码(在操场上:https://play.golang.org/p/d4OtYPtYBDg

type PayloadPublication struct {
    XMLName xml.Name `json:"xmlName"`
    XsiType xml.Attr `xml:"xsi type,attr" json:"xsiType"`
    Lang    xml.Attr `xml:"lang,attr" json:"lang"`
}

func (pp *PayloadPublication) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    // Attributes
    for _, attr := range start.Attr {
        if attr.Name.Local == "type" {
            pp.XsiType = xml.Attr{Name: xml.Name{Local: "xsi:type"}, Value: attr.Value}
        }
    }

    var dummy struct {
        // attributes
        XMLName xml.Name `json:"xmlName"`
        XsiType xml.Attr `xml:"xsi type,attr" json:"xsiType"`
        Lang    xml.Attr `xml:"lang,attr" json:"lang"`
    }

    err := d.DecodeElement(&dummy, &start)
    if err != nil {
        return err
    }

    pp.XMLName = dummy.XMLName
    pp.Lang = dummy.Lang

    return nil
}

func main() {
    payload := PayloadPublication{}

    expectedXML := `<payloadPublication xmlns="http://datex2.eu/schema/2/2_0" xsi:type="MeasurementSiteTablePublication" lang="nl"></payloadPublication>`

    // 1. Unmarshal - 2. Marshal - 3. Compare
    err := xml.Unmarshal([]byte(expectedXML), &payload)
    if err != nil {
        fmt.Print(err.Error())
    }

    result, err := xml.Marshal(payload)
    if err != nil {
        fmt.Print(err.Error())
    }

    fmt.Printf("expected: %v\n", expectedXML)
    fmt.Printf("result:   %v\n", string(result))
}

1 个答案:

答案 0 :(得分:1)

从技术上讲,示例中的黄金结果(我的意思是first one)似乎不是格式正确的XML。它具有xsi属性的未绑定xml元素前缀xsi:type。我认为this spec为此设置了权威规则。该XML代码段似乎是不争的事实,如果它是较大文档的一部分,那么xsi前缀很可能会绑定到其他位置-对于SOAP文档来说很常见。

请注意,Go Marshaller会生成格式正确的XML。由于缺少摘要中的DTD等,该文档仍然不是有效的XML,但是至少它不会混淆任何XML解析器。

作为更广泛的建议,匹配XML文档的确切文本表示形式以进行测试或其他任何事情最有可能产生较差的结果,因为存在多种在语法上正确(且格式正确)的XML编码文档的方式。不同的编组人员可以根据作者的喜好来调整特定的编码方法,这不会使生成的XML损坏或与其他任何兼容的解码器不兼容。与其比较文本片段,不如尝试比较未编组的结构。 github.com/google/go-cmp/cmp包之类的东西可以使其变得简单。