Go 1.20:xml.Marshal生成XML时如何保留未编码URL?站点地图开发
问题:XML序列化时避免URL编码(Go 1.20)
我正在为网站开发站点地图,不希望URL被编码。使用Go 1.20版本,当前代码如下:
package main import ( "encoding/xml" "fmt" ) func main() { testXML() } type ElementTree struct { Href string `xml:"href,attr"` } func testXML() { e := ElementTree{ Href: "https://www.test.com?a=1&b=2", } indent, err := xml.MarshalIndent(e, "", "\t") if err != nil { fmt.Println(err.Error()) return } //<ElementTree href="https://www.test.com?a=1&b=2"></ElementTree> fmt.Println(string(indent)) }
当前代码输出为:
<ElementTree href="https://www.test.com?a=1&b=2"></ElementTree>
我期望得到的结果是:
<ElementTree href="https://www.test.com?a=1&b=2"></ElementTree>
请问如何实现该需求?XML属性中的URL是否必须进行编码?
实现方法
Go标准库的encoding/xml默认会转义XML属性里的特殊字符(比如&),这是符合XML规范的行为。要跳过转义,得自定义xml.Marshaler接口来手动处理序列化逻辑:
package main import ( "encoding/xml" "fmt" "io" ) type ElementTree struct { Href string `xml:"href,attr"` } // 自定义MarshalXML方法,绕过默认转义 func (e ElementTree) MarshalXML(w io.Writer, start xml.StartElement) error { // 直接将原始URL作为属性值添加 start.Attr = append(start.Attr, xml.Attr{ Name: xml.Name{Local: "href"}, Value: e.Href, }) // 写入开始标签 if err := start.WriteTo(w); err != nil { return err } // 写入结束标签(当前结构体没有子元素) end := xml.EndElement{Name: start.Name} return end.WriteTo(w) } func main() { testXML() } func testXML() { e := ElementTree{ Href: "https://www.test.com?a=1&b=2", } indent, err := xml.MarshalIndent(e, "", "\t") if err != nil { fmt.Println(err.Error()) return } fmt.Println(string(indent)) }
运行这段代码就能得到你想要的未编码URL输出。
XML属性中的URL是否必须编码?
严格按照XML规范,属性值里的&必须转义成&——因为&在XML里是特殊字符,用来标识实体引用的起始,不转义会导致XML解析器报错。
不过站点地图的场景比较特殊,大多数搜索引擎能兼容未转义的&,但这不代表格式合法。如果硬要输出未转义的URL,得承担风险:部分严格的XML解析工具可能无法正确读取你的站点地图。
内容的提问来源于stack exchange,提问作者shsf
相关产品推荐
相关产品推荐

