I have the following struct:
type XMLProduct struct {
XMLName xml.Name `xml:\"row\"`
ProductId string `xml:\"product_id\"`
ProductN
As @Tomalak mentioned, outputting CDATA is not supported.
You can probably write ![CDATA[
as xml tag and later on replace the closing tag from the resulting xml. Will this work for you? Its probably not the one with minimal costs, but easiest. You can of course replace the MarshalIndent call with just the Marshal call in the example below.
http://play.golang.org/p/2-u7H85-wn
package main
import (
"encoding/xml"
"fmt"
"bytes"
)
type XMLProduct struct {
XMLName xml.Name `xml:"row"`
ProductId string `xml:"product_id"`
ProductName string `xml:"![CDATA["`
OriginalPrice string `xml:"original_price"`
BargainPrice string `xml:"bargain_price"`
TotalReviewCount int `xml:"total_review_count"`
AverageScore float64 `xml:"average_score"`
}
func main() {
prod := XMLProduct{
ProductId: "ProductId",
ProductName: "ProductName",
OriginalPrice: "OriginalPrice",
BargainPrice: "BargainPrice",
TotalReviewCount: 20,
AverageScore: 2.1}
out, err := xml.MarshalIndent(prod, " ", " ")
if err != nil {
fmt.Printf("error: %v", err)
return
}
out = bytes.Replace(out, []byte("<![CDATA[>"), []byte("<![CDATA["), -1)
out = bytes.Replace(out, []byte("</![CDATA[>"), []byte("]]>"), -1)
fmt.Println(string(out))
}
CDATA with ",cdata" notation. It is handy to create struct with "Cdata" and use along with your xml object
package main
import (
"encoding/xml"
"fmt"
)
type Person struct {
Name string `xml:"Name"`
Age int `xml:"AGE"`
Address Cdata `xml:"ADDRESS"`
}
type Cdata struct {
Value string `xml:",cdata"`
}
func main() {
var address Cdata
address.Value = "John's House, <House #>: 10,Universe PIN: 00000
If you use Go version 1.6 or later, just adding 'cdata' tag will work fine.
type XMLProduct struct {
XMLName xml.Name `xml:"row"`
ProductId string `xml:"product_id"`
ProductName string `xml:"product_name,cdata"`
OriginalPrice string `xml:"original_price"`
BargainPrice string `xml:"bargain_price"`
TotalReviewCount int `xml:"total_review_count"`
AverageScore float64 `xml:"average_score"`
}
@spirit-zhang: since Go 1.6, you can now use ,cdata
tags:
package main
import (
"fmt"
"encoding/xml"
)
type RootElement struct {
XMLName xml.Name `xml:"root"`
Summary *Summary `xml:"summary"`
}
type Summary struct {
XMLName xml.Name `xml:"summary"`
Text string `xml:",cdata"`
}
func main() {
cdata := `<a href="http://example.org">My Example Website</a>`
v := RootElement{
Summary: &Summary{
Text: cdata,
},
}
b, err := xml.MarshalIndent(v, "", " ")
if err != nil {
fmt.Println("oopsie:", err)
return
}
fmt.Println(string(b))
}
Outputs:
<root>
<summary><![CDATA[<a href="http://example.org">My Example Website</a>]]></summary>
</root>
Playground: https://play.golang.org/p/xRn6fe0ilj
The rules are basically: 1) it has to be ,cdata
, you can't specify the node name and 2) use the xml.Name
to name the node as you want.
This is how most of the custom stuff for Go 1.6+ and XML works these days (embedded structs with xml.Name
).
EDIT: Added xml:"summary"
to the RootElement
struct, so you can you can also Unmarshal
the xml back to the struct in reverse (required to be set in both places).
Expanding on the answer by @BeMasher, you can use the xml.Marshaller
interface to do the work for you.
package main
import (
"encoding/xml"
"os"
)
type SomeXML struct {
Unescaped CharData
Escaped string
}
type CharData string
func (n CharData) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
return e.EncodeElement(struct{
S string `xml:",innerxml"`
}{
S: "<![CDATA[" + string(n) + "]]>",
}, start)
}
func main() {
var s SomeXML
s.Unescaped = "http://www.example.com/?param1=foo¶m2=bar"
s.Escaped = "http://www.example.com/?param1=foo¶m2=bar"
data, _ := xml.MarshalIndent(s, "", "\t")
os.Stdout.Write(data)
}
Output:
<SomeXML>
<Unescaped><![CDATA[http://www.example.com/?param1=foo¶m2=bar]]></Unescaped>
<Escaped>http://www.example.com/?param1=foo&param2=bar</Escaped>
</SomeXML>
I'm not sure which version of go the innerxml tag became available in, but it allows you to include data which won't be escaped:
Code:
package main
import (
"encoding/xml"
"os"
)
type SomeXML struct {
Unescaped CharData
Escaped string
}
type CharData struct {
Text []byte `xml:",innerxml"`
}
func NewCharData(s string) CharData {
return CharData{[]byte("<![CDATA[" + s + "]]>")}
}
func main() {
var s SomeXML
s.Unescaped = NewCharData("http://www.example.com/?param1=foo¶m2=bar")
s.Escaped = "http://www.example.com/?param1=foo¶m2=bar"
data, _ := xml.MarshalIndent(s, "", "\t")
os.Stdout.Write(data)
}
Output:
<SomeXML>
<Unescaped><![CDATA[http://www.example.com/?param1=foo¶m2=bar]]></Unescaped>
<Escaped>http://www.example.com/?param1=foo&param2=bar</Escaped>
</SomeXML>