Unmarshaling XML: используйте другой тип цели в зависимости от значения атрибута - PullRequest
1 голос
/ 17 июня 2019

Я хочу использовать другой тип для демонтажа содержимого XML дочернего узла на основе атрибута имени его родителя.

В следующем примере у меня есть 2 дочерних узла с атрибутами «яблоко» и «персик»,Я хотел бы использовать тип Apple, когда атрибут "apple" и Peach, когда "peach".В основном Apple и Peach имеют очень разные структуры, так что это сценарий.Как мне это сделать или какой будет предложенный подход?

Здесь находится детская площадка с базовой настройкой проблемы.

<element>
    <node name="apple">
        <apple>
            <color>red<color>
        </apple>
    </node>
    <node name="peach"> 
        <peach>
            <size>medium</size>
        </peach>
    </node>
</element>
var x = `...` // xml
type Element struct {
    Nodes []struct{
        Name string `xml:"name,attr"`
    } `xml:"node"`
    Apple Apple
    Peach Peach
}
type Apple struct { // use this struct if name is "apple"
    Color string 
} 
type Peach struct { // use this struct if name is "peach"
    Size string
}
func main() {
    e := Element{}
    err := xml.Unmarshal([]byte(x), &e)
    if err != nil {
        panic(err)
    }   
    fmt.Println(e.Apple.Color)
    fmt.Println(e.Peach.Size
}

1 Ответ

2 голосов
/ 17 июня 2019

Вы можете просто перебирать узлы вашего типа Element и создавать структуры Apple и Peach по мере необходимости, включив их атрибут Name:

    for _, element := range e.Nodes {
        switch element.Name {
        case "apple":
            apples = append(apples, Apple{})
        case "peach":
            peaches = append(peaches, Peach{})
        }
    }

Вот ссылка на игровую площадку .

Другое, более сложное решение (но также более изящное и практичное) было бы реализовать собственный метод UnmarshalXML для типа Element, который напрямуюзаполните его правильными типами:

type Apple struct {
    Color string
}
type Peach struct {
    Size string
}

type Fruits struct {
    Apples  []Apple
    Peaches []Peach
}

type Element struct {
    XMLName xml.Name `xml:"element"`
    Nodes   []struct {
        Name  string `xml:"name,attr"`
        Apple struct {
            Color string `xml:"color"`
        } `xml:"apple"`
        Peach struct {
            Size string `xml:"size"`
        } `xml:"peach"`
    } `xml:"node"`
}

func (f *Fruits) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    var element Element
    d.DecodeElement(&element, &start)

    for _, el := range element.Nodes {
        switch el.Name {
        case "apple":
            f.Apples = append(f.Apples, Apple{
                Color: el.Apple.Color,
            })
        case "peach":
            f.Peaches = append(f.Peaches, Peach{
                Size: el.Peach.Size,
            })
        }
    }

    return nil
}

func main() {
    f := Fruits{}

    err := xml.Unmarshal([]byte(x), &f)
    if err != nil {
        panic(err)
    }

    fmt.Println("Apples:", f.Apples)
    fmt.Println("Peaches", f.Peaches)
}

Вот ссылка на игровую площадку для этого второго решения

Результат:

Apples: [{red}]
Peaches [{medium}]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...