通过Go来分析和创建XML

一、分析XML

下面有一个xml文件让你分析。

<?xml version="1.0" encoding="utf-8"?>
<post id="1">
    <content>Hello World!</content>
    <author id="2">Sau She</author>
    <comments>
        <comment id="1">
            <content>Have a great day!</content>
            <author id="3">Adam</author>
        </comment>
        <comment id="2">
            <content>How are you today?</content>
            <author id="4">Betty</author>
        </comment>
    </comments>
</post>

怎么样去分析呢?我们要遵循一下原则。


(1)通过创建一个名为XMLName、类型为xml.Name的字段,可以将XML元素的名字存储在这个字段里面。

(2)通过创建一个与XML元素属性同名的字段,并使用xml:",attr"作为该字段的结构标签,可以将元素的属性的值存储到这个字段里面。

(3)通过创建一个与XML元素相同的字段,并使用xml:",chardata"作为该字段的结构标签,可以将XML元素的字符数据存储到这个字段里面。

(4)通过定义一个任意名字字段,并使用XML:",innerxml"作为该字段的结构标签,可以将XML元素中的原始XML存储到这个字段里面。

(5)没有模式标签(如,attr、,chardata或者,innerxml)的结构字段将与同名的XML元素匹配。

(6)使用xml:"a>b>c"这样的结构标签可以在不指定树桩结构的情况下直接获取指定的XML元素,其中a和b为中间元素,而c则是想要获取的节点元素。


解析代码

package main

import (
    "encoding/xml"
    "fmt"
    "io/ioutil"
    "log"
    "os"
)

type Post struct {
    XMLName xml.Name `xml:"post"`
    Id string `xml:"id,attr"`
    Author Author `xml:"author"`
    Xml string `xml:",innerxml"`
    Comments []Comment `xml:"comments>comment"`
}

type Author struct {
    Id  string `xml:"id,attr"`
    Name string `xml:",chardata"`
}

type Comment struct {
    Id string `xml:"id,attr"`
    Content string `xml:"content"`
    Author Author `xml:"author"`
}

func main() {
    file, err := os.Open("src/text/xml/post.xml")
    if err != nil {
        log.Fatalf("Error opening XML file %v",err)
        return
    }
    defer file.Close()
    bytes, err := ioutil.ReadAll(file)
    if err != nil {
        log.Fatalf("Error reading XML file %v",err)
        return
    }
    var post Post
    xml.Unmarshal(bytes,&post)
    fmt.Println(post)
}

上面的这种方法可以很好的处理体积较小的XML文件,但是却无法高效地处理以流方式传输的XML文件以及体积较大的XML文件。为了解决这个问题,我们需要使用Decoder结构来替代Unmarshal函数,通过手动解码XML元素的方式来解封XML数据。

package main

import (
    "encoding/xml"
    "fmt"
    "io"
    "log"
    "os"
)

type Post struct {
    XMLName xml.Name `xml:"post"`
    Id string `xml:"id,attr"`
    Author Author `xml:"author"`
    Xml string `xml:",innerxml"`
    Comments []Comment `xml:"comments>comment"`
}

type Author struct {
    Id  string `xml:"id,attr"`
    Name string `xml:",chardata"`
}

type Comment struct {
    Id string `xml:"id,attr"`
    Content string `xml:"content"`
    Author Author `xml:"author"`
}

func main() {
    file, err := os.Open("src/text/xml/post.xml")
    if err != nil {
        log.Fatalf("Error opening XML file %v",err)
        return
    }
    defer file.Close()
    decoder := xml.NewDecoder(file)  //根据给定的XML数据生成相应的解码器
    for  {
        t, err := decoder.Token()    //每进行一次迭代,就从解码器获取一个token
        if err == io.EOF {
            break
        }
        if err != nil {
            log.Fatalf("Error decoding XML into tokens %v",err)
        }
        switch se := t.(type) {      //检查token的类型
        case xml.StartElement:
            if se.Name.Local == "comment" {
                var comment Comment
                decoder.DecodeElement(&comment,&se)   //将XML数据解析至结构
                fmt.Println(comment)
            }
        }
    }
}

二、创建XML

package main

import (
    "encoding/xml"
    "io/ioutil"
    "log"
)

type Post struct {
    XMLName xml.Name `xml:"post"`
    Id string `xml:"id,attr"`
    Content string `xml:"content"`
    Author Author `xml:"author"`
    Xml string `xml:",innerxml"`
    Comments []Comment `xml:"comments>comment"`
}

type Author struct {
    Id  string `xml:"id,attr"`
    Name string `xml:",chardata"`
}

type Comment struct {
    Id string `xml:"id,attr"`
    Content string `xml:"content"`
    Author Author `xml:"author"`
}

func main() {
    post := Post{
        Id:"1",
        Content:"Hello World!",
        Author:Author{
            Id:"2",
            Name:"Sau Sheong",
        },
        Comments: []Comment{{
            Id:"1",
            Content:"i love sz",
            Author:Author{
                Id:"3",
                Name:"zhu",
            },
        }},
    }
    output, err := xml.MarshalIndent(&post,"","\t")   //生成段落式的XML
    if err != nil {
        log.Fatalf("Error marshalling to XML %v",err)
        return
    }
    err = ioutil.WriteFile("post2.xml", []byte(xml.Header+string(output)), 0644)  //添加XML声明
    if err != nil {
        log.Fatalf("Error writing XML to file %v",err)
        return
    }
}

我们可以看一下生成的post2.xml文件中的xml数据

<?xml version="1.0" encoding="UTF-8"?>
<post id="1">
    <content>Hello World!</content>
    <author id="2">Sau Sheong</author>
    <comments>
        <comment id="1">
            <content>i love sz</content>
            <author id="3">zhu</author>
        </comment>
    </comments>
</post>

正如我们可以手动将XML解码到Go结构里面一样,我们同样也可以手动将Go结构编码到XML里面。

package main

import (
    "encoding/xml"
    "log"
    "os"
)

type Post struct {
    XMLName xml.Name `xml:"post"`
    Id string `xml:"id,attr"`
    Content string `xml:"content"`
    Author Author `xml:"author"`
    Xml string `xml:",innerxml"`
    Comments []Comment `xml:"comments>comment"`
}

type Author struct {
    Id  string `xml:"id,attr"`
    Name string `xml:",chardata"`
}

type Comment struct {
    Id string `xml:"id,attr"`
    Content string `xml:"content"`
    Author Author `xml:"author"`
}

func main() {
    post := Post{
        Id:"1",
        Content:"Hello World!",
        Author:Author{
            Id:"2",
            Name:"Sau Sheong",
        },
        Comments: []Comment{{
            Id:"1",
            Content:"i love sz",
            Author:Author{
                Id:"3",
                Name:"zhu",
            },
        }},
    }
    xmlFile, err := os.Create("post3.xml")
    if err != nil {
        log.Fatalf("Error creating XML File %v",err)
        return
    }
    encoder := xml.NewEncoder(xmlFile)
    encoder.Indent("","\t")
    err = encoder.Encode(&post)
    if err != nil {
        log.Fatalf("Error encoding XML to file %v",err)
        return
    }
}

1 个评论

https://www.onlinetool.io/xmltogo/

要回复文章请先登录注册