xmlctx

package module
v0.13.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 21, 2026 License: Apache-2.0 Imports: 6 Imported by: 3

README

xmlctx

Go Reference codecov

Namespace-aware XML decoder for Go.

The standard encoding/xml package can't properly match struct tags like xml:"ns1:profile" because it resolves namespace prefixes to full URIs. This means identical XML documents with different prefixes won't decode correctly.

xmlctx fixes this by letting you map struct tag prefixes to namespace URIs, then matching elements based on URI instead of prefix name.

Note: This library is for decoding/unmarshaling XML only. For marshaling structs to XML, use the standard encoding/xml package.

Installation

go get github.com/invopop/xmlctx

Usage

type Person struct {
    XMLName xml.Name `xml:"http://example.com/user person"`
    XmlnsA  string   `xml:"xmlns:addr,attr"`
    Name    string   `xml:"name"`
    Email   string   `xml:"email"`
    City    string   `xml:"addr:city"`
    Country string   `xml:"addr:country"`
}

var person Person
decoder := xmlctx.NewDecoder(
    bytes.NewReader(xmlData),
    xmlctx.WithNamespaces(map[string]string{
        "":     "http://example.com/user",
        "addr": "http://example.com/address",
    }),
)
err := decoder.Decode(&person)

The XML can use any prefix (addr:, a:, address:, etc.) as long as it maps to the correct namespace URI.

Example

These three XML documents all decode the same way:

<user xmlns:ns1="http://example.com/profile">
  <ns1:bio>Software engineer</ns1:bio>
</user>

<user xmlns:prf="http://example.com/profile">
  <prf:bio>Software engineer</prf:bio>
</user>

<user xmlns="http://example.com/profile">
  <bio>Software engineer</bio>
</user>

All work with:

type User struct {
    XMLName xml.Name `xml:"user"`
    XmlnsNS string   `xml:"xmlns:ns1,attr"`
    Bio     string   `xml:"ns1:bio"`
}

decoder := xmlctx.NewDecoder(
    bytes.NewReader(data),
    xmlctx.WithNamespaces(map[string]string{
        "ns1": "http://example.com/profile",
    }),
)
err := decoder.Decode(&user)

What's supported

  • Namespace URI matching instead of prefix matching
  • Default namespaces
  • Nested namespace declarations
  • Multiple prefixes for the same namespace
  • Namespaced attributes
  • String, bool, integer (int, int8-64, uint, uint8-64), pointer, and slice types
  • Character data (,chardata tag)
  • CDATA sections (,cdata tag)
  • XML comments (,comment tag)
  • Inner XML content (,innerxml tag)
  • Path syntax for nested elements (> operator, e.g., xml:"parent>child")
  • Catch-all for unmatched elements (,any tag)
  • Catch-all for unmatched attributes (,any,attr tag)
  • XMLName field for recording element name and namespace
  • Custom unmarshaling via xml.Unmarshaler interface
  • Custom attribute unmarshaling via xml.UnmarshalerAttr interface
  • Text unmarshaling via encoding.TextUnmarshaler interface

Examples

See the examples/ directory for complete, runnable programs:

  • basic - Basic usage with namespace-aware structs
  • different-prefixes - Same struct decodes XML with different prefixes
  • roundtrip - Marshal and unmarshal with the same struct

Run them with:

cd examples/basic && go run main.go

Documentation

Overview

Package xmlctx provides a namespace-aware XML decoder for Go.

The standard encoding/xml package can decode namespaced XML, but it cannot properly match namespace-aware struct tags because it resolves prefixes to full URIs in StartElement.Name.Space, while struct tags use prefixes.

This package solves this problem by allowing you to specify a namespace context that maps prefixes (used in struct tags) to their full namespace URIs. The decoder then matches XML elements based on their namespace URI, regardless of what prefix is used in the actual XML document.

Note: This package is for decoding/unmarshaling XML only. For marshaling structs to XML, use the standard encoding/xml package.

Example usage:

type Person struct {
    Name  string `xml:"name"`
    Email string `xml:"addr:email"`
}

decoder := xmlctx.NewDecoder(
    bytes.NewReader(xmlData),
    xmlctx.WithNamespaces(map[string]string{
        "":     "http://example.com/user",
        "addr": "http://example.com/address",
    }),
)
err := decoder.Decode(&person)

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Unmarshal added in v0.5.0

func Unmarshal(data []byte, v any, opts ...Option) error

Unmarshal decodes XML with namespace context awareness

Types

type Decoder

type Decoder struct {
	// contains filtered or unexported fields
}

Decoder wraps xml.Decoder with namespace context awareness

func NewDecoder

func NewDecoder(r io.Reader, opts ...Option) *Decoder

NewDecoder creates a new namespace-aware decoder

func (*Decoder) Decode

func (d *Decoder) Decode(v any) error

Decode decodes the XML into the provided value

type Option

type Option func(*Decoder)

Option is a functional option for configuring the Decoder

func WithNamespaces

func WithNamespaces(namespaces map[string]string) Option

WithNamespaces sets the namespace mappings for the decoder The map keys are prefixes used in Go struct tags (e.g., "ns1", "ns2", "") The map values are the full namespace URIs (e.g., "http://example.com/schema/profile")

Directories

Path Synopsis
examples
basic command
roundtrip command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL