Skip to Content
Course content

132: encoding/xml Basics

Click on the "Edit" button in the top corner of the screen to edit your slide content.

If you've already spent some time with encoding/json, you're probably feeling confident about how Go handles data serialization. You might be thinking, "I've got this; XML is just JSON with angle brackets and a few more rules."

The "JSON Equivalence" Trap

Here is where most developers trip up. In JSON, everything is a key-value pair. In XML, however, there is a fundamental distinction between an attribute and an element. If you try to treat them the same way in your Go structs, your unmarshaling code will simply return empty strings without throwing an error, leaving you wondering why your data vanished.

Take a look at this snippet of XML representing a product in a catalog:

<product id="978-0134190440">
    <title>The Go Programming Language</title>
    <price>34.99</price>
</product>

If you write your Go struct like this, you're going to have a bad time:

type Product struct {
    ID    string
    Title string
    Price float64
}

When you run xml.Unmarshal on this, Title and Price will populate correctly because they are elements. But ID? It'll be empty. Why? Because id is an attribute of the product tag, not a nested element. Go's XML package doesn't guess; it needs you to be explicit.

Mapping Attributes and Elements Explicitly

To fix this, you have to use struct tags. While JSON tags are usually just the name of the key, XML tags allow you to specify the nature of the data. To capture that ID, you need the ,attr suffix.

type Product struct {
    ID    string  `xml:"id,attr"`
    Title string  `xml:"title"`
    Price float64 `xml:"price"`
}

I'll let you in on a secret: XML is significantly more verbose and "opinionated" than JSON. You'll often find yourself dealing with nested wrappers. For instance, if your XML has a list of products wrapped in a <catalog> tag, you can't just unmarshal into a slice of products. You need a wrapper struct.

Here is how I usually handle a collection of items:

type Catalog struct {
    XMLName  xml.Name  `xml:"catalog"`
    Products []Product `xml:"product"`
}

Notice the XMLName field. While not strictly required for simple unmarshaling, adding it tells Go exactly which root element this struct is intended to map to. It makes your code much more self-documenting.

Dealing with the "Inner" and "Outer" XML

Sometimes you don't want to map every single field to a struct. Maybe you just want the raw XML content inside a specific tag. For that, Go provides the ,innerxml tag.

This is incredibly useful when you're dealing with a legacy API that returns a mix of structured data and arbitrary XML fragments that you intend to pass along to another service without parsing them. Just remember that innerxml captures the raw bytes, so you're responsible for whatever mess is inside those tags.

  • Use ,attr for data inside the opening tag (like id="123").
  • Use standard tags for data between tags (like <name>Go</name>).
  • Create wrapper structs for root elements that contain lists.
  • Use ,innerxml when you need the raw raw content.



📋 Practical Task

Building a Weather Station Data Parser

You have been handed a legacy XML feed from a remote weather station. Your task is to create a Go program that parses this data and calculates the average temperature from the sensors.

The XML Input:

<weather_station id="STATION_001" location="North_Pole">
    <readings>
        <sensor id="S1">
            <temp>-25.4</temp>
        </sensor>
        <sensor id="S2">
            <temp>-22.1</temp>
        </sensor>
        <sensor id="S3">
            <temp>-28.7</temp>
        </sensor>
    </readings>
</weather_station>

Requirements:

  • Define the necessary structs to map the id and location as attributes of the station.
  • Properly map the nested readings and the slice of sensor elements.
  • The sensor struct must capture the id as an attribute and the temp as an element.
  • Write a main function that unmarshals the XML string and prints: "Station STATION_001 in North_Pole reports an average temperature of X".
Rating
0 0

There are no comments for now.

to be the first to leave a comment.