如何在 Go XML 解析中保留 HTML 标签内容

go 的 `encoding/xml` 包默认会将 xml 元素的子节点(如 html 标签)解析为纯文本并忽略嵌套结构,若需原样保留 html 片段(如 `` 标签),应使用 `xml:",innerxml"` 标签而非普通字段映射。

在 Go 中解析包含内嵌 HTML 的 XML 时,常见的误区是直接将 HTML 内容映射为 string 类型字段(如 MyResult stringxml:"text`),这会导致xml.Unmarshal自动展开并丢弃所有子元素标签,仅提取纯文本内容(即“扁平化”处理)。例如HelloWorld会被解析为"HelloWorld",而` 标签本身完全丢失。

正确做法是利用 encoding/xml 提供的特殊结构标签 ",innerxml",它能将目标 XML 元素的原始内部 XML 字节流(包括所有标签、属性和文本)完整捕获为字符串。关键在于:必须将该字段嵌套在匿名或具名结构体中,并通过结构体字段进行映射。

以下是修正后的完整示例:

package main

import (
    "encoding/xml"
    "fmt"
)

type ResultSlice struct {
    MyText []Result `xml:"results>result"`
}

type Result struct {
    Text struct {
        HTML string `xml:",innerxml"` // ✅ 捕获  内全部原始 XML 内容
    } `xml:"text"`
}

func main() {
    s := `
                         
              This has styleThen some not-style
              No style here
              Again, no style
            
          `

    r := &ResultSlice{}
    if err := xml.Unmarshal([]byte(s), r); err != nil {
        fmt.Printf("Parse error: %v\n", err)
        return
    }

    for i, res := range r.MyText {
        fmt.Printf("Result %d: %q\n", i+1, res.Text.HTML)
        // 输出示例:
        // Result 1: "This has styleThen some not-style"
        // Result 2: "No style here"
        // Result 3: "Again, no style"
    }
}

⚠️ 注意事项:

  • xml:",innerxml" 不能直接用于顶层字段(如 HTML stringxml:"text,innerxml"`),必须包裹在结构体内,否则解析行为未定义或失败;
  • 返回的字符串是未经转义的原始内容(如 & 仍为 &,不会自动解码),如需 HTML 渲染,建议配合 html.UnescapeString 或模板安全输出;
  • 若需进一步解析嵌套 HTML(如提取 文本),应使用专用 HTML 解析器(如 golang.org/x/net/html),而非继续依赖 encoding/xml;
  • 此方法适用于 HTML 片段混入 XML 的场景(如 RSS 描述、富文本 API 响应),但不适用于严格 XHTML(需确保嵌套结构合法,否则解析可能出错)。

总结:",innerxml" 是 Go XML 解析器中保留原始子节点序列的唯一可靠方式,合理封装结构体字段即可精准捕获含标签的 HTML 内容,避免信息丢失。