2016-07-29 130 views
0

如何在这种无聊的格式解析XML:解析XML的plist

<key>KEY1</key><string>VALUE OF KEY1</string> 
<key>KEY2</key><string>VALUE OF KEY2</string> 
<key>KEY3</key><integer>42</integer> 
<key>KEY3</key><array> 
    <integer>1</integer> 
    <integer>2</integer> 
</array> 

解析将是非常简单的,如果所有的值将有同一类型 - 例如字符串。但在我的情况下,每个值可能是字符串,数据,整数,布尔值,数组或字典。

这个xml看起来很像json,但不幸的是格式是固定的,我不能改变它。我更喜欢没有任何外部软件包的解决方案。

回答

1

使用encoding/xml提供的低级解析接口,它允许您遍历XML流中的单个标记(例如“开始元素”,“结束元素”等)。

查看encoding/xmlDecoder类型的Token()方法。

0

由于数据结构不好,而且无法修改格式,因此无法使用xml.Unmarshal,因此您可以通过创建新解码器来处理XML元素,然后迭代令牌并使用DecodeElement逐一处理它们。在下面的示例代码中,它将所有内容放在地图中。代码也在github here ...

package main 

import (
     "encoding/xml" 
    "strings" 
    "fmt" 
) 

type PlistArray struct { 
    Integer []int `xml:"integer"` 
} 

const in = "<key>KEY1</key><string>VALUE OF KEY1</string><key>KEY2</key><string>VALUE OF KEY2</string><key>KEY3</key><integer>42</integer><key>KEY3</key><array><integer>1</integer><integer>2</integer></array>" 

func main() { 
    result := map[string]interface{}{} 
    dec := xml.NewDecoder(strings.NewReader(in)) 
    dec.Strict = false 
    var workingKey string 

    for { 
     token, _ := dec.Token() 
     if token == nil { 
      break 
     } 
     switch start := token.(type) { 
     case xml.StartElement: 
      fmt.Printf("startElement = %+v\n", start) 
      switch start.Name.Local { 
      case "key": 
       var k string 
       err := dec.DecodeElement(&k, &start) 
       if err != nil { 
        fmt.Println(err.Error()) 
       } 
       workingKey = k 
      case "string": 
       var s string 
       err := dec.DecodeElement(&s, &start) 
       if err != nil { 
        fmt.Println(err.Error()) 
       } 
       result[workingKey] = s 
       workingKey = "" 
      case "integer": 
       var i int 
       err := dec.DecodeElement(&i, &start) 
       if err != nil { 
        fmt.Println(err.Error()) 
       } 
       result[workingKey] = i 
       workingKey = "" 
      case "array": 
       var ai PlistArray 
       err := dec.DecodeElement(&ai, &start) 
       if err != nil { 
        fmt.Println(err.Error()) 
       } 
       result[workingKey] = ai 
       workingKey = "" 
      default: 
       fmt.Errorf("Unrecognized token") 
      } 
     } 
    } 
    fmt.Printf("%+v", result) 

} 
+0

我也写了类似的东西在此期间。 https://github.com/lofcek/plist – lofcek

+0

太棒了!如果你对这个答案感到满意,请接受它。 – jxstanford