Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct use of XML annotations, fields and structs in custom UnmarshalXML function

Tags:

go

Consider the following struct:

type MyStruct struct {
    Name string
    Meta map[string]interface{}
}

Which has the following UnmarshalXML function:

func (m *MyStruct) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    var v struct {
        XMLName xml.Name //`xml:"myStruct"`
        Name    string   `xml:"name"`
        Meta    struct {
            Inner []byte `xml:",innerxml"`
        } `xml:"meta"`
    }

    err := d.DecodeElement(&v, &start)
    if err != nil {
        return err
    }

    m.Name = v.Name
    myMap := make(map[string]interface{})

    // ... do the mxj magic here ... -

    temp := v.Meta.Inner

    prefix := "<meta>"
    postfix := "</meta>"
    str := prefix + string(temp) + postfix
    //fmt.Println(str)
    myMxjMap, err := mxj.NewMapXml([]byte(str))
    myMap = myMxjMap

    // fill myMap
    //m.Meta = myMap
    m.Meta = myMap["meta"].(map[string]interface{})
    return nil
}

My problem with this code is these lines:

prefix := "<meta>"
postfix := "</meta>"
str := prefix + string(temp) + postfix
myMxjMap, err := mxj.NewMapXml([]byte(str))
myMap = myMxjMap
//m.Meta = myMap
m.Meta = myMap["meta"].(map[string]interface{})

My question is how I make the correct use of the xml annotations (,innerxml etc), fields and structs, so I don't have to manually pre-/append the <meta></meta> tags afterwards to get the whole Meta field as a single map.

The full code example is here: http://play.golang.org/p/Q4_tryubO6

like image 371
Dac0d3r Avatar asked Jul 02 '15 06:07

Dac0d3r


People also ask

How to unmarshal XML to object in JAXB?

The JAXB Unmarshaller interface is responsible for governing the process of deserializing the XML data to Java Objects. The unmarshalling to objects can be done to variety of input sources. 1. How to unmarshal XML to Object 1.1. Create Unmarshaller Generally, to create Unmarshaller you can reuse this code. 1.2. Unmarshalling from an InputStream

What are the child elements of an XML struct?

The first line of the struct declares the XMLName which is essentially the XML tag. Child elements are the Description, Title, and Link which are again essentially the XML tags associated with the data. The Channel field of the struct refers to another struct so this amounts to a field in the Rss struct.

What is @XmlRootElement annotation in Java?

This maps a class or an enum type to an XML root element. When a top-level class or an enum type is annotated with the @XmlRootElement annotation, then its value is represented as XML element in an XML document. //.... It defines the fields or properties of your Java classes that the JAXB engine uses for including into generated XML.

What is the difference between @maps and @XmlRootElement?

Maps a field or property to the text value on an XML tag. Maps a collection to a list of values separated by space. This maps a class or an enum type to an XML root element. When a top-level class or an enum type is annotated with the @XmlRootElement annotation, then its value is represented as XML element in an XML document. //....


1 Answers

xml package doesn't provide a way to unmarshal XML into map[string]interface{} because there is no single way to do it and in some cases it is not possible. A map doesn't preserve order of the elements (that is important in XML) and doesn't allow elements with duplicate keys.

mxj package that you used in your example has some rules how to unmarshal arbitrary XML into Go map. If your requirements do not conflict with these rules you can use mxj package to do all parsing and do not use xml package at all:

// I am skipping error handling here
m, _ := mxj.NewMapXml([]byte(s))
mm := m["myStruct"].(map[string]interface{})
myStruct.Name = mm["name"].(string)
myStruct.Meta = mm["meta"].(map[string]interface{})

Full example: http://play.golang.org/p/AcPUAS0QMj

like image 170
kostya Avatar answered Sep 18 '22 17:09

kostya