Write XML code to XML file in Go

huangapple go评论108阅读模式
英文:

Write XML code to XML file in Go

问题

我有一个打印XML代码的脚本,但我需要它能够创建一个新的XML文件,并将代码写入该文件,而不是打印出来。

以下是打印XML代码的函数:

  1. func processTopic(id string, properties map[string][]string) {
  2. fmt.Printf("<card entity=\"%s\">\n", id)
  3. fmt.Println(" <facts>")
  4. for k, v := range properties {
  5. for _, value := range v {
  6. fmt.Printf(" <fact property=\"%s\">%s</fact>\n", k, value)
  7. }
  8. }
  9. fmt.Println(" </facts>")
  10. fmt.Println("</card>")
  11. }

我该如何修改它,使其能够创建一个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

  1. func processTopic(id string, properties map[string][]string) {
  2. fmt.Printf(&quot;&lt;card entity=\&quot;%s\&quot;&gt;\n&quot;, id)
  3. fmt.Println(&quot; &lt;facts&gt;&quot;)
  4. for k, v := range properties {
  5. for _,value := range v {
  6. fmt.Printf(&quot; &lt;fact property=\&quot;%s\&quot;&gt;%s&lt;/fact&gt;\n&quot;, k, value)
  7. }
  8. }
  9. fmt.Println(&quot; &lt;/facts&gt;&quot;)
  10. fmt.Println(&quot;&lt;/card&gt;&quot;)
  11. }

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结构:

  1. type Card struct {
  2. Entity string `xml:"entity,attr"`
  3. Facts Facts
  4. }
  5. type Facts struct {
  6. Fact []Fact
  7. }
  8. type Fact struct {
  9. Property string `xml:"property,attr"`
  10. Value string `xml:",innerxml"`
  11. }

可以按照以下方式创建数据结构(在playground上运行示例):

  1. card := &Card{
  2. Entity: "1234id",
  3. Facts: Facts{[]Fact{
  4. Fact{Property: "prop1", Value: "val1"},
  5. Fact{Property: "prop2", Value: "val2"},
  6. }},
  7. }

现在,可以将该结构编码为XML并直接写入io.Writer

  1. writer, err := os.Open("/tmp/tmp.xml")
  2. encoder := xml.NewEncoder(writer)
  3. err := encoder.Encode(data)
  4. if err != nil {
  5. panic(err)
  6. }
英文:

While printing your XML may be fine, why not use the encoding/xml package?
Have your XML structure in go:

  1. type Card struct {
  2. Entity string `xml:&quot;entity,attr&quot;`
  3. Facts Facts
  4. }
  5. type Facts struct {
  6. Fact []Fact
  7. }
  8. type Fact struct {
  9. Property string `xml:&quot;property,attr&quot;`
  10. Value string `xml:&quot;,innerxml&quot;`
  11. }

Create your data structure like this (running example on play):

  1. card := &amp;Card{
  2. Entity: &quot;1234id&quot;,
  3. Facts: Facts{[]Fact{
  4. Fact{Property: &quot;prop1&quot;, Value: &quot;val1&quot;},
  5. Fact{Property: &quot;prop2&quot;, Value: &quot;val2&quot;},
  6. }},
  7. }

Now you can encode the structure to XML and write it directly to a io.Writer:

  1. writer, err := os.Open(&quot;/tmp/tmp.xml&quot;)
  2. encoder := xml.NewEncoder(writer)
  3. err := encoder.Encode(data)
  4. if err != nil { panic(err) }

答案2

得分: 3

使用os.Create函数打开文件,并使用fmt.Fprintf函数向文件中写入内容。

示例代码:

  1. f, err := os.Create("out.xml") // 创建/截断文件
  2. if err != nil { panic(err) } // 如果出错则抛出异常
  3. defer f.Close() // 确保文件在使用后关闭
  4. fmt.Fprintf(f, "<card entity=\"%s\">\n", id)
  5. // ...

