Атрибут отмены сопоставления XML по-разному в случае массивов в Golang

#xml #go #unmarshalling

#xml #Вперед #отмена сопоставления

Вопрос:

У меня есть веб-служба, в которой я ожидаю получить два разных запроса; вызывается один, Request содержащий только один Request , а другой вызывается, RequestBulk который содержит массив Request s. Оба сопоставлены со структурами Golang следующим образом:

 type RequestBulk struct {
    XMLName  xml.Name  `xml:"https://item.com RequestBulk"`
    Message  string    `xml:"Message"`
    Request  []Request `xml:"Request,omitempty"`
}

type Request struct {
    XMLName xml.Name `xml:"https://item.com Request"`
    Text    string   `xml:"text"`
}
  

Разархивирование следующих XML-файлов работает должным образом:

 <Request xmlns="https://item.com">
  <text>Some request text</text>
</Request>
  
 <RequestBulk xmlns="https://item.com">
  <Message>Some Text</Message>
  <Request xmlns="https://item.com">
    <text>Some request text</text>
  </Request>
  <Request xmlns="https://item.com">
    <text>Some other request text</text>
  </Request>
</RequestBulk>
  

Проблема

В RequestBulk , если я изменю

 Request []Request `xml:"Request,omitempty"`
  

Для

 RequestMessage []Request `xml:"RequestMessage,omitempty"`
  

и измените XML на:

 <RequestBulk xmlns="https://item.com">
  <Message>Some Text</Message>
  <RequestMessage xmlns="https://item.com">
    <text>Some request text</text>
  </RequestMessage>
  <RequestMessage xmlns="https://item.com">
    <text>Some other request text</text>
  </RequestMessage>
</RequestBulk>
  

Я получаю следующую ошибку:

ожидаемый тип элемента <Request>, но имеющий <RequestMessage>

Очевидно, из-за XMLName xml.Name `xml:"https://item.com Request"`

Вопрос

Как мне сохранить Request структуру без изменений и по-прежнему принимать сообщения типа RequestBulk с другим именем для структуры Request , а именно RequestMessage ?

Другими словами; Как мне использовать одну и ту же структуру с разными пространствами имен?


Запустите его на Go Playground.

Комментарии:

1. Ваш тип запроса включает в себя XMLName указание имени тега Request . Если это не то, что вы хотите, удалите его.

2. @Adrian Я знаю об этом, и я также упомянул об этом в сообщении. Вопрос начинается с прямо противоположного тому, что вы предложили. Пожалуйста, прочитайте вопрос еще раз!

3. Я сделал, но вы приняли ответ, который изменяет Request тип, добавляя к нему новый метод, поэтому сохранение Request неизменным, похоже, не является жестким требованием.

4. @Adrian да, он изменяет Request , но только в том случае, если имя является RequestMessage . Как упоминалось в начале моего вопроса, я хочу иметь возможность обрабатывать оба случая. Получение запросов с именем Request или RequestMessage . Знаете ли вы лучший способ сделать это?

5. Вы можете обработать оба случая любым способом. Вам не нужен XMLName для единственного Request варианта использования: play.golang.org/p/D1P1bVDADe7

Ответ №1:

Вы можете реализовать Unmarshaler интерфейс для перезаписи локального имени элемента перед передачей элемента в декодер для фактического отмены сопоставления.

 func (r *Request) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    if start.Name.Local == "RequestMessage" {
        start.Name.Local = "Request" // overwrite
    }
    type tmp Request // avoid infinite recursive calls to Request.UnmarshalXML
    return d.DecodeElement((*tmp)(r), amp;start) // unmarshal
}
  

https://play.golang.org/p/0a_gpgkywwf