Question Issue Getting XML Element With Namespaces

digitaldrew

Well-known member
Joined
Nov 10, 2012
Messages
167
Programming Experience
Beginner
Hey everyone, I'm trying get the "<reason>" InnerText from the XML below, but have not been having any luck. The XML has multiple namespaces in it...

VB.NET:
<?xml version="1.0" encoding="UTF-8"?>
<epp xmlns:fury="urn:ietf:params:xml:ns:fury-2.0" xmlns:fury-rgp="urn:ietf:params:xml:ns:fury-rgp-1.0" xmlns:fee="urn:ietf:params:xml:ns:fee-0.11" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:smd="urn:ietf:params:xml:ns:signedMark-1.0" xmlns:mark="urn:ietf:params:xml:ns:mark-1.0" xmlns:host="urn:ietf:params:xml:ns:host-1.0" xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1" xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0" xmlns:idn="urn:ietf:params:xml:ns:idn-1.0" xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
    <response>
        <result code="1000">
            <msg>Command completed successfully</msg>
            <extValue>
                <value>
                    <fury:Code>5614</fury:Code>
                </value>
                <reason>2023-01-12T06:44:05.551Z</reason>
            </extValue>
        </result>
        <resData>
            <domain:chkData>
                <domain:cd>
                    <domain:name avail="false">domain.com</domain:name>
                    <domain:reason>This is a reason.</domain:reason>
                </domain:cd>
            </domain:chkData>
        </resData>
        <trID>
            <svTRID>000380328629-0000000002</svTRID>
        </trID>
    </response>
</epp>

I've tried this multiple ways...
VB.NET:
            Dim doc = New Xml.XmlDocument()
            doc.LoadXml(requestResponse)

            Dim nsm = New Xml.XmlNamespaceManager(doc.NameTable)
            nsm.AddNamespace("ds", "http://www.w3.org/2000/09/xmldsig#")
            nsm.AddNamespace("fury", "urn:ietf:params:xml:ns:fury-2.0")
            nsm.AddNamespace("fury-rgp", "urn:ietf:params:xml:ns:fury-rgp-1.0")
            nsm.AddNamespace("fee", "urn:ietf:params:xml:ns:fee-0.11")
            nsm.AddNamespace("smd", "urn:ietf:params:xml:ns:signedMark-1.0")
            nsm.AddNamespace("mark", "urn:ietf:params:xml:ns:mark-1.0")
            nsm.AddNamespace("host", "urn:ietf:params:xml:ns:host-1.0")
            nsm.AddNamespace("launch", "urn:ietf:params:xml:ns:launch-1.0")
            nsm.AddNamespace("rgp", "urn:ietf:params:xml:ns:rgp-1.0")
            nsm.AddNamespace("ns", "urn:ietf:params:xml:ns:epp-1.0")
            nsm.AddNamespace("contact", "urn:ietf:params:xml:ns:contact-1.0")
            nsm.AddNamespace("domain", "urn:ietf:params:xml:ns:domain-1.0")
            nsm.AddNamespace("secDNS", "urn:ietf:params:xml:ns:secDNS-1.1")
            nsm.AddNamespace("idn", "urn:ietf:params:xml:ns:idn-1.0")
            Dim value = doc.SelectSingleNode("//reason", nsm).InnerText
            MsgBox(value.ToString)

This gives me no messagebox and an "Object reference not set to an instance of an object." exception..

VB.NET:
            Dim doc = XDocument.Parse(requestResponse)
            Dim ns As XNamespace = "urn:ietf:params:xml:ns:epp-1.0"
            MsgBox(doc.Element("reason").Value)
            MsgBox(doc.Element(ns + "reason").Value)

VB.NET:
            Dim doc = XDocument.Parse(requestResponse)
            Dim ns As XNamespace = "urn:ietf:params:xml:ns:epp-1.0"
            MsgBox(doc.Descendants("reason").Value())
            MsgBox(doc.Descendants(ns + "reason").Value())

Same thing with both of the codes above - "Object reference not set to an instance of an object." exceptions and no messageboxes..

