You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang如何解析含同名嵌套节点的XML并提取所有claim-text内容?

问题原因

你原有结构体的标签规则只能匹配<claim>节点的直接子层级<claim-text>标签,Go标准库encoding/xml默认不会递归查找深层嵌套的同名标签,因此无法获取嵌套的文本内容。

实现方案

我们可以为Claim类型实现自定义的UnmarshalXML方法,在反序列化阶段递归遍历当前<claim>节点下的所有子节点,提取所有层级<claim-text>标签的文本内容,完整实现代码如下:

package main

import (
	"encoding/xml"
	"fmt"
	"io"
	"strings"
)

// 顶层解析结果结构体
type Result struct {
	Claims []Claim `xml:"claims>claim"`
}

// 自定义Claim类型,存储当前claim下所有claim-text的文本
type Claim struct {
	AllClaimTexts []string
}

// 实现encoding/xml的Unmarshaler接口,自定义反序列化逻辑
func (c *Claim) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	// 递归提取claim-text文本的内部函数
	var extractClaimText func(xml.Token) error
	extractClaimText = func(t xml.Token) error {
		switch token := t.(type) {
		case xml.StartElement:
			// 匹配所有层级的claim-text标签
			if token.Name.Local == "claim-text" {
				var text string
				// 直接解析当前claim-text节点的全部文本(自动拼接内部嵌套的所有文本内容)
				if err := d.DecodeElement(&text, &token); err != nil {
					return err
				}
				// 按需清理文本前后空白,不需要可以删除这行
				text = strings.TrimSpace(text)
				if text != "" {
					c.AllClaimTexts = append(c.AllClaimTexts, text)
				}
				return nil
			}
			// 非claim-text标签,继续遍历子节点
			for {
				nextToken, err := d.Token()
				if err != nil {
					if err == io.EOF {
						break
					}
					return err
				}
				// 遇到当前节点的结束标签,停止子节点遍历
				if _, ok := nextToken.(xml.EndElement); ok {
					break
				}
				if err := extractClaimText(nextToken); err != nil {
					return err
				}
			}
		}
		return nil
	}

	// 遍历当前claim节点的所有子节点
	for {
		t, err := d.Token()
		if err != nil {
			if err == io.EOF {
				break
			}
			return err
		}
		// 遇到claim的结束标签,终止解析
		if end, ok := t.(xml.EndElement); ok && end.Name.Local == "claim" {
			break
		}
		if err := extractClaimText(t); err != nil {
			return err
		}
	}
	return nil
}

// 测试用例
func main() {
	xmlData := `
<claims>
    <claim>
        <claim-text>ABC
            <claim-text>PQR</claim-text>
            <claim-text>Xyz
                <claim-text>A</claim-text>
                <claim-text>B</claim-text>
                <claim-text>C</claim-text>
            </claim-text>
        </claim-text>
    </claim>
    <claim>
        <claim-text>PPP
            <claim-text>ZZZ</claim-text>
            <claim-text>MMM</claim-text>
        </claim-text>
    </claim>
</claims>`

	var res Result
	err := xml.Unmarshal([]byte(xmlData), &res)
	if err != nil {
		panic(err)
	}

	// 打印结果
	for idx, claim := range res.Claims {
		fmt.Printf("第%d个claim的所有claim-text内容:\n", idx+1)
		for _, text := range claim.AllClaimTexts {
			fmt.Printf("- %s\n", text)
		}
	}
}
输出效果

运行上述代码会得到你需要的结果:

第1个claim的所有claim-text内容:
- ABC
- PQR
- Xyz
- A
- B
- C
第2个claim的所有claim-text内容:
- PPP
- ZZZ
- MMM

如果不需要清理文本前后的空白、换行,删除strings.TrimSpace相关逻辑即可。

内容的提问来源于stack exchange,提问作者Priyanka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 19:24:03