LanguagesWorking with XML files in Go

Working with XML files in Go

Go Concurrent Programming

Although XML is more complicated and sophisticated than JSON, it has been in use for data interchange for quite some time. The encoding/xml package can encode and decode structs to and from XML format in a similar way to the encoding/json package. This article quickly explores Go’s standard library while working with XML files.

XML and Golang Programming Examples

XML stands for eXtensible Markup Language is another widely used format to represent and serialize data. Like JSON, it is also a text based markup language derived from Standard Generalized Markup Language (SGML is an international standard for the definition of markup languages…Markup consists of notations called tags that specify the function of a piece of text or how it is to be display).

XML is particularly used to structure information such as documents, data, configuration, and so forth and is widely used to share structured information between programs, people or computers locally as well as over the network. If you are familiar with HTML, the tags used there are fixed or predefined. But in XML, the tags are defined by the creator of the document, and an opening tag must have its corresponding closing tag. Here is a short example of XML markup:

<item number=”E112586”>

<name>Erythromycin</name>

<uses>

Oral; macrolide antibiotic; Does not work for viral infections.

This medication is best absorbed when taken on an empty stomach.

</uses>

<side-effect>

Nausea, vomiting, diarrhea, stomach cramp, loss of appetite.

</side-effect>

</item>

Although it looks similar to HTML, the syntax rules are stricter. Any error in the syntax will not be processed by the XML tool. Key XML syntax rules are as follows:

XMLSyntax Rules

  • All elements must be closed or marked as empty. For example, an empty tag can be: <empty></empty> or use short form </empty> instead.
  • Attributes with the tag must be quoted such as .
  • XML does not have any built-in tags (but the names beginning with xml have special meaning).
  • There are only five built-in character entities: &lt for symbol; &gt for > symbol; &amp for & (ampersand) character; &quot for (double-quotes) and &apos for (single-quote) character respectively.

Encoding and Decoding XML in Go

Unlike JSON, XML is much more verbose, sophisticated and complex. As a result, it is very tedious to write it manually. The encode/xml package provides all the processing power required by the programmer to encode and decode XML from and to struct type in Go much like encode/json. Initially, encoding and decoding by the encoding/xml package used to require more effort and there was no Marshal/Unmarshaller interface. But with later Go versions, this has been changed and now there is almost no visible difference between encoding/json and encoding/xml functionalities. Since they mostly serve similar purposes, their functionalities are also the same.

Below, Golang developers will find a quick example that will illustrate the idea better.

This is a simple example where we marshal/encode a Go struct into XML format and create an XML file to store the information. Later, we again read the XML file, unmarshal/decode the data back into struct type and display it. That’s all.

package main

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

type Employee struct {
	XMLName xml.Name `xml:"employee"`
	Id      int      `xml:"id,attr"`
	Name    string   `xml:"name"`
	Email   string   `xml:"email"`
	Phone   []string `xml:"phone"`
}

func main() {

	//*************************************
	// struct to XML file
	//*************************************
	e1 := &Employee{Id: 101, Name: "Donald Duck", Email: "[email protected]"}
	e1.Phone = []string{"12345", "23456"}

	data, err := xml.MarshalIndent(e1, " ", "  ")
	if err != nil {
		log.Fatal(err)
	}
	err = ioutil.WriteFile("emp.xml", data, 0666)
	if err != nil {
		log.Fatal(err)
	}

	//*************************************
	// XML file to struct
	//*************************************

	data, err = ioutil.ReadFile("emp.xml")
	if err != nil {
		log.Fatal(err)
	}
	e1 = &Employee{}
	err = xml.Unmarshal([]byte(data), &e1)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(e1.Id)
	fmt.Println(e1.Name)
	fmt.Println(e1.Email)
	fmt.Println(e1.Phone)
}

According to Go documentation: “Marshal returns the XML encoding of the value supplied to it as its parameter and handles an array or slice by marshaling each of the elements. It handles a pointer by marshaling the value it points at or, if the pointer is nil, by writing nothing. It handles an interface value by marshaling the value it contains or, if the interface value is nil, by writing nothing. Marshal handles all other data by writing one or more XML elements containing the data.”

Note that, to marshall the struct type, we have invoked the function MarshalIndent function. This function works just like Marshal, but puts each XML element into a new indented line. It starts with a prefix followed by more copies of indent as per the nesting depth.

The Unmarshal function produces a reverse effect and parses the XML encoded data and stores the value in a struct, slice or string. Any malformed data that does not fit into struct, slice or string type is discarded.

A few intricacies while formulating struct fields. This defines how we want to map out struct’s fields to and from XML. The xml.Name field is used for tagging the root name to begin the struct in the XML code. Fields tagged as `xml:”id, attr”` means that it is designated to be the attribute of the field name.

Notice that there is not much of a difference if we put a simple struct type and a struct type formulated to work with XML side by side.

A normal struct
A struct to work with XML
type Employee struct {
	Id      int      
	Name    string   
	Email   string   
	Phone   []string 
}
type Employee struct {
	XMLName xml.Name `xml:"employee"`
	Id      int      `xml:"id,attr"`
	Name    string   `xml:"name"`
	Email   string   `xml:"email"`
	Phone   []string `xml:"phone"`
}

Read: Working with JSON Files in Go.

XML, JSON, and the Go Programming Language

The main advantage to XML is its verbosity and textual representation of data. It is widely used for data exchange by almost all programming languages. Either they provide an in-built library for dealing with XML or have third party support. Go however has built-in support for XML, JSON and other types. It is worth mentioning that although XML and JSON are quite popular, they are not the only two. In fact, there are more optimized formats for data transfer available for use in Go applications. They are relatively new developments such as protocol buffers (aka, protobuf) by Google, Apache Thrift developed by Facebook. They are optimized for faster data transfer and serialization. Go has support for these too along with many others.

Read more Go and Golang programming tutorials.

Latest Posts

Related Stories