为何(encoder).EncodeElement忽略",innerxml"标签?Go XML问题求助
Go XML包序列化CDATA时转义特殊字符的原因及解决方法
原因分析
你遇到的问题核心出在自定义的MarshalXML实现上:
- 你先将
status转成statusMarshaller并调用xml.Marshal,得到的是完整的<statusMarshaller>标签的XML字节流。之后调用d.EncodeElement(temp, se)时,Encoder会把这个字节数组当作普通字符串处理,对所有XML特殊字符(比如<、>、")进行转义,所以最终输出里全是<这类转义序列。 - 虽然你给
Text字段加了,innerxml标签,但因为重写了MarshalXML,默认的innerxml逻辑根本没触发,自然不会按你预期的原样写入内容。
解决方法
不需要额外的statusMarshaller类型,也不用嵌套调用xml.Marshal。直接在MarshalXML里手动处理属性和CDATA内容:
- 先写入
<status>标签的属性(比如date); - 直接写入CDATA的前缀
<![CDATA[; - 写入原始文本内容(注意:如果文本里包含
]]>,需要拆分处理,避免破坏CDATA结构,这里假设你的内容里没有这个序列); - 写入CDATA的后缀
]]>; - 关闭
<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
相关产品推荐
相关产品推荐

