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

为何(encoder).EncodeElement忽略",innerxml"标签?Go XML问题求助

Go XML包序列化CDATA时转义特殊字符的原因及解决方法

原因分析

你遇到的问题核心出在自定义的MarshalXML实现上:

  1. 你先将status转成statusMarshaller并调用xml.Marshal,得到的是完整的<statusMarshaller>标签的XML字节流。之后调用d.EncodeElement(temp, se)时,Encoder会把这个字节数组当作普通字符串处理,对所有XML特殊字符(比如<、>、")进行转义,所以最终输出里全是&lt;这类转义序列。
  2. 虽然你给Text字段加了,innerxml标签,但因为重写了MarshalXML,默认的innerxml逻辑根本没触发,自然不会按你预期的原样写入内容。

解决方法

不需要额外的statusMarshaller类型,也不用嵌套调用xml.Marshal。直接在MarshalXML里手动处理属性和CDATA内容:

  1. 先写入<status>标签的属性(比如date);
  2. 直接写入CDATA的前缀<![CDATA[;
  3. 写入原始文本内容(注意:如果文本里包含]]>,需要拆分处理,避免破坏CDATA结构,这里假设你的内容里没有这个序列);
  4. 写入CDATA的后缀]]>;
  5. 关闭<status>标签。

修改后的代码:

package main

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

var xmlFile string = `<?xml version="1.0" encoding="UTF-8"?>
<statusdb>
  <status date="today">
      <![CDATA[today is < yesterday]]>
  </status>
  <status  date="yesterday">
      <![CDATA[PM,
      1. there are issues with the marshaller
      2. i don't know how to solve them]]>
  </status>
</statusdb>`

type statusDB struct {
    Status []*status `xml:"status"`
}

type status struct {
    Text string `xml:",innerxml"`
    Date string `xml:"date,attr"`
}

func main() {
    var projectStatus statusDB

    err := xml.Unmarshal([]byte(xmlFile), &projectStatus)
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Println("In Go: \"" + projectStatus.Status[0].Text + "\"")
    fmt.Println("In Go: \"" + projectStatus.Status[1].Text + "\"")
    x, err := xml.MarshalIndent(projectStatus, "", "  ")
    if err != nil {
        fmt.Println(err)
        return
    }
    fmt.Printf("%s\n", x)
}

func (tagElement *status) UnmarshalXML(d *xml.Decoder, se xml.StartElement) error {
    temp := struct {
        Text string `xml:",innerxml"`
        Date string `xml:"date,attr"`
    }{}
    d.DecodeElement(&temp, &se)
    temp.Text = strings.TrimSpace(temp.Text)
    temp.Text = strings.TrimPrefix(temp.Text, "<![CDATA[")
    temp.Text = strings.TrimSuffix(temp.Text, "]]>")
    tagElement.Text = temp.Text
    tagElement.Date = temp.Date
    return nil
}

func (tagElement status) MarshalXML(d *xml.Encoder, se xml.StartElement) error {
    // 设置date属性
    se.Attr = append(se.Attr, xml.Attr{Name: xml.Name{Local: "date"}, Value: tagElement.Date})
    // 写入开始标签
    if err := d.EncodeToken(se); err != nil {
        return err
    }
    // 写入CDATA内容
    cdata := xml.CharData("<![CDATA[" + tagElement.Text + "]]>")
    if err := d.EncodeToken(cdata); err != nil {
        return err
    }
    // 写入结束标签
    if err := d.EncodeToken(se.End()); err != nil {
        return err
    }
    return nil
}

输出结果

运行修改后的代码,会得到符合预期的XML:

In Go: "today is < yesterday"
In Go: "PM,
      1. there are issues with the marshaller
      2. i don't know how to solve them"
<statusdb>
  <status date="today"><![CDATA[today is < yesterday]]></status>
  <status date="yesterday"><![CDATA[PM,
      1. there are issues with the marshaller
      2. i don't know how to solve them]]></status>
</statusdb>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 18:16:34