Parsing recursive XML in Golang

Viewed 218

I am trying to parse an XML that (kind of) looks like the following - (Please keep in mind that actual documents have many other tags which I am able to parse successfully.)

<process name="p" id="1234">
<app>
 <element name="ele-1">
   <id>84594</id>
   <element name="ele-11">
     <id>95065</id>
     <element name="ele-111">
       <id>5065</id>
     </element> //ele-111
   </element> //ele-11
   <element name="ele-12">
     <id>4954</id>
   </element> //ele-12
 </element>//ele-1
</app>
.
.
.
//Many other tags here which are working fine
</process>

I have added the ele-# so that it is easy to see where one starts and where one ends. This nested elements can go until arbitrary depth once we are below the top most one(ele-1).

Which means ele-1 will have a list of nested elements and each of them may or may not have a list of nested elements, and then each of them may or may not ...

I want to parse this structure in Go. What is the best way?

I have defined something like this

type ProcessDef struct {
    Process xml.Name `xml:"process"`
    Name    string   `xml:"name,attr"`
    Id      string   `xml:"id,attr"`
    App     AppDef   `xml:"app"`
}

type AppDef struct {
    App      xml.Name     `xml:"app"`
    Elements []ElementDef `xml:"element"`
}

type ElementDef struct {
    Element  xml.Name `xml:"element"`
    Name     string   `xml:"name,attr"`
    Id       string   `xml:"id"`
    Elements []ElementDef
}

Although it reads and populates the value of the first (top level) element in the AppDef struct once I parse the XML, I am unable to parse and get the values of the all the children using the nested recursive definition in the ElementDef struct.

Also when I was trying to add the xml annotation at the slice field at the ElementDef struct, like so - Elements []ElementDef xml:"element" I was getting a warning struct field Elements repeats xml tag "element"

I am a bit lost in order to how to parse such an XML document the best way possible in Go.

1 Answers

You can remove the xml.Name from ElementDef and add the xml:"element" tag to the Elements field.

type ElementDef struct {
    Name     string       `xml:"name,attr"`
    Id       string       `xml:"id"`
    Elements []ElementDef `xml:"element"`
}

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

Or, alternatively, you can keep the xml.Name field, remove the tag, and rename it to XMLName. As the docs state: "If the struct has a field named XMLName of type Name, Unmarshal records the element name in that field."

type ElementDef struct {
    XMLName  xml.Name
    Name     string       `xml:"name,attr"`
    Id       string       `xml:"id"`
    Elements []ElementDef `xml:"element"`
}

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

Related