12 votes

Go XML Marshalling et l'élément racine

En Go, vous pouvez marshaller un struct en XML, par exemple :

package main

import (
    "encoding/xml"
    "fmt"
    )

type person struct {
    Name string
    Starsign string
}

func main() {
    p := &person{"John Smith", "Capricorn"}
    b,_ := xml.MarshalIndent(p,"","   ")
    fmt.Println(string(b))
}

produit des résultats :

<person>
   <Name>John Smith</Name>
   <Starsign>Capricorn</Starsign>
</person>

Le problème est que le type de personne est un "p" minuscule parce que je veux qu'il soit privé au paquet. Mais je préférerais que l'élément XML soit en majuscules : <Person> . Les champs de la structure peuvent être marqués par d'autres noms en utilisant des balises (par exemple `xml : "name"`) sur les champs de la structure, mais cela ne semble pas être une option pour le type de structure.

J'ai trouvé une solution de contournement en utilisant des modèles, mais il serait bon de connaître une meilleure réponse.

14voto

Stephen Weinberg Points 12682

Selon la encodage/xml.Marshal la documentation :

Le nom des éléments XML est choisi, par ordre de préférence :

  • la balise sur le champ XMLName, si les données sont une struct
  • la valeur du champ XMLName de type xml.Name
  • l'étiquette du champ struct utilisé pour obtenir les données
  • le nom du champ struct utilisé pour obtenir les données
  • le nom du type marshallé

Vous pouvez utiliser une balise sur le champ XMLName de la structure pour remplacer le nom de la balise XML de la structure personne. Afin d'éviter de le mettre dans votre structure personne réelle, vous pouvez créer une structure anonyme qui incorpore la structure personne que vous marshalisez.

package main

import (
    "encoding/xml"
    "fmt"
)

type person struct {
    Name        string
    Starsign    string
}

func marshalPerson(p person) ([]byte, error) {
    tmp := struct {
        person
        XMLName struct{}    `xml:"Person"`
    }{person: p}

    return xml.MarshalIndent(tmp, "", "   ")
}

func main() {
    p := person{"John Smith", "Capricorn"}
    b, _ := marshalPerson(p)
    fmt.Println(string(b))
}

5voto

Matjam Points 114

Cela fonctionne également, mais je ne pense pas que ce soit particulièrement joli.

Cependant, cette solution a fonctionné pour moi de manière beaucoup plus directe que l'autre solution acceptée il y a 5 ans.

package main

import (
    "encoding/xml"
    "fmt"
    )

type person struct {
    XMLName xml.Name
    Name string
    Starsign string
}

func main() {
    p := &person{xml.Name{Local: "Person"}, "John Smith", "Capricorn"}
    b,_ := xml.MarshalIndent(p,"","   ")
    fmt.Println(string(b))
}

4voto

Sam Watkins Points 1299

Je pense que le plus simple est d'ajouter un champ fictif à la structure de la personne avec la balise XML.

A struct{} n'utilise pas d'espace de stockage, j'ai vérifié avec unsafe.Sizeof() .

package main

import (
    "encoding/xml"
    "fmt"
)

type person struct {
    Name     string
    Starsign string
    XMLName  struct{} `xml:"Person"`
}

func main() {
    p := &person{Name: "John Smith", Starsign: "Capricorn"}
    b, _ := xml.MarshalIndent(p, "", "   ")
    fmt.Println(string(b))
}

<a href="https://go.dev/play/p/oRLLVo33bG2" rel="nofollow noreferrer">go playground</a>

Si vous préférez initialiser la structure sans utiliser les noms de champs, il est nécessaire d'ajouter un élément pour initialiser la structure vide, comme ceci :

p := &person{"John Smith", "Capricorn", struct{}{}}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X