2016-11-13 2 views
0

Я получил ответ xml, который содержит несколько записей в блоке <Rights></Rights>. Он имеет несколько полей <Name></Name> и <Access></Access>.Повторяющиеся поля анализа в xml

<?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"` 
} 

К сожалению, он записывает только последний элемент в массив. Как-то можно сделать это в 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

ответ

3

Благодаря компоновке документа XML, встроенный в сортировочной правила не могут декодировать данные в ваших данных типов данных.

Ниже упаковщик и unmarshaler реализация, которая должна работать для вашего документа:

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

Смежные вопросы