2016-07-29 91 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