XML немаршальный динамический ответ с индексами в именах полей - PullRequest
1 голос
/ 01 октября 2019

Я пытаюсь разобрать «динамический» XML-ответ, но я не уверен, как к нему подойти. Сервер отвечает довольно большим ответом, поэтому я бы предпочел не анализировать ответ дважды. XML выглядит следующим образом:

...
<nic_cnt>2</nic_cnt>
<ifindex1>eno1</ifindex1>
<ifindex2>eno2</ifindex2>
...

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

1 Ответ

1 голос
/ 01 октября 2019

Вы можете использовать слайс с опцией XML-тега ,any, чтобы указать пакету encoding/xml на добавление в него любого тега XML. Это задокументировано в xml.Unmarshal():

If the XML element contains a sub-element that hasn't matched any
   of the above rules and the struct has a field with tag ",any",
   unmarshal maps the sub-element to that struct field.

Для тегов <ifindexXX> используйте другую структуру, которая содержит поле XMLName типа xml.Name поэтому фактическое имя поля будет доступно, если вам нужно отфильтровать только поля, начинающиеся с ifindex.

Давайте разберем следующий XML:

<root>
    <nic_cnt>2</nic_cnt>
    <ifindex1>eno1</ifindex1>
    <ifindex2>eno2</ifindex2>
</root>

Мыможно смоделировать его с помощью:

type Root struct {
    NicCnt  int     `xml:"nic_cnt"`
    Entries []Entry `xml:",any"`
}

type Entry struct {
    XMLName xml.Name
    Value   string `xml:",innerxml"`
}

Пример кода для его анализа:

var root Root
if err := xml.Unmarshal([]byte(src), &root); err != nil {
    panic(err)
}
fmt.Printf("%+v", root)

Вывод (попробуйте на Go Playground ):

{NicCnt:2 Entries:[
    {XMLName:{Space: Local:ifindex1} Value:eno1}
    {XMLName:{Space: Local:ifindex2} Value:eno2}]}

Обратите внимание, что Root.Entries также будет содержать другие несопоставленные теги XML. Если вам нужны только теги, начинающиеся с ifindex, вот как вы можете их «отфильтровать»:

for _, e := range root.Entries {
    if strings.HasPrefix(e.XMLName.Local, "ifindex") {
        fmt.Println(e.XMLName.Local, ":", e.Value)
    }
}

Если XML также содержит дополнительный тег:

<other>something else</other>

Вывод будет (попробуйте это на Go Playground ):

{NicCnt:2 Entries:[
    {XMLName:{Space: Local:ifindex1} Value:eno1}
    {XMLName:{Space: Local:ifindex2} Value:eno2}
    {XMLName:{Space: Local:other} Value:something else}]}
ifindex1 : eno1
ifindex2 : eno2
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...