Golang —— 反序列化额外的 XML 属性

原文链接:Golang —— 反序列化额外的 XML 属性

Go 的 encoding/xml 包提供了 xml.Attr 类型来表示 XML 属性。你可以通过添加一个字段来接收这些“多余的”或未指定的属性。

示例 XML:
<Person name="Tom" age="30" country="USA"></Person>
方法 1:使用 ,attr 显式字段接收属性

如果你已知属性名,可以这样写:

type Person struct {
    Name    string `xml:"name,attr"`
    Age     string `xml:"age,attr"`
    Country string `xml:"country,attr"`
}
方法 2:接收所有未定义的额外属性

如果你只定义了部分属性,其余的属性可以使用 []xml.Attr 来接收

type Person struct {
    Name        string     `xml:"name,attr"`       // 显式字段
    ExtraAttrs  []xml.Attr `xml:",any,attr"`       // 接收所有额外属性
}

但实际上 xml:",any,attr" 并不直接支持。Go 的标准 encoding/xml 不支持自动捕获未定义的属性进 []xml.Attr。你必须用 xml.Unmarshal 自定义解析器或嵌入结构体 来实现更灵活的处理。


推荐方式:嵌入一个辅助结构体并实现自定义 UnmarshalXML

type Person struct {
    Name string `xml:"name,attr"`
    
    ExtraAttrs []xml.Attr
}

func (p *Person) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    // 提取已知属性
    for _, attr := range start.Attr {
        switch attr.Name.Local {
        case "name":
            p.Name = attr.Value
        default:
            p.ExtraAttrs = append(p.ExtraAttrs, attr)
        }
    }

    // 跳过子元素(如果有)
    return d.Skip()
}

输出示例:

xmlData := `<Person name="Tom" age="30" country="USA"></Person>`
var p Person
xml.Unmarshal([]byte(xmlData), &p)

fmt.Println(p.Name)        // Tom
fmt.Println(p.ExtraAttrs)  // [age="30", country="USA"]

总结:

  • 如果你已知属性名,可直接使用 struct tag xml:"name,attr"
  • 如果你想获取所有额外属性,需要自定义 UnmarshalXML 方法。
  • Go 的 encoding/xml 包功能强大但略显简陋,处理动态字段需要动手实现。

完整示例

下面是一个完整可运行的 Go 示例,展示如何在解析 XML 时获取已知属性和额外未定义的属性。


✅ 示例 XML:

<Person name="Tom" age="30" country="USA"></Person>

✅ Go 代码(可以直接运行):

package main

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

type Person struct {
	Name       string     // 已知属性
	ExtraAttrs []xml.Attr // 未定义的额外属性
}

// 自定义 XML 解码器
func (p *Person) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	for _, attr := range start.Attr {
		switch attr.Name.Local {
		case "name":
			p.Name = attr.Value
		default:
			p.ExtraAttrs = append(p.ExtraAttrs, attr)
		}
	}
	// 跳过内部内容
	return d.Skip()
}

func main() {
	data := `<Person name="Tom" age="30" country="USA"></Person>`
	var p Person
	if err := xml.Unmarshal([]byte(data), &p); err != nil {
		fmt.Println("解析失败:", err)
		return
	}

	fmt.Println("姓名:", p.Name)
	fmt.Println("额外属性:")
	for _, attr := range p.ExtraAttrs {
		fmt.Printf("- %s = %s\n", attr.Name.Local, attr.Value)
	}
}

✅ 输出结果:

姓名: Tom
额外属性:
- age = 30
- country = USA
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值