1 回答
TA贡献1865条经验 获得超7个赞
好了,我们开始吧:
package main
import (
"encoding/json"
"encoding/xml"
"fmt"
"io"
"os"
"strings"
)
type pathVal struct {
path string
val interface{}
}
func encode(dst io.Writer, src []pathVal) error {
enc := xml.NewEncoder(dst)
enc.Indent("", "\t") // for a prettier look
tree := makeTree(src)
err := encodeTree(enc, tree)
if err != nil {
return err
}
return enc.Flush()
}
func encodeTree(enc *xml.Encoder, tree tree) error {
for key, node := range tree {
err := enc.EncodeToken(xml.StartElement{
Name: xml.Name{
Local: key,
},
})
if err != nil {
return err
}
if node.SubTree != nil {
err = encodeTree(enc, node.SubTree)
if err != nil {
return err
}
}
if node.Value != nil {
err = encodeValue(enc, node.Value)
if err != nil {
return err
}
}
err = enc.EncodeToken(xml.EndElement{
Name: xml.Name{
Local: key,
},
})
if err != nil {
return err
}
}
return nil
}
func encodeValue(enc *xml.Encoder, val interface{}) error {
return enc.EncodeToken(xml.CharData(fmt.Sprintf("%v", val)))
}
type tree map[string]*treeNode
type treeNode struct {
SubTree tree
Value interface{}
}
func makeTree(src []pathVal) tree {
root := make(tree)
for _, elem := range src {
comps := strings.Split(elem.path, "/")
comps, last := comps[:len(comps)-1], comps[len(comps)-1]
subTree := root
for _, comp := range comps {
node, exists := subTree[comp]
if !exists {
newTree := make(tree)
subTree[comp] = &treeNode{
SubTree: newTree,
}
subTree = newTree
continue
}
if node.SubTree == nil {
node.SubTree = make(tree)
}
subTree = node.SubTree
}
if node, exists := subTree[last]; exists {
node.Value = elem.val
} else {
subTree[last] = &treeNode{
Value: elem.val,
}
}
}
return root
}
// "Table 1"
var data1 = []pathVal{
pathVal{
path: "SalesPlan/SalesPlanData/Year",
val: 2021,
},
pathVal{
path: "SalesPlan/SalesPlanData/Month",
val: "July",
},
pathVal{
path: "SalesPlan/SalesPlanData/id",
val: 123,
},
pathVal{
path: "SalesPlan/SalesPlanSpot/Spots/City",
val: "NY",
},
}
// "Table 2"
var data2 = []pathVal{
pathVal{
path: "mydoc/Country/City/Street/House",
val: 14,
},
pathVal{
path: "mydoc/Country/City/Street/House",
val: 15,
},
pathVal{
path: "mydoc/Country/City/Street",
val: "Maddison",
},
pathVal{
path: "mydoc/Country/City",
val: "NY",
},
}
func main() {
out, _ := json.MarshalIndent(makeTree(data1), "", "\t")
fmt.Printf("%s\n", out)
fmt.Println(encode(os.Stdout, data1))
out, _ = json.MarshalIndent(makeTree(data2), "", "\t")
fmt.Printf("%s\n", out)
fmt.Println(encode(os.Stdout, data2))
}
(游乐场。
在示例数据(嵌入到示例中的两个“表”)上,我们得到data1data2
<SalesPlan>
<SalesPlanData>
<id>123</id>
<Year>2021</Year>
<Month>July</Month>
</SalesPlanData>
<SalesPlanSpot>
<Spots>
<City>NY</City>
</Spots>
</SalesPlanSpot>
</SalesPlan>
和
<mydoc>
<Country>
<City>
<Street>
<House>15</House>Maddison
</Street>NY
</City>
</Country>
</mydoc>
分别。
注意那些“看起来很奇怪”的情况,“麦迪逊”放在元素里面,“NY”放在元素里面;还要注意 .
我不知道如何处理这两个问题(如果它们是问题),因为你的问题没有明确说明任何关于处理它们的偏好。<Street><City><House>14</House>
我会说处理多个叶元素是相当容易的 - 只需确保不覆盖 中,而是提供收集多个值(可能收集在切片中)并在 中说明这一点。
如何处理一个潜在的XML元素,它应该同时包含一个“普通”值和一个嵌套元素,这实际上是一个悬而未决的问题:我所展示的是100%符合标准的XML,但最终结果可能会让人觉得不自然,因为人们通常期望在人类可读的XML文档中看到的内容。ValuemakeTreeencodeTree
不过,让我把这些作为读者的练习。
请注意,该解决方案仅使用包来“转储”从输入数据创建的树;它不需要算法工作。
- 1 回答
- 0 关注
- 107 浏览
添加回答
举报