Search code examples
xmlgomarshalling

How to omit names of outer XML elements


I need to produce XML files like this one:

  <package>
    <dc:contributor id="creator1">John Doe</dc:contributor>
    <meta refines="creator1" property="role" scheme="marc:relators">aut</meta>
    <meta refines="creator1" property="role" scheme="onix:codelist17">A01</meta>
    <meta refines="creator1" property="file-as">Doe, John</meta>
    <meta refines="creator1" property="diplay-seq">1</meta>
    <dc:contributor id="reviewer1">Mary Poppins</dc:contributor>
    <meta refines="reviewer1" property="role" scheme="marc:relators">rev</meta>
    <meta refines="reviewer1" property="file-as">Poppins, Mary</meta>
    <meta refines="reviewer1" property="diplay-seq">1</meta>
    <dc:contributor id="translator1">Alfred Weasley</dc:contributor>
    <meta refines="translator1" property="role" scheme="marc:relators">trl</meta>
    <meta refines="translator1" property="role" scheme="onix:codelist17">B06</meta>
    <meta refines="translator1" property="file-as">Weasley, Alfred</meta>
    <meta refines="translator1" property="diplay-seq">1</meta>
  </package>

The ordering is important here.

I use this structuring:

type Pack struct {
    XMLName struct{}        `xml:"package"`
    People  []PersonWrapper `xml:""` // <-- is this the problem?
}

type Person struct {
    Id       string `xml:"id,attr"`
    Name     string `xml:"-"`
    Surname  string `xml:"-"`
    FullName string `xml:",innerxml"`
}

type Meta struct {
    Refines  string `xml:"refines,attr"`
    Property string `xml:"property,attr"`
    Scheme   string `xml:"scheme,attr,omitempty"`
    Value    string `xml:",innerxml"`
}

type PersonWrapper struct {
    Person Person `xml:"dc:contributor"`
    Metas  []Meta `xml:"meta"`
}

With this I got:

<package>
  <People>
    <dc:contributor id="creator1">John Doe</dc:contributor>
    <meta refines="creator1" property="role" scheme="marc:relators">aut</meta>
    <meta refines="creator1" property="role" scheme="onix:codelist17">A01</meta>
    <meta refines="creator1" property="file-as">Doe, John</meta>
    <meta refines="creator1" property="diplay-seq">1</meta>
  </People>
  <People>
    <dc:contributor id="reviewer1">Mary Poppins</dc:contributor>
    <meta refines="reviewer1" property="role" scheme="marc:relators">rev</meta>
    <meta refines="reviewer1" property="file-as">Poppins, Mary</meta>
    <meta refines="reviewer1" property="diplay-seq">1</meta>
  </People>
  <People>
    <dc:contributor id="translator1">Ben Weasley</dc:contributor>
    <meta refines="translator1" property="role" scheme="marc:relators">trl</meta>
    <meta refines="translator1" property="role" scheme="onix:codelist17">B06</meta>
    <meta refines="translator1" property="file-as">Weasley, Ben</meta>
    <meta refines="translator1" property="diplay-seq">1</meta>
  </People>
</package>

How to get rid of the <People/> outer tags? I tried to wrap the inner structure into other structs on a higher level but can't reach the desired structure.


Solution

  • You can implement the xml.Marshaler interface for PersonWrapper (and add xmlnames to the nested structs).

    type Pack struct {
        XMLName struct{} `xml:"package"`
        People  []PersonWrapper
    }
    
    type Person struct {
        XMLName  xml.Name `xml:"dc:contributor"`
        Id       string   `xml:"id,attr"`
        Name     string   `xml:"-"`
        Surname  string   `xml:"-"`
        FullName string   `xml:",innerxml"`
    }
    
    type Meta struct {
        XMLName  xml.Name `xml:"meta"`
        Refines  string   `xml:"refines,attr"`
        Property string   `xml:"property,attr"`
        Scheme   string   `xml:"scheme,attr,omitempty"`
        Value    string   `xml:",innerxml"`
    }
    
    type PersonWrapper struct {
        Person Person `xml:"dc:contributor"`
        Metas  []Meta `xml:"meta"`
    }
    
    func (pw PersonWrapper) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
        if err := e.Encode(pw.Person); err != nil {
            return err
        }
        if err := e.Encode(pw.Metas); err != nil {
            return err
        }
        return nil
    }
    

    https://play.golang.org/p/hzrBdHXHwOB