2016-07-29 27 views
0

Wie xml in solchen dummen Format analysieren:Parsing plist xml

<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> 

Parsing wäre sehr einfach, wenn alle Werte gleichen Typen haben würden - zum Beispiel Saiten. Aber in meinem Fall könnte jeder Wert string, data, integer, boolean, array oder dict sein.

Diese XML-Datei sieht fast wie json aus, aber leider ist das Format fest, und ich kann es nicht ändern. Und ich würde eine Lösung ohne externe Pakete bevorzugen.

Antwort

1

Verwenden Sie eine untergeordnete Analysierungsschnittstelle, die von encoding/xml bereitgestellt wird, mit der Sie über einzelne Token im XML-Stream (wie "Startelement", "Endelement" usw.) iterieren können.

Siehe die Token() Methode der encoding/xmlDecoder Art.

0

Da die Daten nicht gut strukturiert sind und Sie das Format nicht ändern können, können Sie nicht xml.Unmarshal verwenden, also können Sie die XML-Elemente durch Erstellen eines neuen Decoders bearbeiten, dann über die Token iterieren und verwenden DecodeElement, um sie einzeln zu verarbeiten. In meinem folgenden Beispielcode wird alles in eine Karte eingefügt. Der Code ist auch auf 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

Ich schreibe auch etwas ähnliches während einer Zwischenzeit. https://github.com/lofcek/plist – lofcek

+0

großartig! Wenn Sie mit dieser Antwort zufrieden sind, akzeptieren Sie sie bitte. – jxstanford