XML-маршалинг и демаршалинг xsi: type - PullRequest
0 голосов
/ 06 октября 2019

Это касается атрибута xsi: type , но если у вас есть элемент с именем <<strong> soap: envelope ...>, возникают аналогичные проблемы, когда кажется необходимым реализовать пользовательский unmarshalerфункции.

вот код с проблемой (на игровой площадке: https://play.golang.org/p/ORQsINYS-9o)

type PayloadPublication struct {
    XMLName xml.Name `json:"xmlName"`
    XsiType xml.Attr `xml:"xsi type,attr" json:"xsiType"`
    Lang    xml.Attr `xml:"lang,attr" json:"lang"`
}

func main() {
    payload := PayloadPublication{}

    expectedXML := `<payloadPublication xmlns="http://datex2.eu/schema/2/2_0" xsi:type="MeasurementSiteTablePublication" lang="nl"></payloadPublication>`

    // 1. Unmarshal - 2. Marshal - 3. Compare
    err := xml.Unmarshal([]byte(expectedXML), &payload)
    if err != nil {
        fmt.Print(err.Error())
    }

    result, err := xml.Marshal(payload)
    if err != nil {
        fmt.Print(err.Error())
    }

    fmt.Printf("expected: %v\n", expectedXML)
    fmt.Printf("result:   %v\n", string(result))
}

результат

expected: <payloadPublication xmlns="http://datex2.eu/schema/2/2_0" xsi:type="MeasurementSiteTablePublication" lang="nl"></payloadPublication>
result:   <payloadPublication xmlns="http://datex2.eu/schema/2/2_0" xmlns:xsi="xsi" xsi:type="MeasurementSiteTablePublication" lang="nl"></payloadPublication>

, как вы можете видеть атрибут xmlns: xsi = "xsi" был добавлен, что не то, что я хочу

В качестве обходного пути для этого можно было бы использовать пользовательский unmarshaler, но это кажется излишне сложным и многословным. (Код ниже). Есть ли более простой способ сделать это? Каким был бы обычный способ иметь дело с этим видом XML?

обходной код (на игровой площадке: https://play.golang.org/p/d4OtYPtYBDg)

type PayloadPublication struct {
    XMLName xml.Name `json:"xmlName"`
    XsiType xml.Attr `xml:"xsi type,attr" json:"xsiType"`
    Lang    xml.Attr `xml:"lang,attr" json:"lang"`
}

func (pp *PayloadPublication) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
    // Attributes
    for _, attr := range start.Attr {
        if attr.Name.Local == "type" {
            pp.XsiType = xml.Attr{Name: xml.Name{Local: "xsi:type"}, Value: attr.Value}
        }
    }

    var dummy struct {
        // attributes
        XMLName xml.Name `json:"xmlName"`
        XsiType xml.Attr `xml:"xsi type,attr" json:"xsiType"`
        Lang    xml.Attr `xml:"lang,attr" json:"lang"`
    }

    err := d.DecodeElement(&dummy, &start)
    if err != nil {
        return err
    }

    pp.XMLName = dummy.XMLName
    pp.Lang = dummy.Lang

    return nil
}

func main() {
    payload := PayloadPublication{}

    expectedXML := `<payloadPublication xmlns="http://datex2.eu/schema/2/2_0" xsi:type="MeasurementSiteTablePublication" lang="nl"></payloadPublication>`

    // 1. Unmarshal - 2. Marshal - 3. Compare
    err := xml.Unmarshal([]byte(expectedXML), &payload)
    if err != nil {
        fmt.Print(err.Error())
    }

    result, err := xml.Marshal(payload)
    if err != nil {
        fmt.Print(err.Error())
    }

    fmt.Printf("expected: %v\n", expectedXML)
    fmt.Printf("result:   %v\n", string(result))
}

1 Ответ

1 голос
/ 07 октября 2019

Технически золотой результат в примере (я имею в виду первый ), похоже, не является правильно сформированным XML. Он имеет несвязанный префикс xml-элемента xsi для атрибута xsi:type. Я думаю, эта спецификация устанавливает авторитетное правило для этого. Этот фрагмент XML выглядит неконкурентным, если он является частью более крупного документа, тогда префикс xsi может быть связан в другом месте - он очень распространен для документов SOAP.

Обратите внимание, чтоGo Marshaller производит правильно сформированный XML. Этот документ все еще не является допустимым XML из-за отсутствия DTD в фрагменте и т. Д., Но по крайней мере он не будет путать любой синтаксический анализатор XML.

В качестве более широкого предложения, соответствующего точному текстовому представлению документов XMLдля тестов или чего-либо еще, скорее всего, даст плохие результаты, потому что существует более одного синтаксически правильного (и правильно сформированного) способа кодирования документа в XML. Различные маршаллеры могут подстраивать конкретный подход к кодированию по вкусу своим авторам, и это не делает сгенерированный XML поврежденным или несовместимым с любым другим совместимым декодером. Вместо того, чтобы сравнивать фрагменты текста, попробуйте сравнить неупорядоченные структуры. Что-то вроде пакета github.com / google / go-cmp / cmp может сделать его простым.

...