【问题标题】:How to get a value from an XML using XPath in Go如何在 Go 中使用 XPath 从 XML 中获取值
【发布时间】:2018-05-09 15:19:50
【问题描述】:

看着go xml package我找不到这种可能性。 Go 只允许定义结构树,将它们映射到 XML 树并使用 xml.NewDecoder(myXmlString).Decode(myStruct) 反序列化。

即使我定义了所需的 Go 结构树,我仍然无法使用 XPath 查询该树。

C# 有方便的函数SelectSingleNode,它允许通过指定 XPath 从 XML 树中选择值,而无需在 C# 类中复制整个树结构。

Go 中是否有类似的可能性? 如果没有,那么实现它的最简单方法是什么(可能重用 xml 包)?

【问题讨论】:

    标签: xml xpath go


    【解决方案1】:

    还有xmlpath 包。

    示例用法:

    path := xmlpath.MustCompile("/library/book/isbn")
    root, err := xmlpath.Parse(file)
    if err != nil {
        log.Fatal(err)
    }
    if value, ok := path.String(root); ok {
        fmt.Println("Found:", value)
    }
    

    【讨论】:

    【解决方案2】:

    Go 的标准包中没有 xpath 解析,所以你需要求助于使用 3rd 方包。

    然后我知道的是Gokogiri
    该软件包基于 libxml2 使用 cgo

    你要导入的子包是github.com/moovweb/gokogiri/xpath

    【讨论】:

      【解决方案3】:

      即使不是 xpath,您也可以使用原生 go xml encoder 包从 XML 中读取值。您将使用 xml.Unmarshal() 函数。 Here 是一个围棋示例。

      package main
      
      import "fmt"
      import "encoding/xml"
      
      func main() {
          type People struct {
              Names []string `xml:"Person>FullName"`
          }
      
          data := `
              <People>
                  <Person>
                      <FullName>Jerome Anthony</FullName>
                  </Person>
                  <Person>
                      <FullName>Christina</FullName>
                  </Person>
              </People>
          `
      
          v := People{Names: []string{}}
          err := xml.Unmarshal([]byte(data), &v)
          if err != nil {
              fmt.Printf("error: %v", err)
              return
          }
          fmt.Printf("Names of people: %q", v)
      }
      

      【讨论】:

      • 虽然这通常是一个很好的答案,但我不赞成它,因为 OP 实际上指定使用 XPath 语法从 XML 对象中检索值。这个解决方案回避了这个问题,根本不使用 XPath 语法!
      【解决方案4】:

      xmlquery 允许您使用 XPath 表达式从 XML 文档中提取数据。

      package main
      
      import (
          "fmt"
          "strings"
          "github.com/antchfx/xmlquery"
      )
      
      func main() {
          htmlstr := `<?xml version="1.0" ?>
          <html>
          <head>
           <title>this is a title</title>
          </head>
          <body>Hello,World</body>
          </html>`
          root, err := xmlquery.Parse(strings.NewReader(htmlstr))
          if err != nil {
               panic(err)
           }
          title := xmlquery.FindOne(root, "//title")
          fmt.Println(title.InnerText())
      }
      

      【讨论】:

      • 有趣的是,@antchfx 的解决方案与@rzymek 提到的xmlpath 不同,它不需要 需要预编译XPath 表达式。相反,XML 查询被缓存 并在需要时重复使用。这是一种替代方法。我想知道是否有人对xmlqueryxmlpath 进行了基准测试。我猜想预编译的 XPath 表达式,can 可用于 不同的 XML 对象,可能更有效。但如果您只处理 one XML 对象,xmlquery 可能会有优势。并排查看每种方法很有趣; xmlpath 似乎更惯用,但xmlquery 更直观。
      猜你喜欢
      • 2022-01-04
      • 2018-05-25
      • 1970-01-01
      • 2014-01-26
      • 1970-01-01
      • 1970-01-01
      • 2015-12-16
      • 1970-01-01
      • 2023-04-01
      相关资源
      最近更新 更多