xml 编码和解码 xsi :type

mengfanrong 阅读:62 2025-06-02 22:19:02 评论:0

这与 xsi:type 属性有关,但如果您有一个名为 <soap:envelope ...> 的元素,则似乎有必要实现类似的问题自定义解码器函数。

这是有问题的代码(在 go Playground 上: 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 的传统方法是什么?

解决方法代码(在 Playground 上: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)) 
} 

请您参考如下方法:

从技术上讲,示例中的黄金结果(我的意思是 first one )似乎不是格式良好的 XML。它的 xsi:type 属性有一个未绑定(bind)的 xml 元素前缀 xsi。我认为,this spec并为此制定了权威规则。这个 XML 片段看起来是出于竞争,如果它是较大文档的一部分,那么 xsi 前缀很可能会绑定(bind)到其他地方 - 这对于 SOAP 文档来说很常见。

请注意,Go Marshaller 会生成格式良好的 XML。由于代码片段中缺少 DTD 等原因,该文档仍然不是有效的 XML,但至少它不会混淆任何 XML 解析器。

作为一个更广泛的建议,匹配 XML 文档的精确文本表示以进行测试或任何其他操作很可能会产生较差的结果,因为有不止一种语法正确(且格式良好)的方法来对 XML 文档进行编码。不同的编码器可以根据作者的喜好调整特定的编码方法,这不会导致生成的 XML 损坏或与任何其他兼容的解码器不兼容。不要比较文本片段,而是尝试比较未整理的结构。类似于 github.com/google/go-cmp/cmp包可以让事情变得简单。


标签:XML
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号