14

我有以下结构:

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 + ]]><and>将被翻译成&lt;and &gt;

我怎样才能CDATA以最低的成本创建?

4

6 回答 6

16

@spirit-zhang:从 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>

游乐场: https: //play.golang.org/p/xRn6fe0ilj

规则基本上是:1)它必须是,cdata,你不能指定节点名称和2)使用xml.Name你想要的节点命名。

这就是如今 Go 1.6+ 和 XML 的大多数自定义内容的工作方式(带有 的嵌入式结构xml.Name)。


编辑:添加xml:"summary"RootElement结构中,因此您也可以Unmarshal将 xml 反向返回到结构(需要在两个地方都设置)。

于 2017-02-05T20:24:07.937 回答
8

我不确定在哪个版本的 go 中可以使用 innerxml 标记,但它允许您包含不会被转义的数据:

代码:

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>
于 2014-10-27T18:22:15.880 回答
4

带有“,cdata”符号的 CDATA。使用“Cdata”创建结构并与您的 xml 对象一起使用很方便

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))
}

输出:

<Person>
  <Name>John</Name>
  <AGE>12</AGE>
  <ADDRESS><![CDATA[John's House, <House #>: 10,Universe  PIN: 00000  ]]></ADDRESS>
</Person>

游乐场: https: //play.golang.org/p/sux2_JB-hkt

于 2018-10-27T19:22:32.160 回答
3

正如@Tomalak 提到的,不支持输出 CDATA。

您可能可以编写![CDATA[为 xml 标记,然后从生成的 xml 中替换结束标记。这对你有用吗?它可能不是成本最低的,但最简单的。您当然可以在下面的示例中仅用 Marshal 调用替换 MarshalIndent 调用。

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))
}
于 2013-01-07T15:28:34.877 回答
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>
于 2015-02-02T22:20:12.830 回答
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"`
}
于 2016-06-29T05:35:35.413 回答