Home > Enterprise >  Converting xml to json in Golang
Converting xml to json in Golang

Time:04-15

I'm using github.com/basgys/goxml2json for xml to json conversion. Below is the example code:

package main

import (
    "fmt"
    "strings"
    xj "github.com/basgys/goxml2json"
)

func main() {
    xml := strings.NewReader(`<?xml version="1.0" encoding="UTF-8"?>
    <osm version="0.6" generator="CGImap 0.0.2">
     <bounds minlat="54.0889580" minlon="12.2487570" maxlat="54.0913900" maxlon="12.2524800"/>
     <foo>bar</foo>
    </osm>`)

    json, err := xj.Convert(xml)
    if err != nil {
        panic("ERROR converting xml to json")
    }

    fmt.Println(json.String())
}

The output of the above code is:

  {
    "osm": {
      "-version": 0.6,
      "-generator": "CGImap 0.0.2",
      "bounds": {
        "-minlat": "54.0889580",
        "-minlon": "12.2487570",
        "-maxlat": "54.0913900",
        "-maxlon": "12.2524800"
      },
      "foo": "bar"
    }
  }

However, I am expecting the output like below as given by https://codebeautify.org/xmltojson/y2221f265:

{
  "osm": {
    "bounds": "",
    "foo": "bar"
  }
}

How to remove the keys starting with - from the JSON output? I do not know the structure of the data beforehand.

CodePudding user response:

Try this

package main

import (
    "encoding/json"
    "fmt"
    "strings"

    xj "github.com/basgys/goxml2json"
)

// ToObject - convert string to any given struct
func ToObject(value string, object interface{}) error {
    err := json.Unmarshal([]byte(value), &object)
    if err != nil {
        return err
    }
    return nil
}
func main() {
    xml := strings.NewReader(`<?xml version="1.0" encoding="UTF-8"?>
    <osm version="0.6" generator="CGImap 0.0.2">
     <bounds minlat="54.0889580" minlon="12.2487570" maxlat="54.0913900" maxlon="12.2524800"/>
     <foo>bar</foo>
    </osm>`)

    converter, err := xj.Convert(xml)
    if err != nil {
        panic("ERROR converting xml to json")
    }
    osmStruct := &ExampleStruct{}
    ToObject(converter.String(), &osmStruct)

    b, _ := json.Marshal(osmStruct)
    fmt.Println(string(b))
}

// ExampleStruct -
type ExampleStruct struct {
    Osm Osm `json:"osm"`
}

// Osm -
type Osm struct {
    Version   string `json:",omitempty"`
    Generator string `json:",omitempty"`
    Bounds    Bounds `json:"bounds"`
    Foo       string `json:"foo"`
}

// Bounds -
type Bounds struct {
    Minlat string `json:",omitempty"`
    Minlon string `json:",omitempty"`
    Maxlat string `json:",omitempty"`
    Maxlon string `json:",omitempty"`
}

CodePudding user response:

I think this should do it. It is a modified version of the goxml2json.Convert func. Used the WithAttrPrefix to specify a custom prefix(in case you ever want to use a - at the start of your body).

Please note that this only works for the latest commit on the master branch, the v1.1.0 tag doesn't support plugins, so you have to go get it like so: go get github.com/basgys/goxml2json@master

RemoveAttr just recursively deletes all children with the given prefix. You could also do other modifications at this point.

package main

import (
    "bytes"
    "fmt"
    "strings"

    xj "github.com/basgys/goxml2json"
)

const prefix = "veryuniqueattrprefix-"

func main() {
    xml := strings.NewReader(`<?xml version="1.0" encoding="UTF-8"?>
    <osm version="0.6" generator="CGImap 0.0.2">
     <bounds minlat="54.0889580" minlon="12.2487570" maxlat="54.0913900" maxlon="12.2524800"/>
     <foo>bar</foo>
    </osm>`)

    // Decode XML document
    root := &xj.Node{}
    err := xj.NewDecoder(
        xml,
        xj.WithAttrPrefix(prefix),
    ).Decode(root)
    if err != nil {
        panic(err)
    }

    RemoveAttr(root)

    // Then encode it in JSON
    buf := new(bytes.Buffer)
    e := xj.NewEncoder(buf)
    err = e.Encode(root)
    if err != nil {
        panic(err)
    }

    fmt.Println(buf.String())
}

func RemoveAttr(n *xj.Node) {
    for k, v := range n.Children {
        if strings.HasPrefix(k, prefix) {
            delete(n.Children, k)
        } else {
            for _, n := range v {
                RemoveAttr(n)
            }
        }
    }
}

outputs:

{"osm": {"bounds": "", "foo": "bar"}}
  • Related