How to create a CDATA node of xml with go?

前端 未结 6 1152
自闭症患者
自闭症患者 2021-02-19 09:03

I have the following struct:

type XMLProduct struct {
    XMLName          xml.Name `xml:\"row\"`
    ProductId        string   `xml:\"product_id\"`
    ProductN         


        
相关标签:
6条回答
  • 2021-02-19 09:26

    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))
    }
    
    0 讨论(0)
  • 2021-02-19 09:27

    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                                                                     
    0 讨论(0)
  • 2021-02-19 09:27

    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"`
    }
    
    0 讨论(0)
  • 2021-02-19 09:28

    @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).

    0 讨论(0)
  • 2021-02-19 09:35

    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>
    
    0 讨论(0)
  • 2021-02-19 09:39

    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>
    
    0 讨论(0)
提交回复
热议问题