• Golang的XML处理


    前言
    前往https://studygolang.com/pkgdoc,了解golang语言中xml包的内容。文中的内容主要来自于该网站。

    XML生成
    理论
    func Marshal(v interface{}) ([]byte, error)
    func MarshalIndent(v interface{}, prefix, indent string) ([]byte, error)
    可以使用Marshal函数和MarshalIndent函数返回XML编码。MarshalIndent函数功能类似于Marshal函数。区别在于有无缩进。

    Marshal处理数组或者切片时会序列化每一个元素。Marshal处理指针时,会序列化其指向的值;如果指针为nil,则啥也不输出。Marshal处理接口时,会序列化其内包含的具体类型值,如果接口值为nil,也是不输出。Marshal处理其余类型数据时,会输出一或多个包含数据的XML元素。

    将结构体转换为XML输出时,需要注意以下规则:

    • XMLName字段,如上所述,会省略
    • 具有标签"-"的字段会省略
    • 具有标签"name,attr"的字段会成为该XML元素的名为name的属性
    • 具有标签",attr"的字段会成为该XML元素的名为字段名的属性
    • 具有标签",chardata"的字段会作为字符数据写入,而非XML元素
    • 具有标签",innerxml"的字段会原样写入,而不会经过正常的序列化过程
    • 具有标签",comment"的字段作为XML注释写入,而不经过正常的序列化过程,该字段内不能有"--"字符串
    • 标签中包含"omitempty"选项的字段如果为空值会省略
      空值为false、0、nil指针、nil接口、长度为0的数组、切片、映射
    • 匿名字段(其标签无效)会被处理为其字段是外层结构体的字段
    • 如果一个字段的标签为"a>b>c",则元素c将会嵌套进其上层元素a和b中。如果该字段相邻的字段标签指定了同样的上层元素,则会放在同一个XML元素里。
      实践
    /*
    `xml:"id,attr"`:Id字段会成为该XML元素的名为id的属性
    `xml:"name>first"`与`xml:"name>last"`:元素first与last会嵌套进上层元素name中
    `xml:"height,omitempty"`:含"omitempty"选项的字段如果为空值会省略
    `xml:"-"`:含"-"的字段会省略
    Age:该字段没有设置标签,可注意观察输出Age标签名为该字段名
    `xml:",comment"`:",comment"的字段作为XML注释写入
     */
    func Test_XMLMarshal(t *testing.T){
    	type Address struct {
    		City, State string
    	}
    	type Person struct {
    		XMLName   xml.Name `xml:"person"`
    		Id        int      `xml:"id,attr"`
    		FirstName string   `xml:"name>first"`
    		LastName  string   `xml:"name>last"`
    		Age       int
    		Height    float32  `xml:"height,omitempty"`
    		Married   bool `xml:"-"`
    		Address
    		Comment string `xml:",comment"`
    		Description string `xml:",innerxml"`
    	}
    	v := &Person{Id: 13, FirstName: "John", LastName: "Doe", Age: 42, Married:true}
    	v.Comment = " Need more details. "
    	v.Address = Address{"Hanga Roa", "Easter Island"}
    	//使用MarshalIndent函数,生成的XML格式有缩进
    	//output, err := xml.MarshalIndent(v, "  ", "    ")
    	//使用Marshal函数,生成的XML格式无缩进
    	output,err:=xml.Marshal(v)
    	if err != nil {
    		fmt.Printf("error: %v
    ", err)
    	}
    	os.Stdout.Write(output)
    }
    

    输出效果:

    使用Marshal函数(无缩进):

    <person id="13"><name><first>John</first><last>Doe</last></name><Age>42</Age><City>Hanga Roa</City><State>Easter Island</State><!-- Need more details. --></person>
    使用MarshalIndent函数(有缩进):
    
      <person id="13">
          <name>
              <first>John</first>
              <last>Doe</last>
          </name>
          <Age>42</Age>
          <City>Hanga Roa</City>
          <State>Easter Island</State>
          <!-- Need more details. -->
      </person>
    

    XML解析
    理论
    func Unmarshal(data []byte, v interface{}) error
    Unmarshal解析XML编码的数据并将结果存入v指向的值。v只能指向结构体、切片或者和字符串。

    解析XML编码时,需要遵守以下规则:

    • 如果结构体字段的类型为字符串或者[]byte,且标签为",innerxml",
      Unmarshal函数直接将对应原始XML文本写入该字段,其余规则仍适用。
    • 如果结构体字段类型为xml.Name且名为XMLName,Unmarshal会将元素名写入该字段
    • 如果字段XMLName的标签的格式为"name"或"namespace-URL name",
      XML元素必须有给定的名字(以及可选的名字空间),否则Unmarshal会返回错误。
    • 如果XML元素的属性的名字匹配某个标签",attr"为字段的字段名,或者匹配某个标签为"name,attr"的字段的标签名,Unmarshal会将该属性的值写入该字段。
    • 如果XML元素包含字符数据,该数据会存入结构体中第一个具有标签",chardata"的字段中,
      该字段可以是字符串类型或者[]byte类型。如果没有这样的字段,字符数据会丢弃。
    • 如果XML元素包含注释,该数据会存入结构体中第一个具有标签",comment"的字段中,
      该字段可以是字符串类型或者[]byte类型。如果没有这样的字段,字符数据会丢弃。
    • 如果XML元素包含一个子元素,其名称匹配格式为"a"或"a>b>c"的标签的前缀,反序列化会深入XML结构中寻找具有指定名称的元素,并将最后端的元素映射到该标签所在的结构体字段。
      以">"开始的标签等价于以字段名开始并紧跟着">" 的标签。
    • 如果XML元素包含一个子元素,其名称匹配某个结构体类型字段的XMLName字段的标签名,
      且该结构体字段本身没有显式指定标签名,Unmarshal会将该元素映射到该字段。
    • 如果XML元素的包含一个子元素,其名称匹配够格结构体字段的字段名,且该字段没有任何模式选项(",attr"、",chardata"等),Unmarshal会将该元素映射到该字段。
    • 如果XML元素包含的某个子元素不匹配以上任一条,而存在某个字段其标签为",any",
      Unmarshal会将该元素映射到该字段。
    • 匿名字段被处理为其字段好像位于外层结构体中一样。
    • 标签为"-"的结构体字段永不会被反序列化填写。
      实践
    /*
    XMLName的标签为`xml:"Person"`,则给的XML编码中XML元素必须有给定的名Person,否则会报错error: expected element type <person> but have <Person>
    Name的标签为`xml:"FullName"`,则给的XML编码中解析XML元素为FullName的值为字段Name对应的值
    Age的标签为`xml:"-"`,则不会被反序列填写,可以观察出Age的值为0
    Phone无标签,则解析时将XML元素为Phone的值为该字段对应的值
    Groups的标签为`xml:"Group>Value"`,则解析时将XML元素为Group的子元素Value的值为该字段对应的值
    Email结构的Where字段的标签为`xml:"where,attr"`,则解析时将XML元素为Email的属性Where的值赋给该字段
    Description标签为",innerxml",通过打印Description的值,可以看出直接将对应原始XML文本写入该字段
    补充说明:
    %#v-值的Go语法表示
    %v-值的默认格式表示。当输出结构体时,扩展标志(%+v)会添加字段名
    %q-该值对应的单引号括起来的go语法字符字面值,必要时会采用安全的转义表示
     */
    func Test_XMLUnMarshal(t *testing.T){
    	type Email struct {
    		Where string `xml:"where,attr"`
    		Addr  string
    	}
    	type Address struct {
    		City, State string
    	}
    	type Result struct {
    		XMLName xml.Name `xml:"Person"`
    		Name    string   `xml:"FullName"`
    		Age     int       `xml:"-"`
    		Phone   string
    		Email   []Email
    		Groups  []string `xml:"Group>Value"`
    		Address
    		Description string `xml:",innerxml"`
    	}
    	v := Result{Name: "none", Phone: "none"}
    	data := `
    		<Person>
    			<FullName>Grace R. Emlin</FullName>
    			<Company>Example Inc.</Company>
               <Age>20</Age>
    			<Email where="home">
    				<Addr>gre@example.com</Addr>
    			</Email>
    			<Email where='work'>
    				<Addr>gre@work.com</Addr>
    			</Email>
    			<Group>
    				<Value>Friends</Value>
    				<Value>Squash</Value>
    			</Group>
    			<City>Hanga Roa</City>
    			<State>Easter Island</State>
    		</Person>
    	`
    	err := xml.Unmarshal([]byte(data), &v)
    	if err != nil {
    		fmt.Printf("error: %v", err)
    		return
    	}
    	fmt.Printf("XMLName: %#v
    ", v.XMLName)
    	fmt.Printf("Name: %q
    ", v.Name)
    	fmt.Printf("Age: %v
    ", v.Age)
    	fmt.Printf("Phone: %q
    ", v.Phone)
    	fmt.Printf("Email: %v
    ", v.Email)
    	fmt.Printf("Email[0].Where: %v
    ", v.Email[0].Where)
    	fmt.Printf("Groups: %v
    ", v.Groups)
    	fmt.Printf("Address: %v
    ", v.Address)
    	fmt.Printf("Description: %v
    ", v.Description)
    }
    

    输出结果:

    XMLName: xml.Name{Space:"", Local:"Person"}
    Name: "Grace R. Emlin"
    Age: 0
    Phone: "none"
    Email: [{home gre@example.com} {work gre@work.com}]
    Email[0].Where: home
    Groups: [Friends Squash]
    Address: {Hanga Roa Easter Island}
    Description: 
    			<FullName>Grace R. Emlin</FullName>
    			<Company>Example Inc.</Company>
                <Age>20</Age>
    			<Email where="home">
    				<Addr>gre@example.com</Addr>
    			</Email>
    			<Email where='work'>
    				<Addr>gre@work.com</Addr>
    			</Email>
    			<Group>
    				<Value>Friends</Value>
    				<Value>Squash</Value>
    			</Group>
    			<City>Hanga Roa</City>
    			<State>Easter Island</State>
     
    
  • 相关阅读:
    Java_static
    Java_字符串操作
    Java_==
    Java_字符串
    Java_Random
    Java_Scanner
    杨辉三角
    颜色分类
    字符串倒序
    jQuery的基本事件
  • 原文地址:https://www.cnblogs.com/enumx/p/12328265.html
Copyright © 2020-2023  润新知