Как создать CDATA node xml с 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
с минимальными затратами?
Ответы
Ответ 1
Как отметил @Tomalak, вывод CDATA не поддерживается.
Возможно, вы можете написать ![CDATA[
как тег xml, а затем заменить закрывающий тег из полученного xml. Будет ли это работать на вас? Вероятно, это не тот, у кого минимальные затраты, но самые простые. Разумеется, вы можете заменить вызов 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))
}
Ответ 2
Я не уверен, какая версия тега 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¶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>
Ответ 3
@spirit-zhang: начиная с версии 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
, вы не можете указать имя node и 2) используйте xml.Name
, чтобы назвать node, как вы хотите.
Таким образом, большинство пользовательских материалов для Go 1.6+ и XML работают в наши дни (встроенные структуры с xml.Name
).
EDIT: добавлена xml:"summary"
в структуру RootElement
, поэтому вы также можете Unmarshal
xml вернуться к структуре в обратном порядке (необходимо установить в обоих местах).
Ответ 4
Развернув ответ на @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>
Ответ 5
Если вы используете 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"`
}