请注意,以上代码是使用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:

  1. f, err := os.Create(&quot;out.xml&quot;) // create/truncate the file
  2. if err != nil { panic(err) } // panic if error
  3. defer f.Close() // make sure it gets closed after
  4. fmt.Fprintf(f, &quot;&lt;card entity=\&quot;%s\&quot;&gt;\n&quot;, id)
  5. // ...

答案3

得分: 2

为了补充bgp的正确答案,通过将函数更改为接受io.Writer作为参数,您可以将XML输出到实现io.Writer接口的任何类型的输出。

  1. func processTopic(w io.Writer, id string, properties map[string][]string) {
  2. fmt.Fprintf(w, "<card entity=\"%s\">\n", id)
  3. fmt.Fprintln(w, " <facts>")
  4. for k, v := range properties {
  5. for _, value := range v {
  6. fmt.Fprintf(w, " <fact property=\"%s\">%s</fact>\n", k, value)
  7. }
  8. }
  9. fmt.Fprintln(w, " </facts>")
  10. fmt.Fprintln(w, "</card>")
  11. }

输出到屏幕(Stdout):

  1. processTopic(os.Stdout, id, properties)

写入文件(代码取自bgp的答案):

  1. f, err := os.Create("out.xml") // 创建/截断文件
  2. if err != nil { panic(err) } // 如果出错则抛出异常
  3. defer f.Close() // 确保在之后关闭文件
  4. 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.

  1. func processTopic(w io.Writer, id string, properties map[string][]string) {
  2. fmt.Fprintf(w, &quot;&lt;card entity=\&quot;%s\&quot;&gt;\n&quot;, id)
  3. fmt.Fprintln(w, &quot; &lt;facts&gt;&quot;)
  4. for k, v := range properties {
  5. for _,value := range v {
  6. fmt.Fprintf(w, &quot; &lt;fact property=\&quot;%s\&quot;&gt;%s&lt;/fact&gt;\n&quot;, k, value)
  7. }
  8. }
  9. fmt.Fprintln(w, &quot; &lt;/facts&gt;&quot;)
  10. fmt.Fprintln(w, &quot;&lt;/card&gt;&quot;)
  11. }

Printing to screen (Stdout):

  1. processTopic(os.Stdout, id, properties)

Writing to file (code taken from bgp's answer):

  1. f, err := os.Create(&quot;out.xml&quot;) // create/truncate the file
  2. if err != nil { panic(err) } // panic if error
  3. defer f.Close() // make sure it gets closed after
  4. processTopic(f, id, properties)

答案4

得分: 0

根据nemo的评论,根据你接收到的fact数据的方式,如果它作为map[string]string接收,那么你也可以为fact映射创建一个Marshaler和Unmarshaler。这在处理不按顺序接收的较大数据集时可能会更复杂,但也可能会更有帮助(例如,无序映射与有序数组/切片相比)。

  1. package main
  2. import (
  3. "encoding/xml"
  4. "io"
  5. "os"
  6. )
  7. type FactMap map[string]string
  8. type factXml struct {
  9. XMLName xml.Name `xml:"fact"`
  10. Prop string `xml:"property,attr"`
  11. Value string `xml:",innerxml"`
  12. }
  13. // Marshal the fact map
  14. func (fm FactMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  15. if len(fm) == 0 {
  16. return nil
  17. }
  18. err := e.EncodeToken(start)
  19. if err != nil {
  20. return err
  21. }
  22. for k, v := range fm {
  23. // XML encoding the `fact` XML entry
  24. e.Encode(factXml{Prop: k, Value: v})
  25. }
  26. return e.EncodeToken(start.End())
  27. }
  28. // Unmarshal the fact map
  29. func (fm *FactMap) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
  30. *fm = FactMap{}
  31. for {
  32. var f factXml
  33. err := d.Decode(&f)
  34. if err == io.EOF {
  35. break
  36. } else if err != nil {
  37. return err
  38. }
  39. (*fm)[f.Prop] = f.Value
  40. }
  41. return nil
  42. }
  43. // Note usage of xml.Name to set the outer XML to `card`, as well as setting Entity as an `entity,attr`
  44. type Card struct {
  45. XMLName xml.Name `xml:"card"`
  46. Entity int `xml:"entity,attr"`
  47. Facts FactMap `xml:"facts"`
  48. }
  49. func main() {
  50. props1 := map[string]string{"key1": "val1", "key2": "val2"}
  51. // Populate the Card struct and marshal it
  52. card := Card{Entity: 5, Facts: props1}
  53. // Append to the file
  54. var f *os.File
  55. // Check if the file exists, err != nil if the file does not exist
  56. _, err := os.Stat("my.xml")
  57. if err != nil {
  58. // if the file doesn't exist, open it with write and create flags
  59. f, err = os.OpenFile("my.xml", os.O_WRONLY|os.O_CREATE, 0666)
  60. } else {
  61. // if the file does exist, open it with append and write flags
  62. f, err = os.OpenFile("my.xml", os.O_APPEND|os.O_WRONLY, 0666)
  63. }
  64. if err != nil {
  65. panic(err)
  66. }
  67. defer f.Close()
  68. e := xml.NewEncoder(f)
  69. // Write marshal the card struct to the file
  70. err = e.Encode(card)
  71. if err != nil {
  72. panic(err)
  73. }
  74. }
