XML and XMPP

221 views
Skip to first unread message

Daniel Corbe

unread,
Jun 18, 2018, 1:01:08 AM6/18/18
to golan...@googlegroups.com
Jabber requires a specific greeting:

<stream:stream
from='im.example.com'
id='++TR84Sm6A3hnt3Q065SnAbbk3Y='
to='jul...@im.example.com'
version='1.0'
xml:lang='en'
xmlns='jabber:client'
xmlns:stream='http://etherx.jabber.org/streams'>

I'm having a bitch of a time designing a struct to encode data. My
current iteration looks like this:

type StreamHeader struct {
XMLName xml.Name `xml:"stream stream"`
From string `xml:"from,attr"`
To string `xml:"to,attr"`
Version string `xml:"version,attr"`
Namespace string `xml:"xmlns,attr"`
XMLns string `xml:"xmlns stream,attr"`
}

Instantiated like so:

streamHeader := StreamHeader{
XMLName: xml.Name{
Space: "stream",
Local: "stream"},
From: jid.String(),
To: jid.GetDomain(),
Version: "1.0",
Namespace: "jabber:client",
XMLns: "http://etherx.jabber.org/streams",
}

Which results in the following:

<stream xmlns="stream" from="dco...@hammerfiber.com"
to="hammerfiber.com" version="1.0" xmlns="jabber:client"
xmlns:_xmlns="xmlns"
_xmlns:stream="http://etherx.jabber.org/streams"</stream>

Obviously, I have a fundamental misunderstanding of how the
Encoder/Marshaller works.

What's tripping me up the most right now is the requirement for multiple
xmlns attributes. Every time a new one appears, Go appends a _ to it.

There isn't enough documentation on this process. Can someone please
hit me with a clue bat?



C Banning

unread,
Jun 18, 2018, 2:39:36 PM6/18/18
to golang-nuts

Daniel Corbe

unread,
Jun 19, 2018, 10:41:25 AM6/19/18
to C Banning, golang-nuts
Thanks. This worked like a charm.

I tip my hat to you, kind stranger.
> --
> You received this message because you are subscribed to the Google Groups
> "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.


ma...@degeneration.co.uk

unread,
Jun 26, 2018, 9:00:38 PM6/26/18
to golang-nuts

In my experience, encoding/xml works best if you let it handle the namespace details itself rather than trying to explicitly choose the prefixes and set the xmlns attributes. While you can often force the encoder to produce namespace markers directly, proper decoding requires handling various different forms that are all considered semantically equivalent, which the decoder can handle for you if you let it.

Also, with the streaming nature of XMPP it may prove simpler to handle the main open and close tags as raw tokens and then use the automatic marshaling for the individual stanzas in an xml.Encoder.


One downside of this is that encoding/xml forces a relatively simple use of XML namespaces where elements are always unprefixed and the namespaces are marked with xmlns attributes. For XMPP in particular, that means that each stanza repeats the xmlns="jabber:client" attribute, which is a valid way to express the XML stream but not the most efficient one in terms of bytes transferred:

        from="im.example.com"
        to="jul...@im.example.com"
        id="++TR84Sm643hnt3!065SnAbbk3Y="
        version="1.0"
        xml:lang="1.0">
  <message xmlns="jabber:client"
           from="f...@im.example.com"
           to="jul...@im.example.com"
           type="chat">
    <body>Hello, world!</body>
  </message>
</stream>


A similar approach can be used to parse an incoming stream, by processing the opening and closing stream tags using Decoder.Token directly, then using DecodeElement for each of the stanzas inside after reading the start token to select an appropriate struct type to decode into.

Sam Whited

unread,
Jun 27, 2018, 11:52:55 PM6/27/18
to golan...@googlegroups.com
On Mon, Jun 18, 2018, at 00:00, Daniel Corbe wrote:
> Jabber requires a specific greeting:
>
> …
>
> I'm having a bitch of a time designing a struct to encode data. My
> current iteration looks like this:

As much as I hate to admit it, I normally Fprintf the stream header onto the wire (taking care that the JID implementation is sound and can't break the XML) and then construct an encoder around the connection.
It's jank, but the encoding/xml package really isn't designed for this and you'll end up running into all sorts of odd issues if you try to do it with a struct.
If you're relying on being able to check for the jabber:client or jabber:server namespace this will break, but I've never run into a situation where I cared what it was on the encoder.

I have a JID implementation that works well for the to/from attributes here if you want it: https://godoc.org/mellium.im/xmpp/jid

The base XMPP package I don't work on often and is more a playground for me to try out new XEPs than anything useful, but the JID package should be stable enough.

―Sam

Sam Whited

unread,
Jun 29, 2018, 3:03:03 PM6/29/18
to golan...@googlegroups.com
Also, FYI, I forgot to link it, but I recently started a Go chat that a handful of people hang out in. You can access it from any network that supports XMPP:

gol...@conference.samwhited.com

—Sam

On Mon, Jun 18, 2018, at 00:00, Daniel Corbe wrote:
> --
> You received this message because you are subscribed to the Google
> Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send
> an email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.


--
Sam Whited
s...@samwhited.com
Reply all
Reply to author
Forward
0 new messages