006-golang中XML文件的处理

golang中XML文件的处理

一.概述

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

二.简单解析举例

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

1.直接访问

举个栗子

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

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

举个栗子

用栗子说话

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文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,711评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,932评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,770评论 0 330
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,799评论 1 271
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,697评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,069评论 1 276
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,535评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,200评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,353评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,290评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,331评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,020评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,610评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,694评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,927评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,330评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,904评论 2 341

推荐阅读更多精彩内容