使用属性作为值使用动态节点映射XML

时间:2018-01-24 22:06:44

标签: xml go

我正在尝试将存储在xml文档中的数据转换为备用数据存储。我尝试过各种技术,但没有一种技术证明有效。问题是xml没有固定的模式,并且具有非常规结构。 xml的样本如下

<?xml version="1.0"?>
<Data>
    <f.1 value="field value" />
    <f.2 value="other value" />
    <f.3 value="field value 2" />
    <withchildren>
        <f.3.1 value="testvalue" />
        <f.3.2 value="test value 3" />
    </withchildren>
</Data>

理想情况下,最终结果应将结果存储在map[string]interface{}中,以便将值转换为标准的多维JSON格式。

1 个答案:

答案 0 :(得分:3)

如果你不确定结构goquery可能是你最好的选择。您的标签名称看起来有点奇怪我认为这只是样本。下面的代码使用键的标记名称并使用value属性,但您可以为任何结构修改它。

10.0
20.0
30.0
40.0
50.0
60.0
70.0
80.0
90.0
100.0
true

如果你真的不知道结构是什么,或者有多少嵌套元素可能会尝试这个递归版本。

如果您有多个具有相同名称的元素,则可以修改代码以添加带有键名称的数字。所以“tag1”,“tag2”等等。

package main

import (
    "fmt"
    "github.com/PuerkitoBio/goquery"
    "strings"
)

func main() {
    xml := `
      <?xml version="1.0"?>
      <Data>
          <f1 value="field value"></f1>
          <f2 value="other value"></f2>
          <f3 value="field value 2"></f3>
          <withchildren>
              <f31 value="testvalue"></f31>
              <f32 value="test value 3"></f32>
          </withchildren>
      </Data>
      `
    data := make(map[string]interface{})
    reader := strings.NewReader(xml)

    doc, _ := goquery.NewDocumentFromReader(reader)
    children := doc.Find("Data").Children()

    children.Each(func(i int, s *goquery.Selection) {

        val, exists := s.Attr("value")
        if exists {
            data[goquery.NodeName(s)] = val
        }

        withchildren := s.Children()

        if withchildren.Length() > 0 {
            withchildren.Each(func(i int, s *goquery.Selection) {
                val, exists := s.Attr("value")
                if exists {
                    data[goquery.NodeName(s)] = val
                }

            })
        }
    })
    fmt.Println(data)
}

还有一些我没有使用的Go包。

mxj将xml转换为map [string] interface {}

goxml2json从xml转换为json。