前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >006-golang中XML文件的处理

006-golang中XML文件的处理

作者头像
上善若水.夏
发布2018-09-28 11:26:12
2.3K0
发布2018-09-28 11:26:12
举报
文章被收录于专栏:上善若水

golang中XML文件的处理

一.概述

在golang中 包"encoding/xml" 提供了对xml文件的解析。

二.简单解析举例

有两种常见方式对其解析,

1.直接访问

举个栗子

代码语言:javascript
复制
package main

import (
    "fmt"
    "io/ioutil"
    "errors"
    "os"
    "log"
    "flag"
    "os/exec"
    "regexp"
    "strings"
    "encoding/xml"
    "bytes"
)


    manifest := projectDir + "/AndroidManifest.xml"

    content, err := ioutil.ReadFile(manifest)
    if err != nil {
        log.Fatal(err)
    }

    //inputReader := strings.NewReader(content)
    //decoder := xml.NewDecoder(inputReader)
    decoder := xml.NewDecoder(bytes.NewBuffer(content))
    for t, err := decoder.Token(); err == nil; t, err = decoder.Token() {
        switch token := t.(type) {
            // 处理元素开始(标签)
            case xml.StartElement:
                name := token.Name.Local
    
                fmt.Printf("Token name: %s\n", name)
                for _, attr := range token.Attr {
                    attrName := attr.Name.Local
                    attrValue := attr.Value
                    fmt.Printf("An attribute is: %s %s\n", attrName, attrValue)
                }
        
                // 处理元素结束(标签)
                case xml.EndElement:    
                    fmt.Printf("Token of '%s' end\n", token.Name.Local) 
                // 处理字符数据(这里就是元素的文本)    
                case xml.CharData:  
                    content := string([]byte(token))    
                    fmt.Printf("This is the content: %v\n", content)    
                default:    
                    // ...
        }
        
    }
        
    fmt.Printf("xml  success!\n")

2.xml和Go中的struct相互转换

缺点: 兼容性不好,而且要定义很多struct

有点,转化后的数据,看起来清晰

举个栗子

用栗子说话

代码语言:javascript
复制
package main

//import "github.com/gin-gonic/gin"
import (
    //"encoding/json"
    "fmt"
    "io/ioutil"
    //"net/http"
    "log"
    "encoding/xml"
    "os"
)


const Header string = `<?xml version="1.0" encoding="utf-8" standalone="no"?>` + "\n"

type manifest struct {
    Xmlns xml.Attr `xml:"android,attr"`
    InstallLocation xml.Attr `xml:"installLocation,attr"`
    Package xml.Attr `xml:"package,attr"`
    PlatformBuildVersionCode xml.Attr  `xml:"platformBuildVersionCode,attr"`
    PlatformBuildVersionName xml.Attr  `xml:"platformBuildVersionName,attr"`
    SupportsScreens SupportsScreens `xml:"supports-screens"`
}


type SupportsScreens  struct {
    AnyDensity xml.Attr `xml:"anyDensity,attr"`
    LargeScreens xml.Attr  `xml:"largeScreens,attr"`
    NormalScreens xml.Attr  `xml:"normalScreens,attr"`
    SmallScreens xml.Attr `xml:"smallScreens,attr"`
    XlargeScreens xml.Attr `xml:"xlargeScreens,attr"`
}

func NewManifest(filename string)(manifest) {

    content, err := ioutil.ReadFile(filename)
    if err != nil {
        log.Fatal(err)
    }
    var result manifest
    err = xml.Unmarshal(content, &result)
    if err != nil {
        log.Fatal(err)
    }
    //log.Println(result)
    
    //log.Println(result.Persons[0].Name)
    
    return  result
}


func main() {
    //xml.Attr
    
    result := NewManifest("project/name/AndroidManifest.xml")

    fmt.Printf("-->%+v\n",result)


    xmlOutPut, outPutErr := xml.MarshalIndent(result, "", "")
    if outPutErr == nil {
        //加入XML头
        headerBytes := []byte(xml.Header)
        //拼接XML头和实际XML内容
        xmlOutPutData := append(headerBytes, xmlOutPut...)
        //写入文件
        ioutil.WriteFile("test.xml", xmlOutPutData, os.ModeAppend)

        fmt.Println("OK~")
    } else {
        fmt.Println(outPutErr)
    }
}

3.XML到Go中struct的转换规则说明。

(标准库encoding/xml文档有详细的说明)

  1. 如果struct的一个字段是string或者[]byte类型且它的tag含有”,innerxml”,Unmarshal会将此字段所对应的元素内所有内嵌的原始xml累加到此字段上。
  2. 如果struct中有一个叫做XMLName且类型为xml.Name的字段,Unmarshal会保存对应的元素的名字到该字段。比如,上面的例子,在Person结构中加上该字段XMLName xml.Name,则结果会是:{[{{ person} polaris 28 无业游民 {[编程 下棋]}} {{ person} studygolang 27 码农 {[编程 下棋]}}]}。可见,该字段是用来映射XML元素的,在生成XML时比较有用。注意,XMLName和类型xml.Name必须是这样,不能改为XmlName。
  3. 如果XMLName字段有tag,且tag的形式是:”name”或”namespace-URL name”,则相应的XML元素必须是这个名字(命名空间可选),否则Unmarshal会返回错误。可以通过在上面的例子中,修改Person的XMLName xml.Name xml:”myperson”试试,会报错:expected element typebut have
  4. 如果某个XML元素有一个属性,它的名字和struct中某个字段匹配(大小写都得匹配),并且该字段的tag包含”,attr”,或者元素的名字显示的被写在了tag中(”name,attr”),这时,Unmarshal会将该属性赋值给该字段。如上面的Name和Age
  5. 如果XML元素包含字符数据(character

data),那么,字符数据会被累加到struct中第一个有tag为”,chardata”的字段。struct字段的类型可以是string或[]byte。如果没有这样的字段,字符数据会被丢弃。如上面的Interests可以再定义一个类型Interest: type Interest struct { Inter string xml:”,chardata” } Interests 中相应的改为:Interest []Interest 当然这个例子中这种方式有些啰嗦。

  1. 如果某个XML元素包含一条或者多条注释,那么这些注释将被累加到第一个含有”,comments” tag的字段上,这个字段的类型可以是[]byte或string,如果没有这样的字段存在,那么注释将会被丢弃。
  2. 如果某个XML元素的子元素的名字和 “a”或 “a>b>c”这种格式的tag的前缀匹配,Unmarshal会沿着XML结构向下寻找这样名字的元素,然后将最里面的元素映射到struct的字段上。以”>”开始的tag和字段后面跟上”>”是等价的。从这知道,上面例子中关于Interests的解析可以更简单,即不需要Interest结构类型
  3. 如果某XML元素的子元素的名字和某个struct的XMLName字段的tag匹配,且该struct的字段没有定义以上规则的tag,Unmarshal会映射该子元素到该struct的字段上。
  4. 如果某个XML元素的子元素的名字和一个没有任何tag的字段匹配,则Unmarshal会映射这个子元素到那个字段上。比如最开始没有使用tag的例子,使用的就是这条规则。
  5. 如果某个XML元素的子元素根据上面的规则都没有匹配到任何字段,然而,该struct有字段带有”,any”的tag,则Unmarshal会映射该子元素到该字段上。
  6. 一个非指针的匿名struct字段会被这样处理:该字段的值是外部struct的一部分

12 . 如果一个struct字段的tag定义为”-“,则Unmarshal不会给它赋值

三.参考链接

  1. Go语言关于XML的读取与生成
  2. 标准库—XML处理(一)
  3. go语言解析带命名空间的xml
  4. http://www.jianshu.com/p/7ac5db1d6b70
  5. golang标准库encodeing/xml文档
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2017.12.12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一.概述
  • 二.简单解析举例
    • 1.直接访问
      • 2.xml和Go中的struct相互转换
        • 3.XML到Go中struct的转换规则说明。
        • 三.参考链接
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档