因此,我尝试解组由Google Go中的其他程序生成的保存文件生成的XML文件。它似乎很好,因为关于这方面的文档相当广泛:http://golang.org/pkg/encoding/xml/#Unmarshal
我仍遇到问题。保存文件中的输出如下:
<location id="id4" x="-736" y="-544">
<committed />
</location>
而不是承诺,位置也可能是紧急的,也可能都不是。这些位置也可以有一个名称和不同的标签,但这些似乎解析得很好。 在我的Go代码中,我使用以下结构:
type Location struct {
Id string `xml:"id,attr"`
Committed bool `xml:"commited"`
Urgent bool `xml:"urgent"`
Labels []Label `xml:"label"`
}
虽然encoding / xml包的Unmarshal函数运行没有错误,并且数据中显示了所示的示例,但是commit和urgent的所有值都是&#34; false&#34;。
为了获得这两个字段的正确值,我应该更改什么?
(使用以下代码完成解组)
xmlFile, err := os.Open("model.xml")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer xmlFile.Close()
b, _ := ioutil.ReadAll(xmlFile)
var xmlScheme uppaal.UppaalXML
err = xml.Unmarshal(b, &xmlScheme)
fmt.Println(err)
答案 0 :(得分:10)
根据this discussion,不支持此行为,您唯一没有看到错误的原因是您在结构定义中错误committed
。如果你正确地写它会得到一个解析错误,因为一个空字符串(一个封闭标签的内容)不是一个布尔值(example on play)。
在链接的golang-nuts线程中,rsc建议使用*struct{}
(指向空结构的指针)并检查该值是否为nil
(example on play):
type Location struct {
Id string `xml:"id,attr"`
Committed *struct{} `xml:"committed"`
Urgent bool `xml:"urgent"`
}
if l.Committed != nil {
// handle not committed
}
答案 1 :(得分:2)
对于简单的布尔值,即当元素存在时value为true,我已经用这种方式解决了它:
示例XML:
<struct>
<hide/>
<data>Value</data>
</struct>
Go中的数据结构:
type XMLValues struct {
Hide BoolIfElementPresent `xml:"hide"`
Data string `xml:"data"`
}
type BoolIfElementPresent struct {
bool
}
func (c *BoolIfElementPresent) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var v string
d.DecodeElement(&v, &start)
*c = BoolIfElementPresent{true}
return nil
}
这样,只要存在<hide/>
并尝试解组,它就会返回true。如果<hide/>
不存在,则不会尝试解组,默认值false
仍保留在结构中。
请注意,每次使用时都必须将布尔值包装在自定义结构中。
d.DecodeElement(&v, &start)
部分似乎没必要,但如果省略该段代码,您将收到错误消息:
xml:(* mypackage.BoolIfElementPresent).UnmarshalXML没有消耗整个元素
编辑:@ShogunPanda的简化版本:
type XMLValues struct {
Hide BoolIfElementPresent `xml:"hide"`
Data string `xml:"data"`
}
type BoolIfElementPresent bool
func (c *BoolIfElementPresent) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
var v string
d.DecodeElement(&v, &start)
*c = true
return nil
}
请注意,您必须使用if xyz == true
来比较布尔值。
答案 2 :(得分:0)
使用一种简单的方法来解决这个空自闭标签或空标签的问题 https://github.com/guregu/null包。
我不喜欢使用小包装的东西,但这个包装为我节省了很多时间
以下是我如何使用此
package main
import (
"encoding/xml"
"fmt"
"github.com/guregu/null"
)
func main() {
type Result struct {
XMLName xml.Name `xml:"Person"`
Name string `xml:"FullName"`
Id null.Int `xml:"Id"`
Height null.Float `xml:"Height"`
}
v := Result{}
data := `
<Person>
<FullName>Grace R. Emlin</FullName>
<Id></Id>
<Height />
</Person>
`
err := xml.Unmarshal([]byte(data), &v)
if err != nil {
fmt.Printf("error: %v", err)
return
}
fmt.Printf("XMLName: %#v\n", v.XMLName)
fmt.Printf("Name: %q\n", v.Name)
if !v.Id.IsZero() {
fmt.Printf("Id: %d\n", v.Id.Int64)
}
}
http://play.golang.org/p/xGKeIUM6NO
完全归功于guregu / null
答案 3 :(得分:0)
我的情况有所不同:我在golang中创建了一个应用,作为从api-a提交到api-b的转发器。 虽然api-a可能会生成一个不关闭的标签,但golang无法读取它,而api-b不会读取它。因此,我创建了两个类,一个是读者,另一个是发帖者。
也许这会给其他人一些启示。
package main
import (
"encoding/xml"
"fmt"
)
type MyDataReader struct {
Name string `xml:"name"`
Lulus *struct{} `xml:"lulus"`
}
type MyDataPoster struct {
Name string `xml:"name"`
Lulus string `xml:"lulus"`
}
func ToPoster(m MyDataReader) MyDataPoster {
res := MyDataPoster{}
res.Name = m.Name
if m.Lulus != nil {
res.Lulus = "1"
}
return res
}
func main() {
xmlString := `<data>
<name>richard</name>
<lulus />
</data>`
m := MyDataReader{}
err := xml.Unmarshal([]byte(xmlString), &m)
fmt.Println(err, m)
mpost := ToPoster(m)
output, errenc := xml.MarshalIndent(mpost, "", " ")
fmt.Println(errenc, string(output))
}
我创建两个类。一种用于检索和解析,另一种用于提交xml。