When generating an XML file with Go, how do you create a doctype declaration?

Simply append your marshalled bytes to the header. As seen in the XML Package Source, a generic header is included:

const (
    // A generic XML header suitable for use with the output of Marshal.
    // This is not automatically added to any output of this package,
    // it is provided as a convenience.
    Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
)

So, this would do it:

myString, err := xml.MarshalIndent(...) // abbreviated here
myString = []byte(xml.Header + string(myString))

A working example I'd found (not my code) available at: http://play.golang.org/p/Rbfb717tvh


Another approach that might worth mentioning here is the one that uses the native XML encoders from Go, which are more suitable than the common marshal function when dealing with streams of XML, or when you plan to work with pretty large XML files.

In this case you would follow a similar approach by creating the struct objects you want to encode first, but now the 2nd step will be creating the *File reference and then writing the xml.Header to it:

xmlFile, err := os.Create("my-file.xml")
if err != nil {
    fmt.Println("Error creating XML file: ", err)
    return
}
xmlFile.WriteString(xml.Header)

After that you will need to create your XML encoder, set up its indentation, and finally encoding the necessary structs into the XML file:

encoder := xml.NewEncoder(xmlFile)
encoder.Indent("", "\t")
err = encoder.Encode(&myStruct)
if err != nil {
    fmt.Println("Error encoding XML to file: ", err)
    return
}

You should see the resulting XML file with the document header you want after that.

Here is a quick POF by using the samples you provided:

package main

import (
    "encoding/xml"
    "fmt"
    "os"
)

// Person represents a <person> node in the XML
type Person struct {
    XMLName    xml.Name `xml:"person"`
    FirstName  string   `xml:"firstName"`
    MiddleName string   `xml:"middleName"`
    LastName   string   `xml:"lastName"`
    Age        int64    `xml:"age"`
    Skills     []Skill  `xml:"skills"`
}

// Skill represents a <skill> node in the XML
type Skill struct {
    XMLName        xml.Name `xml:"skill"`
    Name           string   `xml:"skillName"`
    YearsPracticed int64    `xml:"practice"`
}

func main() {
    person := Person{
        FirstName:  "Bob",
        MiddleName: "",
        LastName:   "Jones",
        Age:        23,
        Skills: []Skill{
            {
                Name:           "Cooking",
                YearsPracticed: 3,
            },
            {
                Name:           "Basketball",
                YearsPracticed: 4,
            },
        },
    }

    xmlFile, err := os.Create("person.xml")
    if err != nil {
        fmt.Println("Error creating XML file: ", err)
        return
    }
    xmlFile.WriteString(xml.Header)
    encoder := xml.NewEncoder(xmlFile)
    encoder.Indent("", "\t")
    err = encoder.Encode(&person)
    if err != nil {
        fmt.Println("Error encoding XML to file: ", err)
        return
    }
}

And this will generate the following XML file:

<?xml version="1.0" encoding="UTF-8"?>
<person>
    <firstName>Bob</firstName>
    <middleName></middleName>
    <lastName>Jones</lastName>
    <age>23</age>
    <skill>
        <skillName>Cooking</skillName>
        <practice>3</practice>
    </skill>
    <skill>
        <skillName>Basketball</skillName>
        <practice>4</practice>
    </skill>
</person>

Tags:

Xml

Doctype

Go