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

标签 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 格式。

最佳答案

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

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)
}

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

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

package main

import (
    "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()
    data = getElements(children)
}

func getElements(children *goquery.Selection) map[string]interface{} {
    data := make(map[string]interface{})
    children.Each(func(i int, s *goquery.Selection) {
        val, exists := s.Attr("value")
        if exists {
            data[goquery.NodeName(s)] = val
        }

        if s.Children().Length() > 0 {
            data[goquery.NodeName(s)] = getElements(s.Children())
        }
    })
    return data
}

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

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

goxml2json从 xml 转换为 json。

关于xml - 使用属性作为动态节点的值映射 XML,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48432473/

相关文章:

java - 在java中处理异常并继续进程而不终止

go - 防止 go build 覆盖 go.mod 中的版本

wordpress - 将 WordPress 与 golang 集成

java - Android:需要格式化布局的帮助

ios - 解析 REST XML API 响应

java - XML 阅读器错误 : unexpected character content exception while invoking webservice

docker - 使用 stretch 和 alpine 进行多阶段构建

json - 序列化为 JSON 时,如何根据运行时条件省略某些字段?

golang google-bigquery v2 api指定目的表

javascript - 读/写文件导致错误。 (JavaScript 和 C++)