如何使用go创建一个xml的CDATA节点?

huangapple go评论87阅读模式
英文:

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 + ]]><>会被转换成&lt;&gt;

我如何以最小的代价创建CDATA

英文:

I have the following struct:

type XMLProduct struct {
    XMLName          xml.Name `xml:&quot;row&quot;`
    ProductId        string   `xml:&quot;product_id&quot;`
    ProductName      string   `xml:&quot;product_name&quot;`
    OriginalPrice    string   `xml:&quot;original_price&quot;`
    BargainPrice     string   `xml:&quot;bargain_price&quot;`
    TotalReviewCount int      `xml:&quot;total_review_count&quot;`
    AverageScore     float64  `xml:&quot;average_score&quot;`
}

And I use the encoding/xml to encode this and then display it on web page.

The ProductName field needs to be enclosed with &lt;![CDATA[]]. But if I write it as &lt;![CDATA[ + p.ProductName + ]]&gt;, the &lt; and &gt; will be translated to &amp;lt; and &amp;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 (
	&quot;fmt&quot;
	&quot;encoding/xml&quot;
)

type RootElement struct {
	XMLName xml.Name `xml:&quot;root&quot;`
	Summary *Summary `xml:&quot;summary&quot;`
}

type Summary struct {
	XMLName xml.Name `xml:&quot;summary&quot;`
	Text    string   `xml:&quot;,cdata&quot;`
}

func main() {

	cdata := `&lt;a href=&quot;http://example.org&quot;&gt;My Example Website&lt;/a&gt;`
	v := RootElement{
		Summary: &amp;Summary{
			Text: cdata,
		},
	}
	
	b, err := xml.MarshalIndent(v, &quot;&quot;, &quot;  &quot;)
	if err != nil {
		fmt.Println(&quot;oopsie:&quot;, err)
		return
	}
	fmt.Println(string(b))
}

Outputs:

