
本文详解如何使用 Go 的 encoding/xml 包解析包含内联 XML 标签(如 <ph>)的混合内容字段(如 <source>),通过组合 chardata、innerxml 和嵌套结构体实现精准提取原始文本与属性数据。
本文详解如何使用 go 的 `encoding/xml` 包解析包含内联 xml 标签(如 `
在 Go 中解析类似 XLIFF 或自定义本地化 XML 时,常遇到 <source> 这类“混合内容”节点:它既包含纯文本(如 "hello %"),又内嵌 XML 元素(如 <ph id="first_name">{0}</ph>)。若直接将 Source 定义为 string,Go 的 XML 解析器会忽略子元素;若仅用 innerxml,则无法分离文本与结构化变量。正确解法是为该字段定义专用结构体,并同时捕获字符数据(chardata)、原始嵌套 XML(innerxml)及子元素(如 ph)。
以下为推荐的结构体定义:
type TransUnit struct {
ID string `xml:"id,attr"`
Source Source `xml:"source"`
Target string `xml:"target"`
}
type Source struct {
Raw string `xml:",innerxml"` // 完整原始内容(含标签)
Text string `xml:",chardata"` // 仅纯文本内容(不含标签)
Vars []Var `xml:"ph"` // 所有 <ph> 子元素
}
type Var struct {
ID string `xml:"id,attr"`
Value string `xml:",innerxml"` // <ph> 内部的文本(如 "{0}")
}✅ 关键要点说明:
- chardata 捕获节点中所有非标签的纯文本(自动拼接相邻文本片段),适用于提取 "hello % " 和 " % " 等占位符前缀;
- innerxml 获取整个节点的原始 XML 字符串(含所有子标签),可用于调试或备用解析;
- xml:"ph" 直接映射子元素为结构体切片,每个 Var 实例携带 id 属性及内部值;
- 注意:chardata 与 innerxml 可共存于同一结构体,Go 解析器会智能分配——chardata 得纯文本,xml:"ph" 得结构化子节点。
? 实际应用示例(生成目标格式字符串):
假设需将 <source> 转为 "hello %{first_name} %{last_name}",可基于解析结果构建:
func (s Source) Format() string {
parts := []string{s.Text} // 初始文本
for _, v := range s.Vars {
parts = append(parts, fmt.Sprintf("%%{%s}", v.ID))
}
return strings.Join(parts, "")
}
// 调用:tu.Source.Format() → "hello %{first_name} %{last_name}"⚠️ 注意事项:
- chardata 不会包含子元素内的文本(如 <ph>{0}</ph> 中的 {0} 属于 Var.Value,而非 Source.Text);
- 若 XML 中存在多个连续文本节点(如换行+空格),chardata 会合并为单一字符串,需自行处理多余空白;
- 避免在 Source 中同时使用 xml:",any" 或未声明字段,否则可能干扰 chardata 提取;
- 测试时建议使用 xml.Unmarshal 并检查 Source.Text 和 Source.Vars 是否非空,确保结构体标签无拼写错误。
通过这种分层建模方式,你无需二次解析 innerxml 字符串,即可安全、高效地还原带变量插槽的本地化模板字符串。

















