Как правильно разобрать xml

Я хочу создать struct = каждый тип команды.

Команды имеют общую часть xml - CommandResult. Я создал интерфейс Command. Мне нужно, чтобы SomeCommand реализовал Command и мог быть проанализирован как xml, также IsError должен быть реализован в CommandResult, другие функции должны быть реализованы SomeCommand.

Код:

type Command interface {
    IsError() bool

    Request(buf *bufio.Writer, params interface{}) error
    ...
}

// Result of request
type CommandResult struct {
    Code    int    `xml:"code,attr" json:"code"`
    Message string `xml:"msg" json:"msg"`
}

// this Command's func is realized by CommandResult 
func (self CommandResult) IsError() bool {
    return true
}


// some command
type SomeCommand struct {
    CommandResult // CommandResult `xml:"response>result" json:"result"`
}

// this Command's func is realized by SomeCommand 
func (self SomeCommand) Request(buf *bufio.Writer, params interface{}) error {
    return nil
}

// other Command's functions are realized by CommandResult too

XML:

<epp>
  <response>
    <result code="1000">
      <msg>Command completed successfully</msg>
    </result>
    <trID>
      <svTRID>asd</svTRID>
    </trID>
  </response>
</epp>

Ожидаемый результат:

a := SomeCommand
xml.NewDecoder(reader).Decode(&a)
// a.CommandResult.Code = 1000
// a.CommandResult.Message = 'Command completed successfully'

// a implements Command

1 ответ

Решение
  1. Я думаю, что пути во встроенной структуре должны быть абсолютными, так как все "родительские" структуры являются частью "дочерних". Так что ваши

     type CommandResult struct {
         Code    int    `xml:"code,attr" json:"code"`
         Message string `xml:"msg" json:"msg"`
     }
    

    Должно быть больше похоже

     type CommandResult struct {
         Code    int    `xml:"response>result>code,attr" json:"code"`
         Message string `xml:"response>result>msg" json:"msg"`
     }
    

    НО! Там мы сталкиваемся с ограничением Го.

  2. Вы не можете использовать attr с цепочкой. На Github есть проблема, но, похоже, ее нет в списке приоритетов. Так что если я правильно понимаю краткую версию вашего CommandResult декларация будет:

    type CommandResult struct {
        Result struct {
            Code    int    `xml:"code,attr" json:"code"`
            Message string `xml:"msg" json:"msg"`
        } `xml:"response>result" json:"response"`
    }
    
  3. Не реальная проблема, но в случае, если вы решите конвертировать Command вернуться к XML было бы неплохо объявить его XMLName, Что-то вроде

    type CommandResult struct {
        XMLName xml.Name `xml:"epp"`
        Result  struct {
            Code    int    `xml:"code,attr" json:"code"`
            Message string `xml:"msg" json:"msg"`
        } `xml:"response>result" json:"response"`
    }
    

    Потому что без него XML-кодировщик будет производить что-то вроде <SomeCommand><response>...</response></SomeCommand>

Обновление с полным примером

package main

import (
    "bufio"
    "encoding/xml"
    "log"
)

type Command interface {
    IsError() bool

    Request(buf *bufio.Writer, params interface{}) error
}

// Result of request
type CommandResult struct {
    XMLName xml.Name `xml:"epp"`
    Result  struct {
        Code    int    `xml:"code,attr" json:"code"`
        Message string `xml:"msg" json:"msg"`
    } `xml:"response>result" json:"response"`
}

// this Command's func is realized by CommandResult
func (self CommandResult) IsError() bool {
    return true
}

// some command
type SomeCommand struct {
    CommandResult
}

// this Command's func is realized by SomeCommand
func (self SomeCommand) Request(buf *bufio.Writer, params interface{}) error {
    return nil
}

type AnotherCommand struct {
    CommandResult
}

func (self AnotherCommand) Request(buf *bufio.Writer, params interface{}) error {
    return nil
}

func main() {
    var c Command

    c = SomeCommand{}
    log.Println(c.IsError())

    c = AnotherCommand{}
    log.Println(c.IsError())
}
Другие вопросы по тегам