Golang解析XML时如何处理缺失的属性或标签
Golang解析XML时如何处理缺失的属性或标签 大家好,
我刚开始学习Go语言,我的第一个迷你项目是尝试编写一个非常简单的代码片段,用于将XML转换为CSV。
我能够相当轻松地让代码片段运行起来,但在处理一个简单的标签缺失边界情况时遇到了困难。在下面Playground链接中的示例中;当XML的第二部分缺少LastName时,我希望代码片段用空字符串更新切片。目前的情况是,当标签缺失时,代码片段会完全忽略该元素,这会在写入CSV时导致问题。
https://play.golang.org/p/JX10U9hH1c3
当前LastName输出: [Raboy Doe]
期望的LastName输出: [Raboy “” Doe]
谢谢。
更多关于Golang解析XML时如何处理缺失的属性或标签的实战教程也可以访问 https://www.itying.com/category-94-b0.html
3 回复
更改您正在解组的目标模型:https://play.golang.org/p/16-J0L-eN-a
在Go中处理XML时,当标签缺失时确实需要特殊处理。你可以通过检查xml.Unmarshal的解析结果,或者在结构体中使用指针类型来区分"缺失"和"空值"。
以下是修改后的代码示例:
package main
import (
"encoding/xml"
"fmt"
)
type Person struct {
XMLName xml.Name `xml:"Person"`
First string `xml:"FirstName"`
Last *string `xml:"LastName"` // 使用指针类型
}
type People struct {
XMLName xml.Name `xml:"People"`
Person []Person `xml:"Person"`
}
func main() {
xmlData := `
<People>
<Person>
<FirstName>Michael</FirstName>
<LastName>Raboy</LastName>
</Person>
<Person>
<FirstName>John</FirstName>
</Person>
<Person>
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>`
var people People
err := xml.Unmarshal([]byte(xmlData), &people)
if err != nil {
fmt.Println("Error:", err)
return
}
var lastNames []string
for _, person := range people.Person {
if person.Last != nil {
lastNames = append(lastNames, *person.Last)
} else {
lastNames = append(lastNames, "") // 缺失时用空字符串
}
}
fmt.Println("LastNames:", lastNames)
}
另一种方法是使用自定义的UnmarshalXML方法:
package main
import (
"encoding/xml"
"fmt"
"strings"
)
type Person struct {
XMLName xml.Name `xml:"Person"`
First string `xml:"FirstName"`
Last string `xml:"LastName"`
}
func (p *Person) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
type Alias Person
temp := &struct {
Last *string `xml:"LastName"`
*Alias
}{
Alias: (*Alias)(p),
}
if err := d.DecodeElement(temp, &start); err != nil {
return err
}
if temp.Last != nil {
p.Last = *temp.Last
} else {
p.Last = "" // 显式设置为空字符串
}
return nil
}
type People struct {
XMLName xml.Name `xml:"People"`
Person []Person `xml:"Person"`
}
func main() {
xmlData := `
<People>
<Person>
<FirstName>Michael</FirstName>
<LastName>Raboy</LastName>
</Person>
<Person>
<FirstName>John</FirstName>
</Person>
<Person>
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>`
var people People
err := xml.Unmarshal([]byte(xmlData), &people)
if err != nil {
fmt.Println("Error:", err)
return
}
var lastNames []string
for _, person := range people.Person {
lastNames = append(lastNames, person.Last)
}
fmt.Println("LastNames:", lastNames)
}
如果你需要更细粒度的控制,可以直接使用xml.Decoder:
package main
import (
"encoding/xml"
"fmt"
"io"
"strings"
)
func main() {
xmlData := `
<People>
<Person>
<FirstName>Michael</FirstName>
<LastName>Raboy</LastName>
</Person>
<Person>
<FirstName>John</FirstName>
</Person>
<Person>
<FirstName>Jane</FirstName>
<LastName>Doe</LastName>
</Person>
</People>`
decoder := xml.NewDecoder(strings.NewReader(xmlData))
var lastNames []string
var inLastName bool
var lastName string
for {
token, err := decoder.Token()
if err == io.EOF {
break
}
if err != nil {
fmt.Println("Error:", err)
return
}
switch se := token.(type) {
case xml.StartElement:
if se.Name.Local == "LastName" {
inLastName = true
} else if se.Name.Local == "Person" {
lastName = "" // 重置为默认值
}
case xml.EndElement:
if se.Name.Local == "Person" {
lastNames = append(lastNames, lastName)
}
case xml.CharData:
if inLastName {
lastName = string(se)
inLastName = false
}
}
}
fmt.Println("LastNames:", lastNames)
}
第一个使用指针的解决方案是最简洁的,它能明确区分标签缺失(nil指针)和空值(指向空字符串的指针)。

