2016-10-24 21 views
2

我有此格式的XML,從數據庫XML與Golang解析(實體濫用屬性)

<table name="table1"> 
    <row> 
     <col name="col1">value</col> 
     <col name="col2">value</col> 
     <col name="col3">value</col> 
    </row> 
    ... 
</table> 
<table name="table2"> 
    <row> 
     <col name="col1">value</col> 
     <col name="col2">value</col> 
     <col name="col3">value</col> 
     <col name="col4">value</col> 
    </row> 
    ... 
</table> 

我想在圍棋與xml.Decode()功能解析這個轉儲來,但我可以」處理這樣的XML。 我試圖匹配一些在Golang中搜索到的使用googling XML解析的例子,但沒有適合這種格式(全部實體都有name屬性)。

更新

感謝您的答案!我想要實現的是:假設我有一個名爲「users」的表和一個名爲「categories」的表,我想創建從該XML開始的多個UserCategory對象。 根據你的第一個答案,我可以很容易地使用解析的對象Table,然後創建我自己的對象,但我想知道我是否可以跳過該對象,直接解碼我的對象。

回答

1

我不知道你要處理什麼樣的問題有,但你的XML實際上看起來像XML值的流,所以你應該把它作爲這樣解碼:

type Table struct { 
    Name string `xml:"name,attr"` 
    Rows []Row `xml:"row"` 
} 

type Row struct { 
    Cols []Col `xml:"col"` 
} 

type Col struct { 
    Name string `xml:"name,attr"` 
    Value string `xml:",chardata"` 
} 

//... 

var err error 
dec := xml.NewDecoder(bytes.NewReader(b)) 
for err == nil { 
    t := Table{} 
    err = dec.Decode(&t) 
    fmt.Printf("%v, %+v\n", err, t) 
} 

遊樂場:https://play.golang.org/p/w4PqLv-Uc0


編輯:如果你想這樣的XML直接解碼成適當的結構,就需要一個更復雜的機械。以下是一個用戶示例:

type User struct { 
    ID  int 
    Name string 
    Surname string 
} 

func (u *User) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error { 
    var err error 

    type col struct { 
     Name string `xml:"name,attr"` 
     Value string `xml:",chardata"` 
    } 

    for { 
     c := col{} 
     err = d.Decode(&c) 
     if err != nil { 
      if err == io.EOF { 
       break 
      } 

      return err 
     } 
     switch c.Name { 
     case "id": 
      u.ID, err = strconv.Atoi(c.Value) 
      if err != nil { 
       return err 
      } 
     case "name": 
      u.Name = c.Value 
      continue 
     case "surname": 
      u.Surname = c.Value 
     } 
    } 

    return nil 
} 

type UserTable struct { 
    Users []User `xml:"row"` 
} 

遊樂場:https://play.golang.org/p/Hqta3Ngjo3

+0

感謝。我的第一個問題還不夠清楚,所以我編輯了一些更多細節 –

+0

@LeonardoRossi請參閱編輯。 –

1

xml.Unmarshal()函數的文檔描述了XML文檔和結構之間的映射是如何工作的(由doc of json.Marshal()補充)。如果你不熟悉結構標籤,請看看這個答案:What are the use(s) for tags in Go?

首先你需要建模XML文檔。請注意,如果您沒有包裝XML元素,那麼這不是1個XML文檔,而是多個,比如您的情況。您有多個<table>文檔。

你可以這樣他們型號:

type Col struct { 
    Name string `xml:"name,attr"` 
    Value string `xml:",chardata"` 
} 

type Row struct { 
    Cols []Col `xml:"col"` 
} 

type Table struct { 
    Name string `xml:"name,attr"` 
    Rows []Row `xml:"row"` 
} 

而且因爲你有多個<table>元素,最簡單的就是創建一個xml.Decoder(),並用Decoder.Decode()通話單獨分析每個(Decoder.Decode()將嘗試從解析1個XML文檔其源讀者)。

這是它是如何做:

d := xml.NewDecoder(strings.NewReader(data)) 
for { 
    var table Table 
    if err := d.Decode(&table); err != nil { 
     fmt.Println(err) 
     break 
    } 
    fmt.Printf("%+v\n", table) 
} 

當有源string沒有更多的數據,Decoder.Decode()將報告io.EOF。具有以下data串運行上面的鱈魚:

const data = `<table name="table1"> 
    <row> 
     <col name="col1">value1</col> 
     <col name="col2">value2</col> 
     <col name="col3">value3</col> 
    </row> 
    <row> 
     <col name="col1">value4</col> 
     <col name="col2">value5</col> 
     <col name="col3">value6</col> 
    </row> 
</table> 
<table name="table2"> 
    <row> 
     <col name="col1">value7</col> 
     <col name="col2">value8</col> 
     <col name="col3">value9</col> 
     <col name="col4">valueA</col> 
    </row> 
</table>` 

輸出是:

{Name:table1 Rows:[{Cols:[{Name:col1 Value:value1} {Name:col2 Value:value2} {Name:col3 Value:value3}]} {Cols:[{Name:col1 Value:value4} {Name:col2 Value:value5} {Name:col3 Value:value6}]}]} 
{Name:table2 Rows:[{Cols:[{Name:col1 Value:value7} {Name:col2 Value:value8} {Name:col3 Value:value9} {Name:col4 Value:valueA}]}]} 
EOF 

嘗試它的Go Playground

1

要根據名稱將每個字段解組爲不同類型,您需要獲取每個開始元素標記,檢查名稱,然後根據需要進行解碼。類似如下(其中getName是返回name屬性的函數;參見操場鏈接最小的工作實施例):

d := xml.NewDecoder(…) 
for { 
    tok, err := d.Token() 
    if err != nil { 
     log.Fatal(err) 
    } 

    start, ok := tok.(xml.StartElement) 
    if !ok { 
     // This is chardata or some other token. 
     // If it's bad XML, it will be caught on the next call to Token() 
     continue 
    } 
    switch getName(start) { 
    case "user": 
     u := &User{} 
     err = d.DecodeElement(u, &start) 
     if err != nil { 
      log.Fatal(err) 
     } 
     // Do whatever you want to do with your struct here. 
     fmt.Printf("Decoded a user: %+v\n", u) 
    case "category": 
     u := &Category{} 
     err = d.DecodeElement(u, &start) 
     if err != nil { 
      log.Fatal(err) 
     } 
     fmt.Printf("Decoded a category: %+v\n", u) 
    default: 
     // If the name is unrecognized, skip the rest of the element. 
     // We could also return an error 
     d.Skip() 
    } 
} 

https://play.golang.org/p/l7Vmj_8Igp