Go语言Unmarshal带CDATA的XML时如何优雅移除结果中的CDATA标记?
解决方案
你之前使用chardata标签会把<remark>节点内的所有原始内容都作为普通文本读取,因此会保留CDATA的外层标记,下面是两种无需粗暴使用strings.Replace的实现方案:
方案1:使用标准库原生cdata标签(最优)
Go标准库encoding/xml原生支持CDATA内容的自动解析,你只需要把结构体字段的标签从chardata替换为cdata即可,反序列化时标准库会自动剥离<![CDATA[和]]>标记,全程不需要你手动写任何字符串处理逻辑:
type Ad struct { XMLName xml.Name `xml:"ad"` Remark string `xml:"remark,cdata"` }
该方案无需引入任何第三方依赖,也不会误处理内容中出现的和CDATA标记相似的字符串,是最符合要求的优雅实现。
方案2:自定义反序列化逻辑(适配复杂场景)
如果你的<remark>节点内同时存在普通文本、多段CDATA这类特殊情况,可以通过实现xml.Unmarshaler接口自定义解析逻辑,精准处理内容:
import ( "encoding/xml" "strings" ) type Ad struct { XMLName xml.Name `xml:"ad"` Remark string } func (a *Ad) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { // 定义临时结构接收节点内部原始内容 var tmp struct { InnerXML string `xml:",innerxml"` } if err := d.DecodeElement(&tmp, &start); err != nil { return err } // 循环移除所有CDATA包裹标记,支持节点内多段CDATA的场景 content := tmp.InnerXML for { prefixIdx := strings.Index(content, "<![CDATA[") if prefixIdx == -1 { break } suffixIdx := strings.Index(content[prefixIdx:], "]]>") if suffixIdx == -1 { break } suffixIdx += prefixIdx content = content[:prefixIdx] + content[prefixIdx+9:suffixIdx] + content[suffixIdx+3:] } a.Remark = content return nil }
该方案灵活性更高,可以适配各种非标准的XML结构,且仅精准匹配首尾的CDATA标记,不会全量替换误伤内容。
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

