0

I have the following XML File named Example.xml. Please note the namespace specification (xmlns) in the root element Message as the question below relates to this.

<?xml version="1.0" encoding="utf-8" ?>
<Message xmlns="http://www.myurl.com/Product" version="010" release="006">
   <Header>
      <To Qualifier="P" />
      <From Qualifier="D" />
      <MessageID>f244251a8c6c4070</MessageID>
      <SentTime>2018-03-21T22:01:16.70Z</SentTime>
   </Header>
   <Body>
      <Product>
         <Description>
            <Identification>
               <ID1>1871598417</ID1>
               <ID2>BE9432042-1234</ID2>
            </Identification>
            <Type>
               <Name>Home Widget</Name>
               <Category>Residential</Category>
            </Type>
         </Description>
      </Product>
   </Body>
</Message>

I have written the following function to return a string using LINQ

Public Function GetProductDetail() As String
    Dim xDoc As XDocument = Nothing
    Dim returnValue As String = ""

    Using xr As XmlReader = XmlReader.Create("C:\Automation\Example.xml")
        xDoc = XDocument.Load(xr)

        Dim query = From t In xDoc.Descendants("Body")
                    Select New With {Key _
                        .ID1 = t.Element("Product").Element("Description").Element("Identification").Element("ID1").Value,
                        .ID2 = t.Element("Product").Element("Description").Element("Identification").Element("ID2").Value,
                        .Name = t.Element("Product").Element("Description").Element("Type").Element("Name").Value}

        For Each item In query
            returnValue = $"ID1: {item.ID1} | ID2: {item.ID2} | Name: {item.Name}"
        Next

    End Using

    Return returnValue
End Function

The issue I am having is that the return value is blank with the above XML file.

When I change the root element to be only as follows:

<Message> 

(i.e. remove everything including xmlns=....) I get the correct return value

returnValue = ID1: 1871598417 | ID2: BE9432042-1234 | Name: Home Widget

I have following questions:

  1. What do I need add to my code or XPath Expression when the xmlns is part of the root element.

  2. Sometime the XML file may not contain the ID2 Element. How do I check in the LINQ Query if the element does not exists or is this even possible with LINQ.

  3. If this is not appropriate to do with LINQ can someone please provide code as to how this can be accomplished.

Appreciate everyone input, time and assistance.

Thanks

Juzer

0

1 Answer 1

0
  1. issue your problem is that you do not give a name to your namespace. for example:
    <Message xmlns:name="http://www.myurl.com/Product" version="010" release="006">.

    When you do not use a custom name for your namespace you must use the whole namespace as an identifier.

    This is the name of the Body without the custom name {{http://www.myurl.com/Product}Body} and this is with the custom name {Body} (Now you will be asking why the element body does not have the preceding {name:Body} at its name this is happening because it does not have any naming implications)

  2. You can use the Null Conditional Operator.
    For example: t.Element("Product").Element("Description").Element("Identification").Element("ID1")?.Value

  3. Although this is not an answer LINQ basically is a way to do a complicated foreach. So the only thing that i would do its maybe use XPath instead of chaining elements that may in the feature any one of them may end up null.

I hope i helped. If any question comes up feel free to ask and i will try to explain.

Thanks,

EDIT:

When you want to find a xml node using Namespace you can use this kind of code. (If i did something wrong please spare me i'm C# Dev not Visual Basic)

Dim nameSpace As xDoc.Root.GetDefaultNamespace()?.NamespaceName
Dim body As xDoc.Descendants(XName.Get("Body", nameSpace))
Dim productXName As XName.Get("Product", nameSpace)
Dim descriptionXName As XName.Get("Description", nameSpace)
Dim identificationXName As XName.Get("Identification", nameSpace)
Dim id1XName As XName.Get("ID1", nameSpace)
Dim id2XName As XName.Get("ID2", nameSpace)
Dim typeXName As XName.Get("Type", nameSpace)
Dim nameXName As XName.Get("Name", nameSpace)
Dim query As From t In body
            select New With {Key _                        
                        .ID1 = t.Element(productXName).Element(descriptionXName).Element(identificationXName).Element(id1XName)?.Value,
                        .ID2 = t.Element(productXName).Element(descriptionXName).Element(identificationXName).Element(id2XName)?.Value,
                        .Name = t.Element(productXName).Element(descriptionXName).Element(typeXName).Element(nameXName)?.Value}

' Updated Working VB.Net Code

Public Function GetProductDetail() As String
    Dim xDoc As XDocument = Nothing
    Dim returnValue As String = ""

    Using xr As XmlReader = XmlReader.Create("C:\Automation\Example.xml")
        xDoc = XDocument.Load(xr)
        Dim xn = xDoc.Root.GetDefaultNamespace()?.NamespaceName
        Dim body = xDoc.Descendants(XName.Get("Body", xn))
        Dim productXName = XName.Get("Product", xn)
        Dim descriptionXName = XName.Get("Description", xn)
        Dim identificationXName = XName.Get("Identification", xn)
        Dim id1XName = XName.Get("ID1", xn)
        Dim id2XName = XName.Get("ID2", xn)
        Dim typeXName = XName.Get("Type", xn)
        Dim nameXName = XName.Get("Name", xn)
        ' Name1 May or Maynot exist in the XML file
        Dim nameXName1 = XName.Get("Name1", xn)

        ' DT May or May not Exist in recived XML File
        Dim query = From t In body
                    Select New With {Key _
                        .ID1 = t.Element(productXName).Element(descriptionXName).Element(identificationXName).Element(id1XName)?.Value,
                        .ID2 = t.Element(productXName).Element(descriptionXName).Element(identificationXName).Element(id2XName)?.Value,
                        .Name = t.Element(productXName).Element(descriptionXName).Element(typeXName).Element(nameXName)?.Value,
                        .DT = t.Element(productXName).Element(descriptionXName).Element(typeXName).Element(nameXName1)?.Value}


        For Each item In query
            returnValue = $"ID1: {item.ID1} | ID2: {item.ID2} | Name: {item.Name} | DT: {item.DT} "
        Next
    End Using
    Return returnValue
End Function
Sign up to request clarification or add additional context in comments.

6 Comments

I am receiving the file from an external source, so I have no control over it. I have tried what you have suggested by trying to pass the namespace to the Descendants like "{myrul.com/Product\}Body", but still getting a blank return value. Can you provide sample code to clarify.
When I post it seems it is removing the http:// in front of the www.myurl.com/Product
Tried suggestion for the Null Conditional Operator it still gave me a NullReferenceException error
I understand that each of the child elements is part of that namespace, but how do I pass it to the Descendants to query the elements
Thanks for the code, I was able to get your idea and even added an element which may or may not exists and it returns the correct value. I am posting the updated working function for others to benefit. Not sure how the formatting will be. But Here it goes
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.