&lt;root&gt;
  &lt;summary&gt;&lt;![CDATA[&lt;a href=&quot;http://example.org&quot;&gt;My Example Website&lt;/a&gt;]]&gt;&lt;/summary&gt;
&lt;/root&gt;

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:&quot;summary&quot; 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&param2=bar")
	s.Escaped = "http://www.example.com/?param1=foo&param2=bar"
	data, _ := xml.MarshalIndent(s, "", "\t")
	os.Stdout.Write(data)
}

输出:

<SomeXML>
	<Unescaped><![CDATA[http://www.example.com/?param1=foo&param2=bar]]></Unescaped>
	<Escaped>http://www.example.com/?param1=foo&amp;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 (
	&quot;encoding/xml&quot;
	&quot;os&quot;
)

type SomeXML struct {
	Unescaped CharData
	Escaped   string
}

type CharData struct {
	Text []byte `xml:&quot;,innerxml&quot;`
}

func NewCharData(s string) CharData {
	return CharData{[]byte(&quot;&lt;![CDATA[&quot; + s + &quot;]]&gt;&quot;)}
}

func main() {
	var s SomeXML
	s.Unescaped = NewCharData(&quot;http://www.example.com/?param1=foo&amp;param2=bar&quot;)
	s.Escaped = &quot;http://www.example.com/?param1=foo&amp;param2=bar&quot;
	data, _ := xml.MarshalIndent(s, &quot;&quot;, &quot;\t&quot;)
	os.Stdout.Write(data)
}

Output:

&lt;SomeXML&gt;
	&lt;Unescaped&gt;&lt;![CDATA[http://www.example.com/?param1=foo&amp;param2=bar]]&gt;&lt;/Unescaped&gt;
	&lt;Escaped&gt;http://www.example.com/?param1=foo&amp;amp;param2=bar&lt;/Escaped&gt;
&lt;/SomeXML&gt;

答案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 (
	&quot;encoding/xml&quot;
	&quot;fmt&quot;
)

type Person struct {
	Name    string `xml:&quot;Name&quot;`
	Age     int    `xml:&quot;AGE&quot;`
	Address Cdata  `xml:&quot;ADDRESS&quot;`
}

type Cdata struct {
	Value string `xml:&quot;,cdata&quot;`
}

func main() {

	var address Cdata
	address.Value = &quot;John&#39;s House, &lt;House #&gt;: 10,Universe  PIN: 00000 &#128540; &quot;

	var person Person
	person.Name = &quot;John&quot;
	person.Age = 12
	person.Address = address

	xml, err := xml.MarshalIndent(person, &quot;&quot;, &quot;  &quot;)
	if err != nil {
		fmt.Println(&quot;oopsie:&quot;, err.Error())
		return
	}

	fmt.Println(string(xml))
}

Output:

&lt;Person&gt;
  &lt;Name&gt;John&lt;/Name&gt;
  &lt;AGE&gt;12&lt;/AGE&gt;
  &lt;ADDRESS&gt;&lt;![CDATA[John&#39;s House, &lt;House #&gt;: 10,Universe  PIN: 00000 &#128540; ]]&gt;&lt;/ADDRESS&gt;
&lt;/Person&gt;

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 (
	&quot;encoding/xml&quot;
	&quot;fmt&quot;
	&quot;bytes&quot;
)

type XMLProduct struct {
	XMLName          xml.Name `xml:&quot;row&quot;`
	ProductId        string   `xml:&quot;product_id&quot;`
	ProductName      string   `xml:&quot;![CDATA[&quot;`
	OriginalPrice    string   `xml:&quot;original_price&quot;`
	BargainPrice     string   `xml:&quot;bargain_price&quot;`
	TotalReviewCount int      `xml:&quot;total_review_count&quot;`
	AverageScore     float64  `xml:&quot;average_score&quot;`
}

func main() {
	prod := XMLProduct{
		ProductId:        &quot;ProductId&quot;,
		ProductName:      &quot;ProductName&quot;,
		OriginalPrice:    &quot;OriginalPrice&quot;,
		BargainPrice:     &quot;BargainPrice&quot;,
		TotalReviewCount: 20,
		AverageScore:     2.1}

	out, err := xml.MarshalIndent(prod, &quot; &quot;, &quot;  &quot;)
	if err != nil {
		fmt.Printf(&quot;error: %v&quot;, err)
		return
	}

	out = bytes.Replace(out, []byte(&quot;&lt;![CDATA[&gt;&quot;), []byte(&quot;&lt;![CDATA[&quot;), -1)
	out = bytes.Replace(out, []byte(&quot;&lt;/![CDATA[&gt;&quot;), []byte(&quot;]]&gt;&quot;), -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&param2=bar"
    s.Escaped = "http://www.example.com/?param1=foo&param2=bar"
    data, _ := xml.MarshalIndent(s, "", "\t")
    os.Stdout.Write(data)
}

输出:

<SomeXML>
	<Unescaped><![CDATA[http://www.example.com/?param1=foo&param2=bar]]></Unescaped>
	<Escaped>http://www.example.com/?param1=foo&amp;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 (
    &quot;encoding/xml&quot;
    &quot;os&quot;
)

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:&quot;,innerxml&quot;`
    }{
        S: &quot;&lt;![CDATA[&quot; + string(n) + &quot;]]&gt;&quot;,
    }, start)
}

func main() {
    var s SomeXML
    s.Unescaped = &quot;http://www.example.com/?param1=foo&amp;param2=bar&quot;
    s.Escaped = &quot;http://www.example.com/?param1=foo&amp;param2=bar&quot;
    data, _ := xml.MarshalIndent(s, &quot;&quot;, &quot;\t&quot;)
    os.Stdout.Write(data)
}

Output:

&lt;SomeXML&gt;
	&lt;Unescaped&gt;&lt;![CDATA[http://www.example.com/?param1=foo&amp;param2=bar]]&gt;&lt;/Unescaped&gt;
	&lt;Escaped&gt;http://www.example.com/?param1=foo&amp;amp;param2=bar&lt;/Escaped&gt;
&lt;/SomeXML&gt;

答案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:&quot;row&quot;`
    ProductId        string   `xml:&quot;product_id&quot;`
    ProductName      string   `xml:&quot;product_name,cdata&quot;`
    OriginalPrice    string   `xml:&quot;original_price&quot;`
    BargainPrice     string   `xml:&quot;bargain_price&quot;`
    TotalReviewCount int      `xml:&quot;total_review_count&quot;`
    AverageScore     float64  `xml:&quot;average_score&quot;`
}

huangapple
  • 本文由 发表于 2013年1月7日 15:24:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/14191596.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定