I have the following struct:
type XMLProduct struct {
XMLName xml.Name `xml:"row"`
ProductId string `xml:"product_id"`
ProductName string `xml:"product_name"`
OriginalPrice string `xml:"original_price"`
BargainPrice string `xml:"bargain_price"`
TotalReviewCount int `xml:"total_review_count"`
AverageScore float64 `xml:"average_score"`
}
And I use the encoding/xml
to encode this and then display it on web page.
The ProductName
field needs to be enclosed with <![CDATA[]]
. But if I write it as <![CDATA[ + p.ProductName + ]]>
, the <
and >
will be translated to <
and >
.
How can I create the CDATA
at minimal cost?
CDATA sections can appear inside element content and allow < and & character literals to appear. A CDATA section begins with the character sequence <! [CDATA[ and ends with the character sequence ]]>. Between the two character sequences, an XML processor ignores all markup characters such as <, >, and &.
In current Java DOM implementation you can access CDATA simply as text data using e. getTextContent() . See example without type check, cast, e. getData() .
A CDATA section is used to mark a section of an XML document, so that the XML parser interprets it only as character data, and not as markup. It comes handy when one XML data need to be embedded within another XML document.
No, The markup denoting a CDATA Section is not permitted as the value of an attribute.
@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).
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>
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 😜 "
var person Person
person.Name = "John"
person.Age = 12
person.Address = address
xml, err := xml.MarshalIndent(person, "", " ")
if err != nil {
fmt.Println("oopsie:", err.Error())
return
}
fmt.Println(string(xml))
}
Output:
<Person>
<Name>John</Name>
<AGE>12</AGE>
<ADDRESS><![CDATA[John's House, <House #>: 10,Universe PIN: 00000 😜 ]]></ADDRESS>
</Person>
Playground: https://play.golang.org/p/sux2_JB-hkt
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))
}
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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With