2

I want to create structs = each type of command.

Commands have common part of xml - CommandResult. I created interface Command. I need to SomeCommand implements Command and can to be parsed as xml, also IsError must be realized in CommandResult, other functions must be realized by SomeCommand.

Code:

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>

Expected result:

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

// a implements Command
Harlam
  • 408
  • 2
  • 11

1 Answers1

1
  1. I think paths in embedded structure should be absolute as all "parent's" structures are part of the "child". So your

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

    Should be more like

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

    BUT! There we are facing Go's limitation.

  2. You can't use attr with chaining. There is issue on Github but looks like it is not in priority list. So if I right understand shortest version of your CommandResult declaration would be:

    type CommandResult struct {
        Result struct {
            Code    int    `xml:"code,attr" json:"code"`
            Message string `xml:"msg" json:"msg"`
        } `xml:"response>result" json:"response"`
    }
    
  3. Not a real problem but in case if you will decide to convert Command back to XML would be nice to declare its XMLName. Something like

    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"`
    }
    

    Because without it XML encoder will produce something like <SomeCommand><response>...</response></SomeCommand>

Update with full example

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())
}
CrazyCrow
  • 4,125
  • 1
  • 28
  • 39
  • thanks for answer. I know it all. Main problem is for me that function IsError() must be copied again and again for each struct (SomeCommand, OtherCommand, ...) for realization Command interface in this cases. And I don't want to do it. – Harlam Feb 04 '16 at 03:02
  • 1
    @Harlam I don't understand what do you mean by "again and again". If you embedding `CommandResult` into `SomeCommand` `SomeCommand` automatically "inhirits" `IsError` method. I've added full example in update. – CrazyCrow Feb 04 '16 at 09:52