duancong7573 2019-05-01 08:27
浏览 74

XML编组生成无根XML

I am working on a rest api in golang and was able to marshal data to xml and json. The struct i have has multiple records but xml marshalling does not add a root for these records. The XML is therefore not valid.

I saw some questions that were solved by setting XMLName but i think that will only change my customer type to something else.

What i still might try is to add around the xml marshalled byte and concatinate. But I am not sure if that is how i have to do it.

EDIT: Apparently XML is marshalled correctly since I am marshalling a struct with multiple objects inside. Marshalling then creates separate XML documents per object. Question then is what the rest clients can work with to consume data or is it bad practice to send multiple xml documents in a rest responce? Browsers couldn't display the resulting xml.

To return a single XML Document I would have to put the list in a struct, which then can be marshalled. I am not sure how I can initialise the struct with sqlx in such a way.

Adding following code does not work:

type custs struct {
    List []Customer `xml:"Customer"`
}

custs customers.[]Customer =  []Customer{}

Code:

package main

import (
    "database/sql"
    json "encoding/json"
    "encoding/xml"
    "fmt"
    "net/http"
)

type Customer struct {
    CustomerID int            `db:"CustomerId"`
    FirstName  string         `db:"FirstName"`
    LastName   string         `db:"LastName"`
    Company    sql.NullString `db:"Company"`
}

func tstSQLite(w http.ResponseWriter, r *http.Request) {

    contentType := r.Header.Get("Content-type")

    Customers := []Customer{}

    var err error

    fmt.Print("executing query")
    err = chinookdb.Select(&Customers, "SELECT CustomerId, FirstName,LastName, Company FROM customers")

    if err != nil {
        panic(err)
    }

    for _, g := range Customers {
        fmt.Println("FirstName:", g.FirstName, "LastName:", g.LastName)
    }

    var data []byte

    if contentType == "application/xml" {
        data, err = xml.Marshal(Customers)
    }

    if contentType == "application/json" || contentType != "application/xml" {
        data, err = json.Marshal(Customers)
    }


    w.Header().Set("Content-Type", "application/json")
    w.Write(data)
}

What i get is following xml:

   <Customer>
      <CustomerID>1</CustomerID>
      <FirstName>Luís</FirstName>
      <LastName>Gonçalves</LastName>
      <Company>
         <String>Embraer - Empresa Brasileira de Aeronáutica S.A.</String>
         <Valid>true</Valid>
      </Company>
   </Customer>
   <Customer>
      <CustomerID>2</CustomerID>
      <FirstName>Leonie</FirstName>
      <LastName>Köhler</LastName>
      <Company>
         <String />
         <Valid>false</Valid>
      </Company>
   </Customer>
   <Customer>
      <CustomerID>3</CustomerID>
      <FirstName>François</FirstName>
      <LastName>Tremblay</LastName>
      <Company>
         <String />
         <Valid>false</Valid>
      </Company>
   </Customer>

but i think it should be like this:

<Customers>
   <Customer>
      <CustomerID>1</CustomerID>
      <FirstName>Luís</FirstName>
      <LastName>Gonçalves</LastName>
      <Company>
         <String>Embraer - Empresa Brasileira de Aeronáutica S.A.</String>
         <Valid>true</Valid>
      </Company>
   </Customer>
   <Customer>
      <CustomerID>2</CustomerID>
      <FirstName>Leonie</FirstName>
      <LastName>Köhler</LastName>
      <Company>
         <String />
         <Valid>false</Valid>
      </Company>
   </Customer>
   <Customer>
      <CustomerID>3</CustomerID>
      <FirstName>François</FirstName>
      <LastName>Tremblay</LastName>
      <Company>
         <String />
         <Valid>false</Valid>
      </Company>
   </Customer>
</Customers>

The marshalled json looks correct since the customers are in brackets:

[
   {
      "CustomerID":1,
      "FirstName":"Luís",
      "LastName":"Gonçalves",
      "Company":{
         "String":"Embraer - Empresa Brasileira de Aeronáutica S.A.",
         "Valid":true
      }
   },
   {
      "CustomerID":2,
      "FirstName":"Leonie",
      "LastName":"Köhler",
      "Company":{
         "String":"",
         "Valid":false
      }
   }
]
  • 写回答

1条回答 默认 最新

  • duanbohan2015 2019-05-01 09:36
    关注

    You must have to wrap this customer collection inside another struct as

    package main
    
    import (
        "encoding/xml"
        "fmt"
        "os"
    )
    
    func main() {
    
        type Customer struct {
            XMLName   xml.Name `xml:"Customer"`
            CustomerID int            `db:"CustomerId"`
            FirstName  string         `db:"FirstName"`
            LastName   string         `db:"LastName"`
            Company    string `db:"Company"`
        }
    
        type Customers struct {
            List []Customer
        }
    
        csts := []Customer{
            Customer{CustomerID: 1, FirstName: "John", LastName: "Doe", Company: "Demo Company"},
            Customer{CustomerID: 2, FirstName: "John2", LastName: "Doe2", Company: "Demo Company2"},
        }
    
    
        res := Customers {
            List: csts,
        }
    
        output, err := xml.MarshalIndent(res, "  ", "    ")
        if err != nil {
            fmt.Printf("error: %v
    ", err)
        }
    
        os.Stdout.Write(output)
    }
    

    Default it could take the name of construct. You can also customized the name using xml.Name type.

    评论

报告相同问题?

悬赏问题

  • ¥15 django项目运行报编码错误
  • ¥15 请问这个是什么意思?
  • ¥15 STM32驱动继电器
  • ¥15 Windows server update services
  • ¥15 关于#c语言#的问题:我现在在做一个墨水屏设计,2.9英寸的小屏怎么换4.2英寸大屏
  • ¥15 模糊pid与pid仿真结果几乎一样
  • ¥15 java的GUI的运用
  • ¥15 我想付费需要AKM公司DSP开发资料及相关开发。
  • ¥15 怎么配置广告联盟瀑布流
  • ¥15 Rstudio 保存代码闪退