Joshua Murphy
Joshua Murphy

Reputation: 23

Trouble accessing namespaced XML attribute with unmarshal in Go

I'm having trouble accessing an attribute in a namespaced tag when using umarshal on some XML data. A working example of what I'm trying to accomplish is on line 14 of my code which demonstrates successfully loading the attribute name from the <cpe-item> tag, into the Name field of the CPE struct.

However, doing the same thing with a name-spaced tag such as on line 19 (loading the name attribute from the <cpe23: cpe23-item> tag into the Name field of the CPE23 struct) does not work - no value is found.

I'm failing to see the discrepancy between these two actions and why one fails while the other doesn't.

package main

import (
    "encoding/xml"
    "fmt"
)

type CPEs struct {
    XMLName xml.Name `xml:"cpe-list"`
    CPEs    []CPE    `xml:"cpe-item"`
}

type CPE struct {
    Name  string `xml:"name,attr"`
    CPE23 CPE23  `xml:"cpe23: cpe23-item"`
}

type CPE23 struct {
    Name string `xml:"cpe23: cpe23-item,name,attr"`
}

func main() {

    var cpes CPEs

    contents := `
    <cpe-list xmlns:meta="http://scap.nist.gov/schema/cpe-dictionary-metadata/0.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cpe-23="http://scap.nist.gov/schema/cpe-extension/2.3" xmlns="http://cpe.mitre.org/dictionary/2.0" xmlns:config="http://scap.nist.gov/schema/configuration/0.1" xmlns:ns6="http://scap.nist.gov/schema/scap-core/0.1" xmlns:scap-core="http://scap.nist.gov/schema/scap-core/0.3" xsi:schemaLocation="http://scap.nist.gov/schema/cpe-extension/2.3 https://scap.nist.gov/schema/cpe/2.3/cpe-dictionary-extension_2.3.xsd http://cpe.mitre.org/dictionary/2.0 https://scap.nist.gov/schema/cpe/2.3/cpe-dictionary_2.3.xsd http://scap.nist.gov/schema/cpe-dictionary-metadata/0.2 https://scap.nist.gov/schema/cpe/2.1/cpe-dictionary-metadata_0.2.xsd http://scap.nist.gov/schema/scap-core/0.3 https://scap.nist.gov/schema/nvd/scap-core_0.3.xsd http://scap.nist.gov/schema/configuration/0.1 https://scap.nist.gov/schema/nvd/configuration_0.1.xsd http://scap.nist.gov/schema/scap-core/0.1 https://scap.nist.gov/schema/nvd/scap-core_0.1.xsd">
        <cpe-item name="I'm the cpe name!"><!--I can parse this attribute-->
            <title>I'm the title!</title>
            <references>
                    <reference href="https://example.com">Example</reference>
                    <reference href="https://example2.com">Example 2</reference>
             </references>
            <cpe-23:cpe23-item name="CPE 2.3 name!"/><!--I can't parse this attribute-->
            </cpe-item>
    </cpe-list>`

    xml.Unmarshal([]byte(contents), &cpes)

    for i := 0; i < len(cpes.CPEs); i++ {
        fmt.Println("CPE Name: " + cpes.CPEs[i].Name)
        fmt.Println("CPE23 Name: " + cpes.CPEs[i].CPE23.Name)
    }
}

Go playground link https://play.golang.org/p/eRMrFePDM4K

Upvotes: 2

Views: 134

Answers (1)

blackgreen
blackgreen

Reputation: 45041

Unfortunately the documentation doesn't provide much insight. Compare with this relatively recent question.

However, it is possible to make your code work by simply removing the namespace from the tag of the CPE23 field:

type CPE struct {
    Name  string `xml:"name,attr"`
    CPE23 CPE23  `xml:"cpe23-item"`
}

type CPE23 struct {
    Name string `xml:"name,attr"`
}

...or by prefixing the tag name with the full namespace, separated by a whitespace:

type CPE struct {
    Name  string `xml:"name,attr"`
    CPE23 CPE23  `xml:"http://scap.nist.gov/schema/cpe-extension/2.3 cpe23-item"`
}

See this Go Play

By looking at the source code of the encoding/xml package, it's possible to see that the tokenizer reads an xml element tag in the form of <ns:foo>, where xmlns:ns="http://mynamespace.com", into an xml.Name struct in the form:

xml.Name{
    Space: "http://mynamespace.com",
    Local: "foo"
}

And then it resolves tags on your destination struct based on those two fields. If there's no namespace on your struct tag, it matches on the value of Local only.

Upvotes: 1

Related Questions