0

I'm trying to create an xml file with the following ordering using the encoding/xml package and i have defined structs for the static subelement and transition subelement, now the problem is i need to to have this in a repeating format so i created another struct to hold slices of both static and transition structs but the result is the static elements all appear before the transition element but i need them to alternate in order. This is the structure i want:

<background>
    //...
    <static>
        <duration></duration>
        <file></file>
    </static>

    <transition>
        <duration>
        <from></from>
        <to></to>
    </transition>

    <static>
        <duration></duration>
        <file></file>
    </static>

    <transition>
        <duration>
        <from></from>
        <to></to>
    </transition>
    //...
</background>

but this is what i get:

<background>
    //...
    <static>
        <duration></duration>
        <file></file>
    </static>
    <static>
        <duration></duration>
        <file></file>
    </static>

    <transition>
        <duration>
        <from></from>
        <to></to>
    </transition>
    <transition>
        <duration>
        <from></from>
        <to></to>
    </transition>
    //...
</background>

Any help as to how i could do it. These are the structs i have created:

type Static struct {
Duration int    `xml:"duration"`
File     string `xml:"file"`
}
type Transition struct {
    Duration float64 `xml:"duration"`
    From     string  `xml:"from"`
    To       string  `xml:"to"`
}
type ST struct {
    Static     []Static     `xml:"static"`
    Transition []Transition `xml:"transition"`
}

type Background struct {
    XMLName   xml.Name  `xml:"background"`
    Comment   string    `xml:",comment"`
    ST
}
The Icon
  • 3
  • 1
  • 3
  • 1
    Just to be clear, do you have any control of the XML structure or does it *have* to be as you specify? Go XML encoding is not designed to preserve order. You might have to write your own encoder. (But I wouldn't be surprised if someone has already done this and put it on Github.) – Andrew W. Phillips May 05 '20 at 01:53
  • If you need an order, you need to model your data structure accordingly. If a `static` and a transition belong to each other, you should wrap them accordingly, in the already existing `ST` for example. to further preserve the order of the process wrapper, I'd suggest adding an attribute to `ST` denoting the order. Then, you can sort the ST elements by that tag on parsing. – Markus W Mahlberg May 05 '20 at 12:09

1 Answers1

0

This

type Static struct {
    XMLName  string `xml:"static"`
    Duration int    `xml:"duration"`
    File     string `xml:"file"`
}

type Transition struct {
    XMLName  string  `xml:"transition"`
    Duration float64 `xml:"duration"`
    From     string  `xml:"from"`
    To       string  `xml:"to"`
}

type Background struct {
    XMLName string `xml:"background"`
    Items   []interface{}
}

bk := Background{
    Items: []interface{}{
        &Static{
            Duration: 11,
            File:     "foo",
        },
        &Transition{
            Duration: 22,
            From:     "aaa",
            To:       "bbb",
        },
        &Static{
            Duration: 33,
            File:     "bar",
        },
        &Transition{
            Duration: 44,
            From:     "xxx",
            To:       "yyy",
        },
    },
}

out, err := xml.Marshal(&bk)

should have your covered (playground).

Note that in order to obtain a properly serialized — in the sense of following one after another in a specified order — list of elements, you have to use a data structure which reflects this; a Go slice suits best in this simple case.

In complicated cases it's possible to make your custom type implement the encoding/xml.Marshaler interface and use a lower-level encoding/xml facilities to encode individual emenets in any order you wish.

kostix
  • 51,517
  • 14
  • 93
  • 176