英文:
When generating an XML file with Go, how do you create a doctype declaration?
问题
Go的xml
包非常出色,使得处理XML变得非常容易。有一件事我不确定如何做:当从本地结构创建XML文档时,如何指定文档类型(doctype)?
例如,这些结构体:
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"`
}
type Skill struct {
XMLName xml.Name `xml:"skill"`
Name string `xml:"skillName"`
YearsPracticed int64 `xml:"practice"`
}
将生成类似于以下的XML:
<person>
<firstName>Bob</firstName>
<middleName></middleName>
<lastName>Jones</lastName>
<age>23</age>
<skills>
<skill>
<skillName>Cooking</skillName>
<practice>3</practice>
</skill>
<skill>
<skillName>Basketball</skillName>
<practice>4</practice>
</skill>
</skills>
</person>
这很好,但是我该如何得到以下结果:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<firstName>Bob</firstName>
<middleName></middleName>
...
这似乎太简单了,但是这是通过字符串拼接来实现的吗?
另外,Go的XML解析器如何处理你想要解组成一组结构体的文本块中的文档类型(doctype)?会忽略它吗?
英文:
Go's xml
package is excellent and makes dealing with XML very easy. There's one thing I'm not sure how to do: when creating an XML document from a native struct, how do you specify the doctype?
For example, these structs:
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"`
}
type Skill struct {
XMLName xml.Name `xml:"skill"`
Name string `xml:"skillName"`
YearsPracticed int64 `xml:"practice"`
}
Will generate something like this XML:
<person>
<firstName>Bob</firstName>
<middleName></middleName>
<lastName>Jones</middleName>
<age>23</age>
<skills>
<skill>
<skillName>Cooking</skillName>
<practice>3</practice>
</skill>
<skill>
<skillName>Basketball</skillName>
<practice>4</practice>
</skill>
</skills>
</person>
Which is great, but what do I do to get this:
<?xml version="1.0" encoding="UTF-8"?>
<person>
<firstName>Bob</firstName>
<middleName></middleName>
...
It almost seems too simple, but is this a matter of doing a string append?
And, on the reverse, how would Go's XML parser handle a doctype in a block of text that you wanted to unmarshal into a set of structs? Ignore it?
答案1
得分: 35
只需将您的编组字节附加到标头即可。如XML Package Source中所示,包含了一个通用的标头:
const (
// 适用于与Marshal的输出一起使用的通用XML标头。
// 这不会自动添加到此包的任何输出中,
// 它只是作为一种便利提供。
Header = `<?xml version="1.0" encoding="UTF-8"?>` + "\n"
)
因此,您可以这样做:
myString, err := xml.MarshalIndent(...) // 这里是缩写
myString = []byte(xml.Header + string(myString))
我找到了一个可工作的示例(不是我的代码),可以在此处找到:http://play.golang.org/p/Rbfb717tvh
英文:
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
答案2
得分: 7
另一种值得一提的方法是使用Go语言的原生XML编码器,它比常见的marshal
函数更适合处理XML流或者处理较大的XML文件。
在这种情况下,你需要先创建要编码的结构体对象,然后创建*File
引用,并将xml.Header
写入其中:
xmlFile, err := os.Create("my-file.xml")
if err != nil {
fmt.Println("Error creating XML file: ", err)
return
}
xmlFile.WriteString(xml.Header)
之后,你需要创建XML编码器,设置缩进,并将需要的结构体编码到XML文件中:
encoder := xml.NewEncoder(xmlFile)
encoder.Indent("", "\t")
err = encoder.Encode(&myStruct)
if err != nil {
fmt.Println("Error encoding XML to file: ", err)
return
}
然后,你应该能够看到生成的XML文件中包含你想要的文档头。
以下是使用你提供的示例进行的快速演示:
package main
import (
"encoding/xml"
"fmt"
"os"
)
// Person 表示XML中的<person>节点
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 表示XML中的<skill>节点
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
}
}
这将生成以下XML文件:
<?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>
英文:
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>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论