英文:
Write XML code to XML file in Go
问题
我有一个打印XML代码的脚本,但我需要它能够创建一个新的XML文件,并将代码写入该文件,而不是打印出来。
以下是打印XML代码的函数:
func processTopic(id string, properties map[string][]string) {
fmt.Printf("<card entity=\"%s\">\n", id)
fmt.Println(" <facts>")
for k, v := range properties {
for _, value := range v {
fmt.Printf(" <fact property=\"%s\">%s</fact>\n", k, value)
}
}
fmt.Println(" </facts>")
fmt.Println("</card>")
}
我该如何修改它,使其能够创建一个XML文件,并将代码写入该文件呢?
英文:
I have a script that print-lines XML code, but I need it to write a new XML file and then write the XML code to the file instead of printing it.
Here is the function that prints the XML code
func processTopic(id string, properties map[string][]string) {
fmt.Printf("<card entity=\"%s\">\n", id)
fmt.Println(" <facts>")
for k, v := range properties {
for _,value := range v {
fmt.Printf(" <fact property=\"%s\">%s</fact>\n", k, value)
}
}
fmt.Println(" </facts>")
fmt.Println("</card>")
}
How can I get it to write an XML file and then write the code to that XML file?
答案1
得分: 19
使用encoding/xml
包来处理XML可能更好。在Go中,可以定义如下的XML结构:
type Card struct {
Entity string `xml:"entity,attr"`
Facts Facts
}
type Facts struct {
Fact []Fact
}
type Fact struct {
Property string `xml:"property,attr"`
Value string `xml:",innerxml"`
}
可以按照以下方式创建数据结构(在playground上运行示例):
card := &Card{
Entity: "1234id",
Facts: Facts{[]Fact{
Fact{Property: "prop1", Value: "val1"},
Fact{Property: "prop2", Value: "val2"},
}},
}
现在,可以将该结构编码为XML并直接写入io.Writer
:
writer, err := os.Open("/tmp/tmp.xml")
encoder := xml.NewEncoder(writer)
err := encoder.Encode(data)
if err != nil {
panic(err)
}
英文:
While printing your XML may be fine, why not use the encoding/xml
package?
Have your XML structure in go:
type Card struct {
Entity string `xml:"entity,attr"`
Facts Facts
}
type Facts struct {
Fact []Fact
}
type Fact struct {
Property string `xml:"property,attr"`
Value string `xml:",innerxml"`
}
Create your data structure like this (running example on play):
card := &Card{
Entity: "1234id",
Facts: Facts{[]Fact{
Fact{Property: "prop1", Value: "val1"},
Fact{Property: "prop2", Value: "val2"},
}},
}
Now you can encode the structure to XML and write it directly to a io.Writer
:
writer, err := os.Open("/tmp/tmp.xml")
encoder := xml.NewEncoder(writer)
err := encoder.Encode(data)
if err != nil { panic(err) }
答案2
得分: 3
使用os.Create
函数打开文件,并使用fmt.Fprintf
函数向文件中写入内容。
示例代码:
f, err := os.Create("out.xml") // 创建/截断文件
if err != nil { panic(err) } // 如果出错则抛出异常
defer f.Close() // 确保文件在使用后关闭
fmt.Fprintf(f, "<card entity=\"%s\">\n", id)
// ...
请注意,以上代码是使用Go语言编写的示例代码,用于打开文件并向其中写入内容。
英文:
Use <a href="http://golang.org/pkg/os/#Create">os.Create</a> to open the file and use <a href="http://golang.org/pkg/fmt/#Fprintf">fmt.Fprintf</a> to write to it.
Example:
f, err := os.Create("out.xml") // create/truncate the file
if err != nil { panic(err) } // panic if error
defer f.Close() // make sure it gets closed after
fmt.Fprintf(f, "<card entity=\"%s\">\n", id)
// ...
答案3
得分: 2
为了补充bgp的正确答案,通过将函数更改为接受io.Writer作为参数,您可以将XML输出到实现io.Writer接口的任何类型的输出。
func processTopic(w io.Writer, id string, properties map[string][]string) {
fmt.Fprintf(w, "<card entity=\"%s\">\n", id)
fmt.Fprintln(w, " <facts>")
for k, v := range properties {
for _, value := range v {
fmt.Fprintf(w, " <fact property=\"%s\">%s</fact>\n", k, value)
}
}
fmt.Fprintln(w, " </facts>")
fmt.Fprintln(w, "</card>")
}
输出到屏幕(Stdout):
processTopic(os.Stdout, id, properties)
写入文件(代码取自bgp的答案):
f, err := os.Create("out.xml") // 创建/截断文件
if err != nil { panic(err) } // 如果出错则抛出异常
defer f.Close() // 确保在之后关闭文件
processTopic(f, id, properties)
英文:
To add to bgp's (+1) correct answer; by changing the function to take a io.Writer as argument, you can output your XML to any type of output implementing the io.Writer interface.
func processTopic(w io.Writer, id string, properties map[string][]string) {
fmt.Fprintf(w, "<card entity=\"%s\">\n", id)
fmt.Fprintln(w, " <facts>")
for k, v := range properties {
for _,value := range v {
fmt.Fprintf(w, " <fact property=\"%s\">%s</fact>\n", k, value)
}
}
fmt.Fprintln(w, " </facts>")
fmt.Fprintln(w, "</card>")
}
Printing to screen (Stdout):
processTopic(os.Stdout, id, properties)
Writing to file (code taken from bgp's answer):
f, err := os.Create("out.xml") // create/truncate the file
if err != nil { panic(err) } // panic if error
defer f.Close() // make sure it gets closed after
processTopic(f, id, properties)
答案4
得分: 0
根据nemo的评论,根据你接收到的fact
数据的方式,如果它作为map[string]string
接收,那么你也可以为fact
映射创建一个Marshaler和Unmarshaler。这在处理不按顺序接收的较大数据集时可能会更复杂,但也可能会更有帮助(例如,无序映射与有序数组/切片相比)。
package main
import (
"encoding/xml"
"io"
"os"
)
type FactMap map[string]string
type factXml struct {
XMLName xml.Name `xml:"fact"`
Prop string `xml:"property,attr"`
Value string `xml:",innerxml"`
}
// Marshal the fact map
func (fm FactMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if len(fm) == 0 {
return nil
}
err := e.EncodeToken(start)
if err != nil {
return err
}
for k, v := range fm {
// XML encoding the `fact` XML entry
e.Encode(factXml{Prop: k, Value: v})
}
return e.EncodeToken(start.End())
}
// Unmarshal the fact map
func (fm *FactMap) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
*fm = FactMap{}
for {
var f factXml
err := d.Decode(&f)
if err == io.EOF {
break
} else if err != nil {
return err
}
(*fm)[f.Prop] = f.Value
}
return nil
}
// Note usage of xml.Name to set the outer XML to `card`, as well as setting Entity as an `entity,attr`
type Card struct {
XMLName xml.Name `xml:"card"`
Entity int `xml:"entity,attr"`
Facts FactMap `xml:"facts"`
}
func main() {
props1 := map[string]string{"key1": "val1", "key2": "val2"}
// Populate the Card struct and marshal it
card := Card{Entity: 5, Facts: props1}
// Append to the file
var f *os.File
// Check if the file exists, err != nil if the file does not exist
_, err := os.Stat("my.xml")
if err != nil {
// if the file doesn't exist, open it with write and create flags
f, err = os.OpenFile("my.xml", os.O_WRONLY|os.O_CREATE, 0666)
} else {
// if the file does exist, open it with append and write flags
f, err = os.OpenFile("my.xml", os.O_APPEND|os.O_WRONLY, 0666)
}
if err != nil {
panic(err)
}
defer f.Close()
e := xml.NewEncoder(f)
// Write marshal the card struct to the file
err = e.Encode(card)
if err != nil {
panic(err)
}
}
英文:
Supporting nemo's comment on the encoding/xml
; depending on how you're receiving the fact
data, if it is received as a map[string]string
then you can also create a Marshaler and Unmarshaler for the fact
map. This is slightly more complexcan be helpful if you're dealing with larger sets of data that you're not receiving in an ordered manner (ie. unordered map vs ordered array/slice).
package main
import (
"encoding/xml"
"io"
"os"
)
type FactMap map[string]string
type factXml struct {
XMLName xml.Name `xml:"fact"`
Prop string `xml:"property,attr"`
Value string `xml:",innerxml"`
}
// Marshal the fact map
func (fm FactMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
if len(fm) == 0 {
return nil
}
err := e.EncodeToken(start)
if err != nil {
return err
}
for k, v := range fm {
// XML encoding the `fact` XML entry
e.Encode(factXml{Prop: k, Value: v})
}
return e.EncodeToken(start.End())
}
// Unmarshal the fact map
func (fm *FactMap) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
*fm = FactMap{}
for {
var f factXml
err := d.Decode(&f)
if err == io.EOF {
break
} else if err != nil {
return err
}
(*fm)[f.Prop] = f.Value
}
return nil
}
// Note usage of xml.Name to set the outer XML to `card`, as well as setting Entity as an `entity,attr`
type Card struct {
XMLName xml.Name `xml:"card"`
Entity int `xml:"entity,attr"`
Facts FactMap `xml:"facts"`
}
func main() {
props1 := map[string]string{"key1": "val1", "key2": "val2"}
// Populate the Card struct and marshal it
card := Card{Entity: 5, Facts: props1}
// Append to the file
var f *os.File
// Check if thet file exists, err != nil if the file does not exist
_, err := os.Stat("my.xml")
if err != nil {
// if the file doesn't exist, open it with write and create flags
f, err = os.OpenFile("my.xml", os.O_WRONLY|os.O_CREATE, 0666)
} else {
// if the file does exist, open it with append and write flags
f, err = os.OpenFile("my.xml", os.O_APPEND|os.O_WRONLY, 0666)
}
if err != nil {
panic(err)
}
defer f.Close()
e := xml.NewEncoder(f)
// Write marshal the card struct to the file
err = e.Encode(card)
if err != nil {
panic(err)
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论