How to handle multiple xml API response results with go?

485 views Asked by At

To handle a xml API response result, need to catch multiple cases. For a success case and a failure case, I can define 2 struct to handle both of them. The source as: go playground.

If the response data has many results, and they don't have the same xml structure, we can define all the struct types in go. But is there an easy way to catch its data?

I found go's xml UnmarshalXML method can rewrite xml data. Package xml But use it need to set to special and unique struct first:

func (r *PostSuccessResponse) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {

    return nil
}

Is it possible to use startElement.Name.Local to iterate over all the response xml data to check what element it has, then use which go struct to handle? Such as if found Fault then use PostFailureResponse struct, if found return then use PostSuccessResponse struct.

1

There are 1 answers

1
Gopher On

Based on the suggestion from comments I recreated your code as follows:

package main

import (
    "encoding/xml"
    "fmt"
)

type PostSuccessResponse struct {
    PostID     string `xml:"return>postResult>postId"`
    PostNumber string `xml:"return>postNumber"`
}

type PostFailureResponse struct {
    Code    string `xml:"detail>faultDetails>code"`
    Details string `xml:"detail>faultDetails>details"`
}

type Response struct {
    PostSuccessResponse *PostSuccessResponse `xml:"Body>postResponse"`
    PostFailureResponse *PostFailureResponse `xml:"Body>Fault"`
}

func main() {
    var response1 = &Response{}
    if err := xml.Unmarshal([]byte(successPayload), response1); err != nil {
        panic(err)
    }
    fmt.Printf("success=%+v failure=%+v\n", response1.PostSuccessResponse, response1.PostFailureResponse)

    var response2 = &Response{}
    if err := xml.Unmarshal([]byte(failurePayload), response2); err != nil {
        panic(err)
    }
    fmt.Printf("success=%+v failure=%+v\n", response2.PostSuccessResponse, response2.PostFailureResponse)
}

var successPayload = []byte(`
    <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
       <env:Header/>
       <env:Body>
          <ns2:postResponse xmlns:ns2="http://example.com/">
             <return>
                <postDetails>
                    <title>P</title>
                    <body>A</body>
                </postDetails>
                <postResult>
                   <postId>1234</postId>
                </postResult>
                <postNumber>1000000</postNumber>
             </return>
          </ns2:postResponse>
       </env:Body>
    </env:Envelope>
`)

var failurePayload = []byte(`
    <env:Envelope xmlns:env="http://schemas.xmlsoap.org/soap/envelope/">
       <env:Header/>
       <env:Body>
          <env:Fault>
             <faultcode>env:Server</faultcode>
             <faultstring>An unexpected problem occurred</faultstring>
             <detail>
                <ns2:faultDetails xmlns:ns2="http://example.com/">
                   <code>Unexpected error</code>
                   <details>The post content is not right.</details>
                </ns2:faultDetails>
             </detail>
          </env:Fault>
       </env:Body>
    </env:Envelope>
`)

Output:

success=&{PostID:1234 PostNumber:1000000} failure=<nil>
success=<nil> failure=&{Code:Unexpected error Details:The post content is not right.}