如何在GO中解封动态XML

时间:2019-07-03 09:59:52

标签: xml go

我尝试使用Go解析XML,该Go用于与另一个系统交换数据。我知道原则上如何使用xml.Unmarshal函数进行解析。但是,在协议中,根元素<PROTO>的子元素有所不同(请参见下面的示例)。对于子元素(REQUEST.DATAREQUEST.ACLREQUEST.NAC,...-远远超过二十种),到目前为止,我已经定义了xml:...语法的结构-解析这些单子元素的作品。

但是,有没有一种好方法可以将整个消息解析为一个结构,其中一个变量类型取决于子元素?例如使用界面?

可能的XML消息示例:

<PROTO
   version="1.00">
  <REQUEST.DATA>
    <DATA-L>Some information</DATA-L>
  </REQUEST.DATA>
</PROTO>
<PROTO
   version="1.00">
  <REQUEST.ACK>
    <ACK-ID>1</ACK-ID>
  <REQUEST.ACK>
</PROTO>

我的Go应用程序中的摘录:

// XML: REQUEST.DATA
type DataRequest struct {
    LData string `xml:"DATA-L"`
}

// XML: REQUEST.ACK
type AckRequest struct {
    AckId int `xml:"ACK-ID"`
}

// XML: PROTO  <============= ??
type Request struct {
    Version float32  `xml:"version,attr"`
    RemoteRequest {AckRequest, DataRequest, ...} ????
}

func main() {
    message := `<PROTO version="1.00"><REQUEST.ACK><ACK-ID>1</ACK-ID><REQUEST.ACK></PROTO>`
    data := `<REQUEST.ACK><ACK-ID>1</ACK-ID><REQUEST.ACK>`
    doc := &AckRequest{}
    err := xml.Unmarshal([]byte(data), &doc)
    if err != nil {
        fmt.Printf("error: %v", err)
        return
    }
    fmt.Printf("data %+v", doc)
}

我不仅要解析子元素data,而且要解析整个文档message(涉及<PROTO>)。并且想要具有包含各个子元素的信息的结构。

1 个答案:

答案 0 :(得分:0)

您可以将DataRequestAckRequest作为指针嵌入Request结构中。这样,您以后可以检查它们是否为nil

// XML: REQUEST.DATA
type DataRequest struct {
    LData string `xml:"DATA-L"`
}

// XML: REQUEST.ACK
type AckRequest struct {
    AckId int `xml:"ACK-ID"`
}

type Request struct {
    Version float32      `xml:"version,attr"`
    Ack     *AckRequest  `xml:"REQUEST.ACK"`
    Data    *DataRequest `xml:"REQUEST.DATA"`
}

func main() {
    message := `<PROTO version="1.00"><REQUEST.ACK><ACK-ID>1</ACK-ID></REQUEST.ACK></PROTO>`
    proto := &Request{}
    err := xml.Unmarshal([]byte(message), &proto)
    if err != nil {
        fmt.Printf("error: %v", err)
        return
    }
    // if proto.Ack == nil {
    //   fmt.Println("Ack is nil")
    // }
    fmt.Printf("data %+v\n", proto)
    fmt.Printf("data %+v\n", proto.Ack)
}
  

数据&{版本:1 Ack:0xc0000b6050数据:}

     

数据&{AckId:1}

您还可以实现自己的解码器并进行动态类型切换https://stackoverflow.com/a/33517875/1199408