英文:
How to create a CDATA node of xml with go?
问题
我有以下的结构体:
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"`
}
我使用encoding/xml
来编码它,然后在网页上显示。
ProductName
字段需要用<![CDATA[]]>
括起来。但是如果我写成<![CDATA[ + p.ProductName + ]]>
,<
和>
会被转换成<
和>
。
我如何以最小的代价创建CDATA
?
英文:
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 &lt;
and &gt;
.
How can I create the CDATA
at minimal cost?
答案1
得分: 18
自Go 1.6以来,你现在可以使用,cdata
标签:
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))
}
输出:
<root>
<summary><![CDATA[<a href="http://example.org">My Example Website</a>]]></summary>
</root>
Playground: https://play.golang.org/p/xRn6fe0ilj
基本规则是:1)它必须是,cdata
,不能指定节点名称;2)使用xml.Name
来命名节点。
这是Go 1.6+和XML的大多数自定义内容的工作方式(使用嵌入的xml.Name
结构)。
英文:
@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).
答案2
得分: 8
我不确定innerxml标签是在哪个版本的go中可用的,但它允许您包含不会被转义的数据:
代码:
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)
}
输出:
<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&param2=bar")
s.Escaped = "http://www.example.com/?param1=foo&param2=bar"
data, _ := xml.MarshalIndent(s, "", "\t")
os.Stdout.Write(data)
}
Output:
<SomeXML>
<Unescaped><![CDATA[http://www.example.com/?param1=foo&param2=bar]]></Unescaped>
<Escaped>http://www.example.com/?param1=foo&amp;param2=bar</Escaped>
</SomeXML>
答案3
得分: 4
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
英文:
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
答案4
得分: 3
如@Tomalak所提到的,输出CDATA是不被支持的。
你可以将![CDATA[
写成xml标签,然后在生成的xml中替换闭合标签。这对你有用吗?这可能不是最低成本的方法,但是最简单。你当然可以在下面的示例中用Marshal调用替换MarshalIndent调用。
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))
}
英文:
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))
}
答案5
得分: 3
扩展了@BeMasher的答案,你可以使用xml.Marshaller
接口来完成工作。
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)
}
输出:
<SomeXML>
<Unescaped><![CDATA[http://www.example.com/?param1=foo¶m2=bar]]></Unescaped>
<Escaped>http://www.example.com/?param1=foo&param2=bar</Escaped>
</SomeXML>
英文:
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&param2=bar"
s.Escaped = "http://www.example.com/?param1=foo&param2=bar"
data, _ := xml.MarshalIndent(s, "", "\t")
os.Stdout.Write(data)
}
Output:
<SomeXML>
<Unescaped><![CDATA[http://www.example.com/?param1=foo&param2=bar]]></Unescaped>
<Escaped>http://www.example.com/?param1=foo&amp;param2=bar</Escaped>
</SomeXML>
答案6
得分: 0
如果您使用的是Go版本1.6或更高版本,只需添加'cdata'标签即可正常工作。
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"
}
英文:
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"`
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论