Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go XML Marshalling and the Root Element

In Go, you can marshall a struct to XML, e.g.:

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))
}

produces output:

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

My problem is, the person type is lower-case "p" because I want that to be private to the package. But I'd prefer the XML element to be uppercase: <Person>. The fields within the struct can be marshalled to other names using tags (e.g. `xml:"name"`) against the structure fields but this doesn't seem to be an option for the structure type.

I have a work-around using templates, but it would be nice to know a better answer.

like image 700
scaganoff Avatar asked Sep 13 '12 03:09

scaganoff


2 Answers

I think the easiest thing is just to add a dummy field to the person struct with the XML tag.

A struct{} element does not use any storage, I checked with 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

If you prefer to initialize the struct without using field names, it is necessary to add an item to initialize the empty struct, like this:

p := &person{"John Smith", "Capricorn", struct{}{}}
like image 112
Sam Watkins Avatar answered Oct 20 '22 16:10

Sam Watkins


This also works, though I don't think it's particularly pretty.

However, this worked in a lot more straight forward manner for me than the other accepted solution from 5 years ago.

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))
}
like image 32
Matjam Avatar answered Oct 20 '22 15:10

Matjam