Как создать CDATA узел 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 + ]]>
, the <
и >
будет переведен на <
и >
.
как я могу создать CDATA
при минимальных затратах?
5 ответов
Как упоминал @Tomalak, вывод CDATA не поддерживается.
вы, вероятно, можете написать ![CDATA[
как XML-тег и позже заменить закрывающий тег из результирующего xml. Это сработает для тебя? Это, вероятно, не тот, с минимальными затратами, но самый простой. Конечно, вы можете заменить вызов MarshalIndent только вызовом Marshal в приведенном ниже примере.
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))
}
Я не уверен, в какой версии 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¶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>
@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
).
EDIT: добавлено xml:"summary"
до RootElement
struct, так что вы можете вы также можете Unmarshal
xml возвращается к структуре в обратном порядке (требуется установить в обоих местах).
расширение ответа @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>
Если вы используете 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"`
}