5

我有一个打印行 XML 代码的脚本,但我需要它来编写一个新的 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

4 回答 4

19

虽然打印您的 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"`
}

像这样创建您的数据结构(在 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) }
于 2013-10-09T00:14:11.540 回答
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)
// ...
于 2013-10-08T03:37:54.177 回答
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)
于 2013-10-08T08:50:18.930 回答
0

支持 nemo 对encoding/xml; 根据您接收fact数据的方式,如果它是作为 a 接收的,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)
    }
}
于 2017-10-02T04:09:51.917 回答