将XML代码写入Go中的XML文件

时间:2013-10-08 02:30:43

标签: xml 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文件,然后将代码写入该XML文件?

4 个答案:

答案 0 :(得分:14)

打印XML时可能没问题,为什么不使用encoding/xml包呢? 你的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"`
}

像这样创建数据结构(running example on play):

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

答案 1 :(得分:3)

使用os.Create打开文件并使用fmt.Fprintf写入文件。

示例:

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

答案 2 :(得分:2)

添加到bgp的(+1)正确答案;通过更改函数以将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>")
}

打印到屏幕(标准输出):

processTopic(os.Stdout, id, properties)

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

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)

答案 3 :(得分:0)

支持nemo对encoding/xml的评论;根据您收到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 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)
    }
}