Thanks in advance!
 
It's domain:reason where domain is the namespace prefix, you have to use this in query and the prefix is looked up in XmlNamespaceManager.
So doc.SelectSingleNode("//domain:reason", nsm).InnerText will work in your first code.

Your third code (Descendants) will work if you change namespace to urn:ietf:params:xml:ns:domain-1.0 and use the ns+"reason" line.
 
Just noticed there is another reason element that is in default namespace (xmlns="urn:ietf:params:xml:ns:epp-1.0").
Same goes here, you have to qualify it in query "//ns:reason" in first code, third code (Descendants) is ok for line ns + "reason" for that namespace url.
 
@JohnH now I am trying to get the same timestamp from a different response. The timestamp is still in "reason," but the namespace I am using is returning the first <reason> and not the second....

My Code:
VB.NET:
            Dim doc = XDocument.Parse(requestResponse)
            Dim ns As XNamespace = "urn:ietf:params:xml:ns:epp-1.0"
            MsgBox(doc.Descendants(ns + "reason").Value())

The Response:
VB.NET:
<?xml version="1.0" encoding="UTF-8"?>
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0" xmlns:host="urn:ietf:params:xml:ns:host-1.0" xmlns:contact="urn:ietf:params:xml:ns:contact-1.0" xmlns:domain="urn:ietf:params:xml:ns:domain-1.0" xmlns:rgp="urn:ietf:params:xml:ns:rgp-1.0" xmlns:fury="urn:ietf:params:xml:ns:fury-2.0" xmlns:fury-rgp="urn:ietf:params:xml:ns:fury-rgp-1.0" xmlns:idn="urn:ietf:params:xml:ns:idn-1.0" xmlns:secDNS="urn:ietf:params:xml:ns:secDNS-1.1" xmlns:launch="urn:ietf:params:xml:ns:launch-1.0" xmlns:mark="urn:ietf:params:xml:ns:mark-1.0" xmlns:smd="urn:ietf:params:xml:ns:signedMark-1.0" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:fee="urn:ietf:params:xml:ns:fee-0.11">
    <response>
        <result code="2304">
            <msg>Object status prohibits operation</msg>
            <extValue>
                <value>
                    <fury:ciraCode>8455</fury:ciraCode>
                </value>
                <reason>Droplist Session is not currently open.</reason>
            </extValue>
            <extValue>
                <value>
                    <fury:ciraCode>5614</fury:ciraCode>
                </value>
                <reason>2023-01-21T09:27:00.017Z</reason>
            </extValue>
        </result>
        <trID>
            <svTRID>CIRA-000380668899-0000000003</svTRID>
        </trID>
    </response>
</epp>

With the code above it's giving me this: Droplist Session is not currently open.
What I am actually wanting to get is this: 2023-01-21T09:27:00.017Z

How can I determine the namespace for this one? Thanks!
 
They have the same namespace. It's like an array with two elements. (the two extValue elements are sieblings)

You can use SelectNodes and inspect each of them if you seek some value, here it looks to be a date value so you could try with Date.TryParse for each value, it will return True for the date string only.

I learnt that order of sieblings in xml does not matter and can't be relied upon, but anyway, if there is such structure that there is always two elements and you always want the second element you could SelectSingleNode and use the 1-based array indexer [] in query. Here [] operator has higher precedence that // operator, so you'd have to use paranthesis in the query like this: (//ns:reason)[2]
 
They have the same namespace. It's like an array with two elements. (the two extValue elements are sieblings)

You can use SelectNodes and inspect each of them if you seek some value, here it looks to be a date value so you could try with Date.TryParse for each value, it will return True for the date string only.

I learnt that order of sieblings in xml does not matter and can't be relied upon, but anyway, if there is such structure that there is always two elements and you always want the second element you could SelectSingleNode and use the 1-based array indexer [] in query. Here [] operator has higher precedence that // operator, so you'd have to use paranthesis in the query like this: (//ns:reason)[2]

Thanks John!
 
Back
Top