T
T
Toster1002016-03-18 13:05:18
go
Toster100, 2016-03-18 13:05:18

Go how to parse XML?

Let's say there is XML that needs to be deserialized

<stream:features>
    <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
    <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
        <mechanism>PLAIN</mechanism>
        <mechanism>DIGEST-MD5</mechanism>
        <mechanism>SCRAM-SHA-1</mechanism>
    </mechanisms>
    <c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.process-one.net/en/ejabberd/' ver='NUUMEO3rKA30XLGO1FbA9EZT1rY='/>
    <register xmlns='http://jabber.org/features/iq-register'/>
</stream:features>

(As you might guess, I decided to write my own implementation of an XMPP client as an exercise to understand the topic of working with XML in Go).
And, frankly, there are a lot of questions, but, in short, I don’t understand how to do it at all. Let's say I want to deserialize a list of mechanisms, for this I have declared the following structures:
type Mechanism struct {
  XMLName   xml.Name `xml:"mechanism"`
  Mechanism string
}
type Features struct {
  XMLName    xml.Name    `xml:"features"`
  Mechanisms []Mechanism `xml:mechanisms`
}
Let's just say, I myself understand that this will not work, and indeed, when trying to unmarshal, a nil structure of type Features is obtained.
How to get the contents of the mechanism tags (it is not set by attributes, but just inside the tag)?
Do I need to describe the entire structure or can I describe only those fields that interest me?
Another question: let's say there is a <sometag/> tag that works like a flag. How can you reflect its presence / absence in the structure?
It is likely that this topic has already been described somewhere, if so, I will be glad to provide a link with specific examples (possible in eng).
And another question, for example, I can have two variants of an object coming in response from the server and I don’t know in advance which one will come, but in xml.Unmarshal I need to pass a pointer to a structure of a certain type. How to be in such a situation?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Alexander Pavlyuk, 2016-03-18
@pav5000

Something like this: https://play.golang.org/p/yiKGZY4GZL

package main

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

type CNode struct {
  Hash string `xml:"hash,attr"`
  Node string `xml:"node,attr"`
}

type Features struct {
  XMLName    xml.Name `xml:"stream features"`
  Mechanisms []string `xml:"mechanisms>mechanism"`
  C          CNode    `xml:"c"`
}

func main() {
  raw_data := []byte(`
        <stream:features>
            <starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
            <mechanisms xmlns='urn:ietf:params:xml:ns:xmpp-sasl'>
                <mechanism>PLAIN</mechanism>
                <mechanism>DIGEST-MD5</mechanism>
                <mechanism>SCRAM-SHA-1</mechanism>
            </mechanisms>
            <c xmlns='http://jabber.org/protocol/caps' hash='sha-1' node='http://www.process-one.net/en/ejabberd/' ver='NUUMEO3rKA30XLGO1FbA9EZT1rY='/>
            <register xmlns='http://jabber.org/features/iq-register'/>
        </stream:features>
    `)

  var v Features
  err := xml.Unmarshal(raw_data, &v)
  if err != nil {
    log.Fatal(err)
  }

  fmt.Printf("%+v\n", v)
}

Basically, the specification and a couple of examples are here https://golang.org/pkg/encoding/xml

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question