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>