Gox语言中集成了Go语言的第三方库etree,因此已经内置XML文档的处理功能。etree更详细的文档可参考这里。
我们直接来看下面这个例子:
etree = github_beevik_etree
reshapeXMLX = fn(xmlA) {
treeT = etree.NewDocument()
if treeT == nil {
return tk.GenerateErrorStringF("create XML tree failed")
}
errT = treeT.ReadFromString(xmlA)
if errT != nil {
return tk.GenerateErrorStringF("invalid XML: %v", errT)
}
treeT.Indent(2)
outputT, errT = treeT.WriteToString()
if errT != nil {
return tk.GenerateErrorStringF("failed to reshape XML: %v", errT)
}
return outputT
}
flattenXML = fn(xmlA, nodeA) {
treeT = etree.NewDocument()
if treeT == nil {
return tk.GenerateErrorStringF("create XML tree failed")
}
errT = treeT.ReadFromString(xmlA)
if errT != nil {
return tk.GenerateErrorStringF("invalid XML: %v", errT)
}
rootNodeT = treeT.FindElement("//" + nodeA)
if rootNodeT == nil {
return tk.GenerateErrorStringF("node not found: %v", nodeA)
}
nodesT = rootNodeT.ChildElements()
bufT = new(strings.Builder)
for i, v = range nodesT {
if i > 0 {
bufT.WriteString("\n")
}
bufT.WriteString(tk.Spr("%v: %v", v.Tag, v.Text()))
}
return bufT.String()
}
getMSSFromXML = fn(xmlA, nodeA) {
treeT = etree.NewDocument()
if treeT == nil {
return nil, tk.Errf("create XML tree failed")
}
errT = treeT.ReadFromString(xmlA)
if errT != nil {
return nil, tk.Errf("invalid XML: %v", errT)
}
rootNodeT = treeT.FindElement("//" + nodeA)
if rootNodeT == nil {
return nil, tk.Errf("node not found: %v", nodeA)
}
nodesT = rootNodeT.ChildElements()
mapT = make(map[string]string, len(nodesT))
for _, jv = range nodesT {
mapT[jv.Tag] = jv.Text()
}
return mapT, nil
}
getMSSArrayFromXML = fn(xmlA, nodeA) {
treeT = etree.NewDocument()
if treeT == nil {
return nil, tk.Errf("create XML tree failed")
}
errT = treeT.ReadFromString(xmlA)
if errT != nil {
return nil, tk.Errf("invalid XML: %v", errT)
}
rootNodeT = treeT.FindElement("//" + nodeA)
if rootNodeT == nil {
return nil, tk.Errf("node not found: %v", nodeA)
}
nodesT = rootNodeT.ChildElements()
aryT = make([]map[string]string, 0)
for _, v = range nodesT {
internalNodesT = v.ChildElements()
mapT = make(map[string]string, len(internalNodesT))
for _, jv = range internalNodesT {
mapT[jv.Tag] = jv.Text()
}
aryT = append(aryT, mapT)
}
return aryT, nil
}
xmlT = `<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<ZvendorNameFuzquery xmlns="urn:sap-com:document:sap:soap:functions:mc-style">
<Iname xmlns="">北京大学</Iname>
<Iresv1 xmlns="">简称:北大</Iresv1>
<Iresv2 xmlns=""></Iresv2>
<Tname xmlns="">
</Tname>
</ZvendorNameFuzquery>
</Body>
</Envelope>`
resultT = reshapeXMLX(xmlT)
println(resultT)
println("\n-----\n")
resultT = flattenXML(xmlT, "ZvendorNameFuzquery")
println(resultT)
println("\n-----\n")
resultT = getMSSFromXML(xmlT, "ZvendorNameFuzquery")
println(resultT)
println("\n-----\n")
xmlT = `<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<ZvendorNameFuzquery xmlns="urn:sap-com:document:sap:soap:functions:mc-style">
<item>
<Iname xmlns="">北京大学</Iname>
<Iresv1 xmlns="">简称:北大</Iresv1>
<Iresv2 xmlns=""></Iresv2>
<Tname xmlns="">
</Tname>
</item>
<item>
<Iname xmlns="">清华大学</Iname>
<Iresv1 xmlns=""></Iresv1>
<Iresv2 xmlns="">地址</Iresv2>
<Tname xmlns="">
</Tname>
</item>
</ZvendorNameFuzquery>
</Body>
</Envelope>`
resultT = getMSSArrayFromXML(xmlT, "ZvendorNameFuzquery")
println(resultT)
首先,我们将使用github.com/beevik/etree包,这是一个Go语言中非常优秀的处理XML的第三方包。虽然可以直接按Gox约定的github_beevik_etree来使用该包,但为了代码简洁,在一开始我们给它定义了一个简称变量etree。
然后用etree.NewDocument()函数创建一个XML文档对象后,就可以进行各种处理了。
代码中的reshapeXMLX函数是将XML字符串进行重新格式化的函数;
flattenXML函数则是将XML中指定节点下的所有子节点提取出来生成一个数组(注意只能提取一级);
getMSSFromXML函数则是将XML中指定节点下的内容提取成为map[string]string格式的映射;
getMSSArrayFromXML函数则是用于提取一个数组,形式为[]map[string]string。
代码的执行结果如下:
λ gox scripts\xml.gox
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<ZvendorNameFuzquery xmlns="urn:sap-com:document:sap:soap:functions:mc-style">
<Iname xmlns="">北京大学</Iname>
<Iresv1 xmlns="">简称:北大</Iresv1>
<Iresv2 xmlns=""/>
<Tname xmlns=""/>
</ZvendorNameFuzquery>
</Body>
</Envelope>
-----
0xc000068c10: 北京大学
0xc000068c70: 简称:北大
0xc000068cd0:
0xc000068d30:
-----
[map[Iname:北京大学 Iresv1:简称:北大 Iresv2: Tname:
] <nil>]
-----
[[map[Iname:北京大学 Iresv1:简称:北大 Iresv2: Tname:
] map[Iname:清华大学 Iresv1: Iresv2:地址 Tname:
]] <nil>]
可以看到结果都符合预期。
至于如何生成XML文档、添加各种节点等,请参考etree的详细文档。
* 注:由于0.988版本后,为了减少不必要的文件体积,Gox已经放弃了其他脚本引擎,仅支持Qlang引擎,因此下面的内容已经无效,仅留作对旧版本的参考。
下面是Anko引擎版的代码:
tk = import("tk")
etree = import("etree")
strings = import("strings")
func reshapeXMLX(xmlA) {
treeT = etree.NewDocument()
if treeT == nil {
return tk.GenerateErrorStringF("create XML tree failed")
}
errT = treeT.ReadFromString(xmlA)
if errT != nil {
return tk.GenerateErrorStringF("invalid XML: %v", errT)
}
treeT.Indent(2)
outputT, errT = treeT.WriteToString()
if errT != nil {
return tk.GenerateErrorStringF("failed to reshape XML: %v", errT)
}
return outputT
}
func flattenXML(xmlA, nodeA) {
treeT = etree.NewDocument()
if treeT == nil {
return tk.GenerateErrorStringF("create XML tree failed")
}
errT = treeT.ReadFromString(xmlA)
if errT != nil {
return tk.GenerateErrorStringF("invalid XML: %v", errT)
}
rootNodeT = treeT.FindElement("//" + nodeA)
if rootNodeT == nil {
return tk.GenerateErrorStringF("node not found: %v", nodeA)
}
nodesT = rootNodeT.ChildElements()
bufT = make(strings.Builder)
i = 0
for v in nodesT {
if i > 0 {
bufT.WriteString("\n")
}
bufT.WriteString(tk.Spr("%v: %v", v.Tag, v.Text()))
i++
}
return bufT.String()
}
func getMSSFromXML(xmlA, nodeA) {
treeT = etree.NewDocument()
if treeT == nil {
return nil, tk.Errf("create XML tree failed")
}
errT = treeT.ReadFromString(xmlA)
if errT != nil {
return nil, tk.Errf("invalid XML: %v", errT)
}
rootNodeT = treeT.FindElement("//" + nodeA)
if rootNodeT == nil {
return nil, tk.Errf("node not found: %v", nodeA)
}
nodesT = rootNodeT.ChildElements()
mapT = make(map[string]string, len(nodesT))
for jv in nodesT {
mapT[jv.Tag] = jv.Text()
}
return mapT, nil
}
func getMSSArrayFromXML(xmlA, nodeA) {
treeT = etree.NewDocument()
if treeT == nil {
return nil, tk.Errf("create XML tree failed")
}
errT = treeT.ReadFromString(xmlA)
if errT != nil {
return nil, tk.Errf("invalid XML: %v", errT)
}
rootNodeT = treeT.FindElement("//" + nodeA)
if rootNodeT == nil {
return nil, tk.Errf("node not found: %v", nodeA)
}
nodesT = rootNodeT.ChildElements()
aryT = make([]map[string]string, 0)
for v in nodesT {
internalNodesT = v.ChildElements()
mapT = make(map[string]string, len(internalNodesT))
for jv in internalNodesT {
mapT[jv.Tag] = jv.Text()
}
aryT += mapT
}
return aryT, nil
}
xmlT = `<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<ZvendorNameFuzquery xmlns="urn:sap-com:document:sap:soap:functions:mc-style">
<Iname xmlns="">北京大学</Iname>
<Iresv1 xmlns="">简称:北大</Iresv1>
<Iresv2 xmlns=""></Iresv2>
<Tname xmlns="">
</Tname>
</ZvendorNameFuzquery>
</Body>
</Envelope>`
resultT = reshapeXMLX(xmlT)
println(resultT)
println("\n-----\n")
resultT = flattenXML(xmlT, "ZvendorNameFuzquery")
println(resultT)
println("\n-----\n")
resultT = getMSSFromXML(xmlT, "ZvendorNameFuzquery")
println(resultT)
println("\n-----\n")
xmlT = `<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<ZvendorNameFuzquery xmlns="urn:sap-com:document:sap:soap:functions:mc-style">
<item>
<Iname xmlns="">北京大学</Iname>
<Iresv1 xmlns="">简称:北大</Iresv1>
<Iresv2 xmlns=""></Iresv2>
<Tname xmlns="">
</Tname>
</item>
<item>
<Iname xmlns="">清华大学</Iname>
<Iresv1 xmlns=""></Iresv1>
<Iresv2 xmlns="">地址</Iresv2>
<Tname xmlns="">
</Tname>
</item>
</ZvendorNameFuzquery>
</Body>
</Envelope>`
resultT = getMSSArrayFromXML(xmlT, "ZvendorNameFuzquery")
println(resultT)
代码的执行结果如下:
λ gox scripts\xml.gox
<Envelope xmlns="http://schemas.xmlsoap.org/soap/envelope/">
<Body>
<ZvendorNameFuzquery xmlns="urn:sap-com:document:sap:soap:functions:mc-style">
<Iname xmlns="">北京大学</Iname>
<Iresv1 xmlns="">简称:北大</Iresv1>
<Iresv2 xmlns=""/>
<Tname xmlns=""/>
</ZvendorNameFuzquery>
</Body>
</Envelope>
-----
Iname: 北京大学
Iresv1: 简称:北大
Iresv2:
Tname:
-----
[map[Iname:北京大学 Iresv1:简称:北大 Iresv2: Tname:
] <nil>]
-----
[[map[Iname:北京大学 Iresv1:简称:北大 Iresv2: Tname:
] map[Iname:清华大学 Iresv1: Iresv2:地址 Tname:
]] <nil>]