英文:

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

  1. package main
  2. import (
  3. &quot;encoding/xml&quot;
  4. &quot;io&quot;
  5. &quot;os&quot;
  6. )
  7. type FactMap map[string]string
  8. type factXml struct {
  9. XMLName xml.Name `xml:&quot;fact&quot;`
  10. Prop string `xml:&quot;property,attr&quot;`
  11. Value string `xml:&quot;,innerxml&quot;`
  12. }
  13. // Marshal the fact map
  14. func (fm FactMap) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
  15. if len(fm) == 0 {
  16. return nil
  17. }
  18. err := e.EncodeToken(start)
  19. if err != nil {
  20. return err
  21. }
  22. for k, v := range fm {
  23. // XML encoding the `fact` XML entry
  24. e.Encode(factXml{Prop: k, Value: v})
  25. }
  26. return e.EncodeToken(start.End())
  27. }
  28. // Unmarshal the fact map
  29. func (fm *FactMap) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
  30. *fm = FactMap{}
  31. for {
  32. var f factXml
  33. err := d.Decode(&amp;f)
  34. if err == io.EOF {
  35. break
  36. } else if err != nil {
  37. return err
  38. }
  39. (*fm)[f.Prop] = f.Value
  40. }
  41. return nil
  42. }
  43. // Note usage of xml.Name to set the outer XML to `card`, as well as setting Entity as an `entity,attr`
  44. type Card struct {
  45. XMLName xml.Name `xml:&quot;card&quot;`
  46. Entity int `xml:&quot;entity,attr&quot;`
  47. Facts FactMap `xml:&quot;facts&quot;`
  48. }
  49. func main() {
  50. props1 := map[string]string{&quot;key1&quot;: &quot;val1&quot;, &quot;key2&quot;: &quot;val2&quot;}
  51. // Populate the Card struct and marshal it
  52. card := Card{Entity: 5, Facts: props1}
  53. // Append to the file
  54. var f *os.File
  55. // Check if thet file exists, err != nil if the file does not exist
  56. _, err := os.Stat(&quot;my.xml&quot;)
  57. if err != nil {
  58. // if the file doesn&#39;t exist, open it with write and create flags
  59. f, err = os.OpenFile(&quot;my.xml&quot;, os.O_WRONLY|os.O_CREATE, 0666)
  60. } else {
  61. // if the file does exist, open it with append and write flags
  62. f, err = os.OpenFile(&quot;my.xml&quot;, os.O_APPEND|os.O_WRONLY, 0666)
  63. }
  64. if err != nil {
  65. panic(err)
  66. }
  67. defer f.Close()
  68. e := xml.NewEncoder(f)
  69. // Write marshal the card struct to the file
  70. err = e.Encode(card)
  71. if err != nil {
  72. panic(err)
  73. }
  74. }

huangapple
  • 本文由 发表于 2013年10月8日 10:30:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/19238114.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定