Как разобрать динамический XML в GO - PullRequest
0 голосов
/ 03 июля 2019

Я пытаюсь проанализировать XML с помощью Go, который используется для обмена данными с другой системой. Я знаю, как в принципе работает синтаксический анализ с функцией xml.Unmarshal. Однако в протоколе дочерний элемент корневого элемента <PROTO> варьируется (см. Примеры ниже). Для дочерних элементов (REQUEST.DATA, REQUEST.ACL, REQUEST.NAC, ... - гораздо больше, чем двадцать различных) я уже определил структуры с синтаксисом xml:... - синтаксический анализ этих дочерних элементов работает.

Но есть ли хороший способ проанализировать все сообщение как структуру, где один переменный тип зависит от дочернего элемента? Например с использованием интерфейса?

Пример возможных сообщений XML:

<PROTO
   version="1.00">
  <REQUEST.DATA>
    <DATA-L>Some information</DATA-L>
  </REQUEST.DATA>
</PROTO>
<PROTO
   version="1.00">
  <REQUEST.ACK>
    <ACK-ID>1</ACK-ID>
  <REQUEST.ACK>
</PROTO>

Фрагменты из моего приложения Go:

// XML: REQUEST.DATA
type DataRequest struct {
    LData string `xml:"DATA-L"`
}

// XML: REQUEST.ACK
type AckRequest struct {
    AckId int `xml:"ACK-ID"`
}

// XML: PROTO  <============= ??
type Request struct {
    Version float32  `xml:"version,attr"`
    RemoteRequest {AckRequest, DataRequest, ...} ????
}

func main() {
    message := `<PROTO version="1.00"><REQUEST.ACK><ACK-ID>1</ACK-ID><REQUEST.ACK></PROTO>`
    data := `<REQUEST.ACK><ACK-ID>1</ACK-ID><REQUEST.ACK>`
    doc := &AckRequest{}
    err := xml.Unmarshal([]byte(data), &doc)
    if err != nil {
        fmt.Printf("error: %v", err)
        return
    }
    fmt.Printf("data %+v", doc)
}

Вместо простого анализа дочернего элемента data Я хочу проанализировать весь документ message (<PROTO> задействован). И хочу иметь структуру, которая содержит информацию о соответствующем дочернем элементе.

1 Ответ

0 голосов
/ 03 июля 2019

Вы можете встроить DataRequest и AckRequest как указатели в структуру Request. Таким образом, вы можете проверить позже, если они nil или нет.

// XML: REQUEST.DATA
type DataRequest struct {
    LData string `xml:"DATA-L"`
}

// XML: REQUEST.ACK
type AckRequest struct {
    AckId int `xml:"ACK-ID"`
}

type Request struct {
    Version float32      `xml:"version,attr"`
    Ack     *AckRequest  `xml:"REQUEST.ACK"`
    Data    *DataRequest `xml:"REQUEST.DATA"`
}

func main() {
    message := `<PROTO version="1.00"><REQUEST.ACK><ACK-ID>1</ACK-ID></REQUEST.ACK></PROTO>`
    proto := &Request{}
    err := xml.Unmarshal([]byte(message), &proto)
    if err != nil {
        fmt.Printf("error: %v", err)
        return
    }
    // if proto.Ack == nil {
    //   fmt.Println("Ack is nil")
    // }
    fmt.Printf("data %+v\n", proto)
    fmt.Printf("data %+v\n", proto.Ack)
}

данные & {Версия: 1 Ack: 0xc0000b6050 Данные:}

data & {AckId: 1}

Вы также можете реализовать свой собственный декодер и выполнять динамическое переключение типов https://stackoverflow.com/a/33517875/1199408.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...