【问题标题】:Go XML Marshalling and the Root ElementGo XML 编组和根元素
【发布时间】:2012-09-13 03:14:05
【问题描述】:

在 Go 中,您可以将结构编组为 XML,例如:

package main

import (
    "encoding/xml"
    "fmt"
    )

type person struct {
    Name string
    Starsign string
}

func main() {
    p := &person{"John Smith", "Capricorn"}
    b,_ := xml.MarshalIndent(p,"","   ")
    fmt.Println(string(b))
}

产生输出:

<person>
   <Name>John Smith</Name>
   <Starsign>Capricorn</Starsign>
</person>

我的问题是,人员类型是小写的“p”,因为我希望它对包是私有的。但我更喜欢 XML 元素为大写:&lt;Person&gt;。可以使用标签(例如`xml:“name”`)针对结构字段将结构中的字段编组为其他名称,但这似乎不是结构类型的选项。

我有一个使用模板的解决方法,但很高兴知道一个更好的答案。

【问题讨论】:

    标签: xml-serialization go


    【解决方案1】:

    我认为最简单的事情就是使用 XML 标记向 person 结构添加一个虚拟字段。

    struct{} 元素不使用任何存储,我检查了unsafe.Sizeof()

    package main
    
    import (
        "encoding/xml"
        "fmt"
    )
    
    type person struct {
        Name     string
        Starsign string
        XMLName  struct{} `xml:"Person"`
    }
    
    func main() {
        p := &person{Name: "John Smith", Starsign: "Capricorn"}
        b, _ := xml.MarshalIndent(p, "", "   ")
        fmt.Println(string(b))
    }
    

    go playground

    如果你更喜欢不使用字段名来初始化结构体,则需要添加一个项来初始化空结构体,如下所示:

    p := &person{"John Smith", "Capricorn", struct{}{}}
    

    【讨论】:

      【解决方案2】:

      这也可以,虽然我不认为它特别漂亮。

      但是,与 5 年前其他公认的解决方案相比,这对我来说更直接。

      package main
      
      import (
          "encoding/xml"
          "fmt"
          )
      
      type person struct {
          XMLName xml.Name
          Name string
          Starsign string
      }
      
      func main() {
          p := &person{xml.Name{Local: "Person"}, "John Smith", "Capricorn"}
          b,_ := xml.MarshalIndent(p,"","   ")
          fmt.Println(string(b))
      }
      

      【讨论】:

        【解决方案3】:

        根据encoding/xml.Marshal 文档:

        XML 元素的名称取自,按优先顺序排列:

        • XMLName 字段上的标记,如果数据是结构体
        • xml.Name 类型的 XMLName 字段的值
        • 用于获取数据的struct字段的标签
        • 用于获取数据的结构字段名称
        • 编组类型的名称

        您可以在结构中的 XMLName 字段上使用标记来覆盖人员结构的 XML 标记名称。为了避免将其放入您的实际 person 结构中,您可以创建一个匿名结构来嵌入您正在编组的 person 结构。

        package main
        
        import (
            "encoding/xml"
            "fmt"
        )
        
        type person struct {
            Name        string
            Starsign    string
        }
        
        func marshalPerson(p person) ([]byte, error) {
            tmp := struct {
                person
                XMLName struct{}    `xml:"Person"`
            }{person: p}
        
            return xml.MarshalIndent(tmp, "", "   ")
        }
        
        func main() {
            p := person{"John Smith", "Capricorn"}
            b, _ := marshalPerson(p)
            fmt.Println(string(b))
        }
        

        【讨论】:

        • 谢谢!解决方案是正确的,但是您在答案中输入的代码并不完全有效。我不得不将 TagName 字段更改为 XMLName。
        • 同意“不友好”,现在我有一个导出的 XMLName 字段。我必须说,go 中的编组支持最初看起来不错,但是当您有多种格式等时不能很好地扩展。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多