英文:
How to parse xml correctly
问题
我想创建结构体来表示每种类型的命令。
命令有一个共同的XML部分 - CommandResult。我创建了一个接口Command。我需要SomeCommand实现Command接口,并且可以被解析为XML,同时还需要在CommandResult中实现IsError函数,其他函数由SomeCommand实现。
代码:
type Command interface {
    IsError() bool
    Request(buf *bufio.Writer, params interface{}) error
    ...
}
// 请求的结果
type CommandResult struct {
    Code    int    `xml:"code,attr" json:"code"`
    Message string `xml:"msg" json:"msg"`
}
// 这个Command的函数由CommandResult实现
func (self CommandResult) IsError() bool {
    return true
}
// 一些命令
type SomeCommand struct {
    CommandResult // CommandResult `xml:"response>result" json:"result"`
}
// 这个Command的函数由SomeCommand实现
func (self SomeCommand) Request(buf *bufio.Writer, params interface{}) error {
    return nil
}
// 其他Command的函数也由CommandResult实现
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实现了Command接口
英文:
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
答案1
得分: 1
我认为嵌入结构中的路径应该是绝对路径,因为所有的“父级”结构都是“子级”的一部分。所以你的代码应该更像是这样的:
type CommandResult struct {
    Code    int    `xml:"response>result>code,attr" json:"code"`
    Message string `xml:"response>result>msg" json:"msg"`
}
但是!我们面临着Go语言的限制。
你不能在链式结构中使用attr。在Github上有一个相关的问题(https://github.com/golang/go/issues/3688),但看起来它不在优先列表中。所以如果我正确理解的话,你的CommandResult声明的最简版本应该是:
type CommandResult struct {
    Result struct {
        Code    int    `xml:"code,attr" json:"code"`
        Message string `xml:"msg" json:"msg"`
    } `xml:"response>result" json:"response"`
}
这不是一个真正的问题,但是如果你决定将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
}
// 请求的结果
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"`
}
// 这个Command的函数由CommandResult实现
func (self CommandResult) IsError() bool {
    return true
}
// 一些命令
type SomeCommand struct {
    CommandResult
}
// 这个Command的函数由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())
}
希望对你有所帮助!
英文:
- 
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.
 - 
You can't use
attrwith chaining. There is issue on Github but looks like it is not in priority list. So if I right understand shortest version of yourCommandResultdeclaration 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"` } - 
Not a real problem but in case if you will decide to convert
Commandback to XML would be nice to declare itsXMLName. Something liketype 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())
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论