go 操作xml 和 json

go 操作xml 和 json 分别使用 encoding/xml 和 encoding/json 来实现 下面我们通过代码来讲解一下go 操作xml 文件 和 json 格式数据

读取xml

假设我有一个xml 文件如下
C:\\Users\\admin\\go\\src\\html\\mgr.xml

<?xml version="1.0" encoding="utf-8"?>
<servers version="1">
    <server>
        <serverName>Shanghai_VPN</serverName>
        <serverIP>127.0.0.1</serverIP>
    </server>
    <server>
        <serverName>Beijing_VPN</serverName>
        <serverIP>127.0.0.2</serverIP>
    </server>
    <database>
        <databaseName>Oracle</databaseName>
        <databasePort>1521</databasePort>
    </database>
    <database>
        <databaseName>MySQL</databaseName>
        <databasePort>3306</databasePort>
    </database>
</servers>

现在我们需要取出其中的数据 我们需要定义结构体 定义我们需要拿到xml的哪些标签,例如我现在想拿到server 标签和 database 标签里面的数据那我就需要为这两个标签分别定义两个结构体

为元素定义结构体

// server 标签
type servers struct {
        XMLName xml.Name `xml:"server"`
        ServerName string `xml:"serverName"`
        ServerIP string `xml:"serverIP"`
    }
// database 标签
type database struct {
    XMLName xml.Name `xml:"database"`
    DatabaseName string `xml:"databaseName"`
    DatabasePort int `xml:"databasePort"`
}
// 整个xml 文件 里面包含了 server 和 database 标签
type XmlData struct {
        XmlName xml.Name `xml:"servers"`
        Version string  `xml:"version,attr"`
        Servers []servers `xml:"server"`
        Database []database `xml:"database"`
        Desc string `xml:",innerxml"`
    }

这里需要注意几点1. 结构体的字段必须是可导出的 2.tag 必须和xml 里面的元素名称一样,也就是 xml:"xx" 这个地方 定义的tag 和 xml 元素名称不一样或者说大小写不一样都会导致xml 元素解析不出来,例如我的xml:"databasePort" 这个databasePort 必须和 xml 里面的标签一样的名称

完整代码demo

package growth

// 学习go 第十四天 学习使用go io操作

import (
    "fmt"
    "os"
    "io/ioutil"
    "path/filepath"
    "encoding/xml"

)

func Day14IO()  {

    currentPath, _ := filepath.Abs(os.Args[0])
    fmt.Println(currentPath)
    // 打开并读取文件
    data, err:= ioutil.ReadFile("C:\\Users\\admin\\go\\情绪.jpg")
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println(string(data))
}

