none
XML finding element from node RRS feed

  • Question

  • Hey

    im currently getting data from XML by finding the element, checking for a node value that i already have and if true, getting the rest of the data from the element but in order to do this, i need to know the element first.

    Is there a way of searching for the node value instead and if found, getting the element that owns it so that i can get the rest of the data for that element?

    <standardData>
    	<!-- Standard Component Data -->
    	<identifier>Assembly Main Head</identifier>
    	<idNumber>1258491231</idNumber>
    	<attachedTo>Cylinder #1</attachedTo>
    	<attachedToKind>Cylinder</attachedToKind>
    	<attachedToidNumber>1258491234</attachedToidNumber>
    	<material>Stainless Steel</material>
    	<designThickness units="in">0.2214</designThickness>
    </standardData>

    inm the above XML, i need all of the data within standardData but only have the idNumber as the filter and standrdData isnt always called standardData

    Thanks


    Nacho is the derivative of Nigel - True fact! I am self taught in VB.Net. 50% of the time, I am right 100% of the time!

    Saturday, February 15, 2020 7:53 PM

All replies

  • Hi,
    try following console demo:

    Module Module34
      Sub Main()
        Try
          Call (New Demo).Execute()
        Catch ex As Exception
          Console.WriteLine(ex.ToString)
        End Try
        Console.WriteLine("Continue enter key")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
        Private xml As XElement = <root>
                                    <standardData>
                                      <!-- Standard Component Data -->
                                      <identifier>Assembly Main Head</identifier>
                                      <idNumber>1258491231</idNumber>
                                      <attachedTo>Cylinder #1</attachedTo>
                                      <attachedToKind>Cylinder</attachedToKind>
                                      <attachedToidNumber>1258491234</attachedToidNumber>
                                      <material>Stainless Steel</material>
                                      <designThickness units="in">0.2214</designThickness>
                                    </standardData>
                                  </root>
        Friend Sub Execute()
          Dim searchId = "1258491231"
          Dim result = xml.Descendants("idNumber").Where(Function(node)
                                                           Return node.Value = searchId
                                                         End Function).FirstOrDefault.Parent
    
          Console.WriteLine(result)
        End Sub
      End Class
    
    End Module


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Sunday, February 16, 2020 9:15 AM
  • I think that the problem can be solved with “XPath” too, which can be used in case of XmlDocument and XDocument objects. For XDocument, it looks like this:

     

    Imports System.Xml.XPath
    
    . . .
    
    
    Dim xdoc As XDocument = <?xml version="1.0"?>
                            <MyData>
                                <someOtherElement>
                                    <!-- Some other element -->
                                    <identifier>aaa</identifier>
                                    <idNumber>777777777777</idNumber>
                                    <attachedTo>bbb</attachedTo>
                                    <attachedToKind>ccc</attachedToKind>
                                    <attachedToidNumber>99999999999</attachedToidNumber>
                                    <material>ddd</material>
                                    <designThickness units="in">1.2345</designThickness>
                                </someOtherElement>
                                <myElement>
                                    <!-- The element that contains idNumber=1258491231 -->
                                    <identifier>Assembly Main Head</identifier>
                                    <idNumber>1258491231</idNumber>
                                    <attachedTo>Cylinder #1</attachedTo>
                                    <attachedToKind>Cylinder</attachedToKind>
                                    <attachedToidNumber>1258491234</attachedToidNumber>
                                    <material>Stainless Steel</material>
                                    <designThickness units="in"> 0.2214</designThickness>
                                </myElement>
                            </MyData>
     
    Dim idNumber As Integer = 1258491231
    Dim element As XElement = xdoc.XPathSelectElement($"//*[idNumber='{idNumber}']")
     
    If element IsNot Nothing Then
        Dim identifier As String = element.XPathSelectElement("identifier").Value
        ' . . .
        Dim designThickness As String = element.XPathSelectElement("designThickness").Value
        Dim designThicknessUnits As String = element.XPathSelectElement("designThickness").Attribute("units").Value
    End If
     

    Can be done with XmlDocument too.




    • Edited by Viorel_MVP Sunday, February 16, 2020 4:34 PM
    Sunday, February 16, 2020 4:33 PM
  • Hey

    Thanks for the code. I need to be a little more detailed in the results. With the data above, how would i get the parent element name (myElement) and then all of the node names? for example, i would use the idNumber to get the parent Element name and then use the parent name as the filter to loop through all of the nodes to get the node names & values. So, effectively using the idNumber to locate the element and then looping through the element to get all of the data results

     dim GetNameFromMSDNExample as string = ResultFromParentElementSearch 
    
    Dim xml_doc As XmlDocument = New XmlDocument
            Dim ConcString As String = String.Empty
            xml_doc.Load("C:\Users\source\repos\Decom\Decom\Decom Example.xml")
            Dim generalElement = xml_doc.GetElementsByTagName(GetNameFromMSDNExample)
            For Each node As XmlElement In generalElement
                Dim getIdent As String = node("identifier").InnerText.ToString().ToUpper
                Dim getIDno As String = node("idNumber").InnerText.ToString().ToUpper
    Next

    Thanks



    Nacho is the derivative of Nigel - True fact! I am self taught in VB.Net. 50% of the time, I am right 100% of the time!

    Monday, February 17, 2020 9:01 PM
  • Hi

    I tried your code thanks, it gives me all of the results but in a single text stream. as the text will be unknown i havent found a way of separating the text into specific lines...

    Result = Assembly Main Head1258491231Cylinder #1Cylinder1258491234Stainless Steelin0.2214

    Thanks


    Nacho is the derivative of Nigel - True fact! I am self taught in VB.Net. 50% of the time, I am right 100% of the time!

    Tuesday, February 18, 2020 3:49 AM
  • Is there an easier way? xPath, xDocument may be easier for some than others. for me, its yet another tangent methods to learn and i dont understand it. I understand the traditional XML more. I actually thought it wouldnt be this difficult but its turning into a much bigger monster now. My problem is the levels of nodes in the xml document. They are unknown and can vary. The names of the elements can vary too. The only given value i have to work with is the idNumber. The node will always be called idNumber and thats what i need to search with. In my mind:

    • Find the idNumber in the XML document - (1258491231)
    • Get the Parent of the idNumber (the next one up is <standardData>)
    • use that to filter the loop - xml_doc.GetElementsByTagName(Parent)
    • get all of the nodes owned by the parent

    is there a way of finding the node, finding its parent and then moving up the tree to get parent of parent etc?

    Thanks for any help, ive had a day of a multitude of errors

    Thanks


    Nacho is the derivative of Nigel - True fact! I am self taught in VB.Net. 50% of the time, I am right 100% of the time!

    Tuesday, February 18, 2020 4:11 AM
  • Hey

    To expand a little further, how difficult would it be to get the name of the node & the value for each iteration?

    so with this data

     <standardData>
         <!-- Standard Component Data -->
         <identifier>Assembly Main Head</identifier>
         <idNumber>1258491231</idNumber>
         <attachedTo>Cylinder #1</attachedTo>
         <attachedToKind>Cylinder</attachedToKind>
         <attachedToidNumber>1258491234</attachedToidNumber>
         <material>Stainless Steel</material>
         <designThickness units="in">0.2214</designThickness>
    </standardData>

    then

    Dim xml_doc As XmlDocument = New XmlDocument
    xml_doc.Load("C:\Users\source\repos\Decom\Decom\DecomExample.xml")
    
    Dim idNumber As Integer = 1258491249 'obtained from model
    Dim ParentNode As String ' somehow get parentnode by using idNumber = "standardData"
    Dim InfoNodeList = xml_doc.GetElementsByTagName("ParentNode") 'using parentnode as tag name
    For Each node As XmlElement In InfoNodeList
        Dim GetNodeName As String 'Get the node name i.e. attachedTo
        Dim GetNodeValue As String ' Get the node Value i.e Cylinder #1
        'use the name & val to create external properties elsewhere
        Call CreateExternalProps(GetNodeName, GetNodeValue)
    Next

    This would allow me to be totally dynamic in saving the values as i could create a property based on the node name and apply the value directly to it

    thanks


    Nacho is the derivative of Nigel - True fact! I am self taught in VB.Net. 50% of the time, I am right 100% of the time!

    Tuesday, February 18, 2020 4:30 AM
  • Hi,
    try my demo!

    Your result you get when you assign all values all embedded nodes:

    Console.WriteLine(result.Value)

    To get all subnodes you must iterate :

          For Each node In result.Descendants
            Console.WriteLine($"{node.Name}: {node.Value}")
          Next


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Tuesday, February 18, 2020 4:47 AM
  • Hi,
    try following demo (iterate through all subnodes).

    Module Module34
      Sub Main()
        Try
          Call (New Demo).Execute()
        Catch ex As Exception
          Console.WriteLine(ex.ToString)
        End Try
        Console.WriteLine("Continue enter key")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
        Friend Sub Execute()
          Dim xml = XElement.Load("Module34.xml") ' load file with xml data
          Dim searchId = "1258491231"
          Dim result = Xml.Descendants("idNumber").Where(Function(node)
                                                           Return node.Value = searchId
                                                         End Function).FirstOrDefault.Parent
          'Console.WriteLine(result)
          'Console.WriteLine(result.Value)
          For Each node In result.Descendants
            Console.WriteLine($"{node.Name}: {node.Value}")
          Next
        End Sub
      End Class
    
    End Module
    


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks

    Tuesday, February 18, 2020 4:50 AM
  • Hi

    Thanks very much for that, I can get the node name & value now :)

    Using your demo, is there a way to adjust it so i can step up one to the to the parent? There is some data at that level that i need to include with all of the nodes at this level. I have checked at it looks like everything steps up 1 level with a bit of parent info...

    Easy when you know how :)

    Thanks


    Nacho is the derivative of Nigel - True fact! I am self taught in VB.Net. 50% of the time, I am right 100% of the time!

    Tuesday, February 18, 2020 5:07 AM
  • Hi,
    try following demo:

    Module Module1
      Sub Main()
        Try
          Call (New Demo).Execute()
        Catch ex As Exception
          Console.WriteLine(ex.ToString)
        End Try
        Console.WriteLine("Continue enter key")
        Console.ReadKey()
      End Sub
    
      Friend Class Demo
        Friend Sub Execute()
          Dim xml = XElement.Load("Module34.xml") ' load file with xml data
          Dim searchId = "1258491231"
          Dim findedNode = xml.Descendants("idNumber").Where(Function(node)
                                                               Return node.Value = searchId
                                                             End Function).FirstOrDefault.Parent
          'Console.WriteLine(result)
          'Console.WriteLine(result.Value)
          ' show finded node
          Console.WriteLine($"- finded node <{findedNode.Name}>")
          For Each node In findedNode.Descendants
            Console.WriteLine($"{node.Name}: {node.Value}")
          Next
    
          ' get parent node of finded node
          Console.WriteLine("--- nodes of parent node of finded node")
          Dim parentNode = findedNode.Parent
          Console.WriteLine($"- parent node <{parentNode.Name}>")
          ' show alle nodes in parent node
          For Each node As XElement In parentNode.Nodes
            Console.WriteLine($"{node.Name}, idNumber: {node.<idNumber>.Value}")
          Next
        End Sub
    
      End Class
    
    End Module

    My test data in xml file:

    <?xml version="1.0" encoding="utf-8" ?>
    <Root>
      <DataList1>
        <standardData>
          <!-- Standard Component Data -->
          <identifier>Assembly Main Head</identifier>
          <idNumber>1258491231</idNumber>
          <attachedTo>Cylinder #1</attachedTo>
          <attachedToKind>Cylinder</attachedToKind>
          <attachedToidNumber>1258491234</attachedToidNumber>
          <material>Stainless Steel</material>
          <designThickness units="in">0.2214</designThickness>
        </standardData>
        <standardData>
          <identifier>Assembly Main Head</identifier>
          <idNumber>1234567890</idNumber>
          <attachedTo>Cylinder #1</attachedTo>
          <attachedToKind>Cylinder</attachedToKind>
          <attachedToidNumber>1258491234</attachedToidNumber>
          <material>Stainless Steel</material>
          <designThickness units="in">0.2214</designThickness>
        </standardData>
        <standardData>
          <identifier>Assembly Main Head</identifier>
          <idNumber>2345678901</idNumber>
          <attachedTo>Cylinder #1</attachedTo>
          <attachedToKind>Cylinder</attachedToKind>
          <attachedToidNumber>1258491234</attachedToidNumber>
          <material>Stainless Steel</material>
          <designThickness units="in">0.2214</designThickness>
        </standardData>
      </DataList1>
      <DataList2>
        <standardData>
          <!-- Standard Component Data -->
          <identifier>Assembly Main Head</identifier>
          <idNumber>3456789012</idNumber>
          <attachedTo>Cylinder #1</attachedTo>
          <attachedToKind>Cylinder</attachedToKind>
          <attachedToidNumber>1258491234</attachedToidNumber>
          <material>Stainless Steel</material>
          <designThickness units="in">0.2214</designThickness>
        </standardData>
        <standardData>
          <identifier>Assembly Main Head</identifier>
          <idNumber>4567890123</idNumber>
          <attachedTo>Cylinder #1</attachedTo>
          <attachedToKind>Cylinder</attachedToKind>
          <attachedToidNumber>1258491234</attachedToidNumber>
          <material>Stainless Steel</material>
          <designThickness units="in">0.2214</designThickness>
        </standardData>
        <standardData>
          <identifier>Assembly Main Head</identifier>
          <idNumber>5678901234</idNumber>
          <attachedTo>Cylinder #1</attachedTo>
          <attachedToKind>Cylinder</attachedToKind>
          <attachedToidNumber>1258491234</attachedToidNumber>
          <material>Stainless Steel</material>
          <designThickness units="in">0.2214</designThickness>
        </standardData>
      </DataList2>
    </Root>


    --
    Best Regards / Viele Grüße
    Peter Fleischer (former MVP for Developer Technologies)
    Homepage, Tipps, Tricks


    Tuesday, February 18, 2020 5:39 AM