Как выполнить маршал и демаршал XML с нерегулярными атрибутами - PullRequest
0 голосов
/ 13 января 2020

У меня есть XML, где разные объекты представлены одним и тем же тегом, но с разными атрибутами. Примерно так:

<xml>
    <body>
        <Packet type="clients">
            <Row id="123" name="bill"/>
            <Row id="456" name="sasha"/>
        </Packet>
        <Packet type="orders">
            <Row sum="90" status="DONE" />
            <Row sum="190" status="DONE" />
       </Packet>
   </body>
</xml>

Гарантируется, что будет только один пакет с каждым типом.

К сожалению, я не могу изменить структуру XML, и я должен работать с ней как есть. Как лучше всего справиться с такой структурой в Go? Должен ли я иметь одну структуру со всеми возможными атрибутами и просто заполнять нужные для каждого «пакета»?

type XML struct {
    XMLName xml.Name `xml:"xml"`
    Body    struct {
        Packet []struct {
            Type string `xml:"type,attr"`
            Row  []struct {
                ID     string `xml:"id,attr"`
                Name   string `xml:"name,attr"`
                Sum    string `xml:"sum,attr"`
                Status string `xml:"status,attr"`
            } `xml:"Row"`
        } `xml:"Packet"`
    } `xml:"body"`
} 

Это кажется выполнимым, но довольно неудобным, потому что на самом деле у меня есть много разных типов пакетов с множество разных атрибутов.

Или, может быть, есть способ сопоставить пакеты с различными Go структурами? Примерно так:

type XML struct {
    XMLName xml.Name `xml:"xml"`
    Body    struct {
        ClientPacket struct {
            Type string `xml:"type,attr"`
            Row  []struct {
                ID   string `xml:"id,attr"`
                Name string `xml:"name,attr"`
            } `xml:"Row"` 
        } `xml:"Packet"` // ???
        OrderPacket struct {
            Type string `xml:"type,attr"`
            Row  []struct {
                Sum   string `xml:"sum,attr"`
                Status string `xml:"status,attr"`
            } `xml:"Row"` 
        } `xml:"Packet"` // ???
    } `xml:"body"`
} 

Более поздний кажется более умным и гораздо более читабельным примером, но я не понимаю, как его маршалировать и демаршировать xml.

Ответы [ 2 ]

0 голосов
/ 13 января 2020

Сначала преобразуйте файл (например, используя XSLT) перед маршалингом.

0 голосов
/ 13 января 2020

Я могу подумать о нескольких способах достижения этой цели: вы можете попробовать подход, который вы уже описали, со структурой, содержащей все возможные атрибуты. Это было бы утомительно, но легко. Вы также можете попробовать написать собственный демаршалер для Packet:

type PacketXML struct {
   A *PacketTypeA
   B *PacketTypeB
   ...
}

func (x *PacketXML)  UnmarshalXML(d *Decoder, start StartElement) error {
    // Look at start attributes, find out what type of packet it has
    packetType:=findAttr(start,"type")
    switch packetType {
      case "typeA":
         x.A=&PacketTypeA{}
         return d.Decode(x.A)
      case "typeB":
         x.B=&PacketTypeB{}
         return d.Decode(x.B)
      ...
    }
  return nil
}

Когда все будет сделано, вы можете проверить, какой элемент из PacketXML экземпляров не ноль, и использовать его.

...