5

Is there a way to retain xml namespace prefixes when encoding? I am processing XML using the xml.Decoder Token/RawToken function and doing some transformations. There is a large amount of XML we want to remain formatted similar to the original XML. When I write a StartElement token back out unchanged the namespaces get written incorrectly.

Desired output:

<Inq xmlns="http://test/default">
  <Num>TestNum</Num>
  <test xmlns:t="http://test/prefix">
    <t:namespace>test</t:namespace>
  </test>
</Inq>

Actual output:

<Inq xmlns="http://test/default">
  <Num>TestNum</Num>
  <test xmlns:_xmlns="xmlns" _xmlns:t="http://test/prefix">
    <namespace xmlns="t">test</namespace>
  </test>
</Inq>

Code to reproduce the issue:

package main

import (
    "bytes"
    "encoding/xml"
    "fmt"
    "io"
    "strings"
)

func main() {
    expected := `<Inq xmlns="http://test/default"><Num>TestNum</Num><test xmlns:t="http://test/prefix"><t:namespace>test</t:namespace></test></Inq>`
    payloadReader := strings.NewReader(expected)
    decoder := xml.NewDecoder(payloadReader)
    buf := new(bytes.Buffer)
    encoder := xml.NewEncoder(buf)

    for {
        token, err := decoder.RawToken()
        if err != nil {
            if err == io.EOF {
                break
            }

            panic(err)
        }

        if token == nil {
            break
        }

        if err := encoder.EncodeToken(token); err != nil {
            panic(err)
        }
    }

    if err := encoder.Flush(); err != nil {
        panic(err)
    }

    actual := buf.String()
    if actual != expected {
        fmt.Printf("got: %s\nwant: %s\n", actual, expected)
    }
}

https://go.dev/play/p/mrjN5xOAp-y

Is there anyway to get the desired behavior other than tracking the namespace and prefixes and recreating the Start and End elements with the desired prefix naming?

1

1 Answer 1

0

This is not yet possible using an official Go release but this feature request which is still in review makes it possible. It's not yet released which means that you need to build and use your own Go compiler which can be problematic especially if you want to build the code on another machine as a part of the CI pipeline. To build the custom Go compiler:

$ git clone https://go.googlesource.com/go
$ cd go/src
$ git fetch https://go.googlesource.com/go refs/changes/53/355353/30 && git checkout -b change-355353 FETCH_HEAD
$ git rebase origin
$ ./make.bash
$ PATH="$PWD"/../bin:"$PATH"
$ GOROOT="$(git rev-parse --show-toplevel)"

Now, in the same shell, change to the directory where you have the code. Make sure you use the correct Go compiler (the timestamp will be different):

$ go version
go version go1.25-devel_dcc605f108 Sat May 24 23:57:00 2025 +0200 linux/amd64

Make one change - replace:

token, err := decoder.RawToken()

with:

token, err := decoder.Token()

Run code:

$ go run .
$

Output is now as you expected.

Your question is specifically about encoding/xml but https://github.com/golang/go/issues/9519 issue mentioned in the comment under the question mentions using an external library that reportedly supports the feature you're looking for out of the box:

For now, I found a replacement to encoding/xml using nbio/xml which handles namespaces properly.

So if you don't want to use a custom Go compiler with unreleased features you can consider using nbio/xml.

Sign up to request clarification or add additional context in comments.

2 Comments

I had seen github.com/golang/go/issues/9519 before posting and tested out nbio/xml which does not work. It produces the same xml as the current go release. This only seems to help if you are marshalling/unmarshalling. I tested with the feature still in review and this worked the way I would expect. Is there a timeline on when this would be released? Looks like the feature has been there for a couple years.
There is no timeline, it's up to the Go team to accept it or reject it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.