func Day14Xml()  {
    // 学习使用go 处理xml, go 使用xml.Unmarshal(data []byte, v interface{}) error 来处理xml文件
    /*
    我们需要定义结构体来获取我们需要解析的xml标签
    Unmarshal解析的时候XML元素和struct字段怎么对应起来的呢?
    这是有一个优先级读取流程的,首先会读取struct tag,也就是 `xml:"xx"` 这个地方
    如果没有,那么就会对应字段名。必须注意一点的是解析的时候tag、
    字段名、XML元素都是大小写敏感的,所以必须一一对应字段

    解析XML到struct的时候遵循如下的规则:

    1. 如果struct的一个字段是string或者[]byte类型且它的tag
    含有",innerxml",Unmarshal将会将此字段所对应的元素内所有内嵌的原始xml
    累加到此字段上,如上面例子Description定义。最后的输出是
    2. 如果struct中有一个叫做XMLName,且类型为xml.Name字段,
    那么在解析的时候就会保存这个element的名字到该字段,如上面例子中的servers。
    3. 如果某个struct字段的tag定义中含有XML结构中element的名称,
    那么解析的时候就会把相应的element值赋值给该字段,
    如上servername和serverip定义
    4. 如果某个struct字段的tag定义了中含有",attr",
    那么解析的时候就会将该结构所对应的element的与字段同名的
    属性的值赋值给该字段,如上version定义
    5. 如果某个struct字段的tag定义了"-",那么不会为该字段解析匹配任何xml数据
    6. 如果struct字段后面的tag定义了",any",如果他的子元素在不满足其他的规则的时候就会匹配到这个字段
     */

    type servers struct {
        XMLName xml.Name `xml:"server"`
        ServerName string `xml:"serverName"`
        ServerIP string `xml:"serverIP"`
    }

    type database struct {
        XMLName xml.Name `xml:"database"`
        DatabaseName string `xml:"databaseName"`
        DatabasePort int `xml:"databasePort"`
    }

    type XmlData struct {
        XmlName xml.Name `xml:"servers"`
        Version string  `xml:"version,attr"`
        Servers []servers `xml:"server"`
        Database []database `xml:"database"`
        Desc string `xml:",innerxml"`
    }
    filename := "C:\\Users\\admin\\go\\src\\html\\mgr.xml"
    file , err := os.Open(filename)

    if err != nil {
        fmt.Println("Open File err", err)
        return
    }

    defer file.Close()
    // 读取xml 文件
    data, e1 := ioutil.ReadAll(file)
    if e1 != nil {
        fmt.Println("Read File Err", err)
        return
    }
    properties := &XmlData{}
    // 通过xml.Umarshal 解析xml
    e2 := xml.Unmarshal(data, properties)

    if e2 != nil {
        fmt.Println(e2)
        return
    }
    fmt.Println(properties.Servers[0].ServerIP)
    fmt.Println(properties.Servers[0].ServerName)
    fmt.Println(properties.Database[0].DatabaseName)
    fmt.Println(properties.Database[0].DatabasePort)
    fmt.Println(properties.Database[1].DatabaseName)
    fmt.Println(properties.Database[1].DatabasePort)

}

读取json

现在假如我们有这样一个json 数据

{"ip": "192.168.1.100", "port": 1521, "nums": [1, 2, 3], "relation": {"mykey": "myval"}}

我们想拿到里面全部的key-value

go 解析json 同样需要定义结构体

为这个json 定义结构体

type data struct {
    // 结构体里面的字段必须是可导出的(大写字母开头)
    // 且字段名要和json 里面key的名称一样
    Ip string
    Port int
    Nums []int
    Relation map[string]string

}

然后使用 json.Unmarshal来解析

完整的代码demo


package growth

// 学习go 第十六天 学习使用go 操作json

import (
    "fmt"
    "encoding/json"
)

type data struct {
    // 结构体里面的字段必须是可导出的(大写字母开头)
    // 且字段名要和json 里面key的名称一样
    Ip string
    Port int
    Nums []int
    Relation map[string]string

}



func Day16Json() {

    /*
    在解析的时候,如何将json数据与struct字段相匹配呢?
    例如JSON的key是Foo,那么怎么找对应的字段呢?
    首先查找tag含有Foo的可导出的struct字段(首字母大写)
    其次查找字段名是Foo的导出字段
    最后查找类似FOO或者FoO这样的除了首字母之外其他大小写不敏感的
    导出字段

     */
    var loads data
    js := []byte(`{"ip": "192.168.1.100", "port": 1521, "nums": [1, 2, 3], "relation": {"mykey": "myval"}}`)
    // 解析json
    err := json.Unmarshal(js, &loads)

    if err != nil {
        fmt.Println("Unmarshal Err", err)
        return
    }

    fmt.Println(loads)

    // 生成json, 假如我们需要生成像上面一样的json 需要通过json.Marshal 方法, 我们需要Marshal的对象还是结构体

    var dumps data
    dumps.Ip = "127.0.0.1"
    dumps.Port = 3306
    dumps.Nums = []int {1, 2, 3}
    dumps.Relation = map[string]string{"key": "value"}
    // Marshal 之后返回的是byte 类型的数组[]byte
    dump, e2 := json.Marshal(dumps)

    if e2 != nil {
        fmt.Println("Marshal Err", e2)
        return
    }
    // dump 是 byte 类型的数组
    fmt.Println(dump)
    // 转换为string就可以看到json
    fmt.Println(string(dump))

}

猜你喜欢

转载自blog.csdn.net/lucky404/article/details/81023365