解析xml中的重复字段

时间:2016-11-13 14:50:33

标签: xml go

我得到了一个xml响应,其中包含<Rights></Rights>块中的多个条目。它有几个<Name></Name><Access></Access>字段。

<?xml version="1.0" encoding="UTF-8"?>
<SessionInfo>
   <SID>000000000000</SID>
   <Challenge>1337</Challenge>
   <BlockTime>0</BlockTime>
   <Rights>
      <Name>Dial</Name>
      <Access>2</Access>
      <Name>App</Name>
      <Access>2</Access>
      <Name>HomeAuto</Name>
      <Access>2</Access>
      <Name>BoxAdmin</Name>
      <Access>2</Access>
      <Name>Phone</Name>
      <Access>2</Access>
      <Name>NAS</Name>
      <Access>2</Access>
   </Rights>
</SessionInfo>

我希望将其转换为权利结构。

type sessionInfo struct {
    XMLName    xml.Name `xml:"SessionInfo"`
    SID        string   `xml:"SID"`
    Challenge  string   `xml:"Challenge"`
    BlockTime  uint     `xml:"BlockTime"`
    Rights     []rights `xml:"Rights"`
}

type rights struct {
    Name   string `xml:"Name"`
    Access int    `xml:"Access"`
}

不幸的是,它只会将最后一个Element写入数组。是否有可能在Go中执行此操作而无需编写自己的解码器?

<SessionInfo>
    <SID>000000000000</SID>
    <Challenge>1337</Challenge>
    <BlockTime>0</BlockTime>
    <Rights>
        <Name>NAS</Name>
        <Access>2</Access>
    </Rights>
</SessionInfo>

您可以在此处测试:https://play.golang.org/p/29I2GPttOz

1 个答案:

答案 0 :(得分:3)

由于XML文档的布局,内置的编组规则无法将数据解码为您的给定数据类型。

以下是适用于您的文档的封送程序和解组程序实现:

package main

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

var data = []byte(`<?xml version="1.0" encoding="UTF-8"?>
    <SessionInfo>
       <SID>000000000000</SID>
       <Challenge>1337</Challenge>
       <BlockTime>0</BlockTime>
       <Rights>
          <Name>Dial</Name>
          <Access>2</Access>
          <Name>App</Name>
          <Access>2</Access>
          <Name>HomeAuto</Name>
          <Access>2</Access>
          <Name>BoxAdmin</Name>
          <Access>2</Access>
          <Name>Phone</Name>
          <Access>2</Access>
          <Name>NAS</Name>
          <Access>2</Access>
       </Rights>
    </SessionInfo>`)

type sessionInfo struct {
    XMLName   xml.Name `xml:"SessionInfo"`
    SID       string   `xml:"SID"`
    Challenge string   `xml:"Challenge"`
    BlockTime uint     `xml:"BlockTime"`
    Rights    *rights  `xml:"Rights"`
}

type rights struct {
    Rights []*right
}

type NameElement struct {
    XMLName xml.Name `xml:"Name"`
    Value   string   `xml:",chardata"`
}
type AccessElement struct {
    XMLName xml.Name `xml:"Access"`
    Value   string   `xml:",chardata"`
}

func (r *rights) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    for {
        var name NameElement
        var access AccessElement
        if err := d.Decode(&name); err != nil {
            if err == io.EOF {
                break
            }
            return err
        }
        if err := d.Decode(&access); err != nil {
            return err
        }
        value, err := strconv.Atoi(access.Value)
        if err != nil {
            return err
        }
        r.Rights = append(r.Rights, &right{
            Name:   name.Value,
            Access: value,
        })
    }
    return nil
}

func (r *rights) MarshalXML(e *xml.Encoder, start xml.StartElement) error {

    parentName := xml.Name{
        Local: "Rights",
    }

    parentStart := xml.StartElement{
        Name: parentName,
    }

    if err := e.EncodeToken(parentStart); err != nil {
        return err
    }

    for _, right := range r.Rights {
        name := NameElement{
            Value: right.Name,
        }
        value := AccessElement{
            Value: strconv.Itoa(right.Access),
        }
        if err := e.Encode(&name); err != nil {
            return err
        }
        if err := e.Encode(&value); err != nil {
            return err
        }
    }

    parentEnd := xml.EndElement{
        Name: parentName,
    }
    if err := e.EncodeToken(parentEnd); err != nil {
        return err
    }

    return nil
}

type right struct {
    Name   string
    Access int
}

func main() {
    var result sessionInfo
    if err := xml.Unmarshal(data, &result); err != nil {
        log.Fatalln(err)
    }

    if out, err := xml.MarshalIndent(result, "", "  "); err != nil {
        log.Fatalln(err)
    } else {
        fmt.Println(string(out))
    }
}

https://play.golang.org/p/MK0RCfJo0a