You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
package main
import (
"bytes""encoding/xml""fmt""io"
)
varxmlstring=` <Person> <FullName>Grace R. Emlin</FullName> <!-- this is the comment for Company --> <Company>Example Inc.</Company> <City>Hanga Roa</City> <State>Easter Island</State> </Person> `funcmain() {
decoder:=xml.NewDecoder(bytes.NewReader([]byte(xmlstring)))
for {
t, err:=decoder.Token()
iferr!=nil {
iferr==io.EOF {
fmt.Printf("Parse XML finished!\n")
} else {
fmt.Printf("Failed to Parse XML with the error of %v\n", err)
}
break
}
t=xml.CopyToken(t)
switcht:=t.(type) {
case xml.StartElement:
fmt.Printf("StartElement: <%v>\n", t.Name.Local)
case xml.EndElement:
fmt.Printf("EndElement: <%v>\n", t.Name.Local)
case xml.CharData:
fmt.Printf("CharData: %v\n", string(t))
case xml.Comment:
fmt.Printf("Comment: <!--%v-->\n", string(t))
}
}
}
前言
由于 oVirt 的 API 接口的数据格式是 XML,所以在实现 oVirt Go SDK 时,需要对接口响应 XML 数据进行解析。接口的XML 数据格式非常标准,所以非常适合用
xml:"***"
struct tag 来实现 Unmarshal 操作。Go 自带的 encoding/xml 库提供了非常便捷的 XML Marshal 和 Unmarshal 功能,只需在 struct 中定义 tag 即可。但后来在完善 SDK 的过程中,我发现了 struct tag 方案的一些局限性,于是决定自行实现 SDK 中的 XML-Unmarshal。
encoding/xml Unmarshal
的局限无法判断 XML 与 struct 对应
encoding/xml.Unmarshal
方法返回一个error
,但当 XML 数据与传入的 struct 不对应时,返回的error
仍然是nil
,以下面为例:Playground上面的例子中,Customers 和 Customer 中的 tag 定义与 XML 中的 element 定义完全不一样,但
xml.Unmarshal
函数不返回任何错误,custs 仍然是零值。这种情况导致,当 XML 数据可能是两种完全不同的格式(即对应两个完全不同的 struct)时,无法判断到底是哪个。我尝试了一个解决方案,但很丑陋,而且还不能保证完全正确,即:
struct 的属性必须 exported
由于
encoding/xml
使用reflect
反射来实现 Unmarshal,所以要求 struct 的属性都必须是 exported 的,比如:对于 XML 中的标签<name>
而言,对应的属性一般定义为Name
。在我实现 oVirt Go SDK 时,就出现了问题:name
作为属性名,访问和设值则使用 getter/setter 函数所以这就导致 unexported 的属性是无法使用
xml.Unmarshal
的;即便可以继续使用Name
作为属性名,但getter 函数只能用GetName
,但这样不符合 Go 的编码规范。关于 Go XML Stream API
对于 Go 中的 XML Stream API,官方和网上的资料很少,因为绝大多数的 XML Unmarshal 都是直接使用上面提到的 struct tag 方式,找不到可以直接参考的例子。
通过查看
encoding/xml
中的marshal.go
、read.go
和xml.go
三个源文件,找到了一些基础概念和简单操作。xml.Decoder
代表了一个XML的 Stream,xml.Decoder.Token()
函数即返回 XML Stream 中的下一个元素,返回值是xml.Token
xml.Token
代表了 XML 中每一项元素,会被解析成xml.StartElement
、xml.EndElement
、xml.CharData
、xml.Comment
、xml.ProcInst
、xml.Directive
中的一种xml.CharData
,即xml.Token
中的一种下面使用一段代码来描述 Go XML Stream API 的简单用法。playgroud
输出是:
总结
本文简单介绍了我要定制实现 XML Unmarshal 的原因,和 Go XML Stream API 的一些基础,后续在我完成 oVirt Go SDK 的 XML Unmarshal 重构后,会将更详细的实现细节补充上来。
The text was updated successfully, but these errors were encountered: