Golang如何解码XML文件中特定的嵌套子元素?

Golang如何解码XML文件中特定的嵌套子元素? 例如,我有以下XML:

<container>
     <children>
          <child type="M">1</child>
          <child type="C">2</child>
          <child type="W">3</child>
     </children>
</container>

如何指定获取类型为C的子元素?如果我有这样的结构体:

type Container struct {
     Container Child `xml:"container>children"`
}
type Child struct {
     Type string `cml:"type,attr"`
     Child int `xml:"child"`
}

使用上面的结构体会返回第一个子元素。但我想要第二个或第三个子元素。有没有办法在不遍历XML的情况下实现这一点?

谢谢!


更多关于Golang如何解码XML文件中特定的嵌套子元素?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

我认为使用Go语言内置的XML库无法实现这个功能。这里有一个XPath实现,或许能满足你的需求:https://github.com/antchfx/xmlquery

更多关于Golang如何解码XML文件中特定的嵌套子元素?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


package main

import (
    "fmt"
    "github.com/clbanning/mxj"
)

func main() {
    data := []byte(`<container>
         <children>
             <child type="M">1</child>
             <child type="C">2</child>
            <child type="W">3</child>
        </children>
    </container>`)

	m, err := mxj.NewMapXml(data)
    if err != nil {
        fmt.Println("NewMapXml err:", err)
        return
    }

    vals, err := m.ValuesForKey("-type")
    if err != nil {
        fmt.Println("ValuesForKey err:", err)
        return
    }

     for i := 1; i < 3; i++ {
        fmt.Println(i, "is:", vals[i])
    }
}
package main

import (
	"fmt"
	"strconv"

	"github.com/clbanning/mxj"
)

func main() {
	data := []byte(`<container>
     <children>
          <child type="M">1</child>
          <child type="C">2</child>
          <child type="W">3</child>
     </children>
</container>`)

	mxj.PrependAttrWithHyphen(false)
	m, err := mxj.NewMapXml(data)
	if err != nil {
		fmt.Println("NewMapXml err:", err)
		return
	}


	for i := 1; i < 3; i++ {
		val, err := m.ValueForPath("container.children.child["+strconv.Itoa(i)+"].type")
	 	if err != nil {
			fmt.Println("ValuesForKey err:", err)
	    		return
	    	}
	    	fmt.Println(i, "is:", val)
	    }
}

在Go中解码XML时,可以通过结构体标签的层级路径来指定嵌套元素。对于你的需求,可以通过以下方式直接获取特定类型的子元素:

package main

import (
    "encoding/xml"
    "fmt"
)

type Container struct {
    Children []Child `xml:"children>child"`
}

type Child struct {
    Type  string `xml:"type,attr"`
    Value int    `xml:",chardata"`
}

func main() {
    data := `
<container>
     <children>
          <child type="M">1</child>
          <child type="C">2</child>
          <child type="W">3</child>
     </children>
</container>`

    var container Container
    err := xml.Unmarshal([]byte(data), &container)
    if err != nil {
        panic(err)
    }

    // 查找类型为C的子元素
    for _, child := range container.Children {
        if child.Type == "C" {
            fmt.Printf("找到类型为C的子元素: %d\n", child.Value)
            break
        }
    }
}

如果你需要直接获取特定位置的子元素而不遍历,可以在结构体中使用切片索引:

type Container struct {
    Children struct {
        Child []Child `xml:"child"`
    } `xml:"children"`
}

func main() {
    data := `
<container>
     <children>
          <child type="M">1</child>
          <child type="C">2</child>
          <child type="W">3</child>
     </children>
</container>`

    var container Container
    err := xml.Unmarshal([]byte(data), &container)
    if err != nil {
        panic(err)
    }

    // 直接访问第二个子元素(索引为1)
    if len(container.Children.Child) > 1 {
        fmt.Printf("第二个子元素: type=%s, value=%d\n", 
            container.Children.Child[1].Type, 
            container.Children.Child[1].Value)
    }
}

如果你只需要特定类型的子元素,可以在解码后使用过滤函数:

func getChildByType(children []Child, childType string) (Child, bool) {
    for _, child := range children {
        if child.Type == childType {
            return child, true
        }
    }
    return Child{}, false
}

func main() {
    // ... 解码代码同上
    
    if child, found := getChildByType(container.Children, "C"); found {
        fmt.Printf("类型为C的子元素: %d\n", child.Value)
    }
}

注意:Go的xml包不支持在结构体标签中直接指定属性条件过滤。要获取特定类型的子元素,需要在解码后通过遍历或索引来访问。

回到顶部