locked
Help with LINQ to XML RRS feed

  • Question

  • Hello Everybody;

    I need help with a LINQ statement that aims to extract one element value by querying another element under the same parent but with different attribute. My XML is as follows:
    <parent>
    <entrydata columnnumber="1" name="OfficeLocation">
    <text>UK</text>
    </entrydata>
    <entrydata columnnumber="2" name="FullName">
    <text>Maya Angelo</text>
    </entrydata>
    <entrydata columnnumber="3" name="InternetAddress">
    <text>Mayaa@anything.com</text>
    </entrydata>
    </parent>

    I want to query this xml to get the entrydata/InterentAddress/text value  where the entrydata/FullName/text Value= "XXXX". I appreciate if somebody can provide a sample of LINQ in VB.

    Thank you in advance.
    Monday, August 3, 2009 7:56 PM

Answers

  • You can always evaluate an expression relative to the current XPathNavigator e.g. if you have

    foreach (XPathNavigator text in xmlNav.Select("/parent[entrydata[@name='FullName']/text='Maya Angelo']/entrydata[@name='InternetAddress']/text"))
    {
      Console.WriteLine("{InternetAddress: {0}", text.Value);
      Console.WriteLine("Full name: {0}", text.SelectSingleNode("../../entrydata[@name = 'FullName']/text").Value);
    }
    then the SelectSingleNode access the sibling entrydata element of the grandparent of the text element.

    MVP XML My blog
    • Marked as answer by Silversea Wednesday, August 5, 2009 5:57 PM
    Wednesday, August 5, 2009 2:27 PM

All replies

  • Acutally one XPath expression can do it:

         /parent[entrydata[@name="FullName"]/text="Maya Angelo"]/entrydata[@name="InternetAddress"]/text
    Your potential, our passion.
    Tuesday, August 4, 2009 2:53 AM
  • Assuming that 'parent' element you show is contained somewhere in a larger XML document you could do the following LINQ to XML and VB.NET:

            Dim doc As XDocument = XDocument.Load("..\..\XMLFile1.xml")
            Dim s As String = "Maya Angelo"
    
            Dim parent As XElement = _
            doc...<parent>.Where(Function(p) p.<entrydata>.Any(Function(e) e.@name = "FullName" AndAlso e.<text>.Value = s)).FirstOrDefault()
    
            If parent IsNot Nothing Then
                Console.WriteLine(parent.<entrydata>.Where(Function(e) e.@name = "InternetAddress").First().<text>.Value)
            Else
                Console.WriteLine("Not found")
            End If
    So I have broken up the query into two parts, the first to find the parent element containing the entrydata with the FullName you are looking for, then, if that is found, a second query to find the InternetAddress.
    MVP XML My blog
    Tuesday, August 4, 2009 10:56 AM
  • Thank you Chen that was simpler than I thought. It worked nicely. This is the code that I used:
           
            XpathLBL.Text = ""
            Dim xpathDoc As XPathDocument
            Dim xmlNav As XPathNavigator
            Dim xmlNI As XPathNodeIterator

            xpathDoc = New XPathDocument(Server.MapPath("XMLtest.xml"))
            xmlNav = xpathDoc.CreateNavigator()

            'xmlNI = xmlNav.Select("/parent[entrydata[@name='FullName']/text='Maya Angelo']/entrydata[@name='InternetAddress']/text")

            While (xmlNI.MoveNext())
                XpathLBL.Text += xmlNI.Current.Value + "<br/>"
            End While

    As you see I am using a Label in a web page to bind the data to. How can I bind the two values ('Fullname' and 'InternetAddress') to the label? Should I add another select statement to the XpathNodeIterator? How does that work?

    Once again thanks very much.


    Tuesday, August 4, 2009 1:38 PM
  • Thank you Martin. That was very informative. I would like to test this solution also and I will let you know very soon.


    Tuesday, August 4, 2009 1:42 PM
  • Hmm... I don't know much about Label in a webpage. Can you just concatinate the two values using some special character as separator? For example "'Maya Angelo|Mayaa@anything.com", and later when you need the Fullname and InternetAddress, you can split the label value and get each attribute value respecitvely.
    Your potential, our passion.
    Wednesday, August 5, 2009 2:09 AM
  • Hi Chen

    My concern is not to how to display the values by manipulating the label string. My question is how to get these values in the first place. I can get one of them to read with the following statement:

    xmlNI = xmlNav.Select("/parent[entrydata[@name='FullName']/text='Maya Angelo']/entrydata[@name='InternetAddress']/text")

    This gives me the "InternetAddress" value. How do I get the "FullName" to read also? Do I need to add another Select statement to the Iterator? How can I do that?

    Thanks again
    Wednesday, August 5, 2009 12:49 PM
  • Hi Silversea, sorry I am a bit confused. You already know that the "FullName" value is "Maya Angelo", right? Because that is the condition for selecting the corresponding "InternetAddress". So why you still want to query the "FullName" value?


    Your potential, our passion.
    Wednesday, August 5, 2009 1:22 PM
  • Hi Chen

    Good question! Sorry for the confusion. My answer is:
    Because eventually I would like to change the code to perform a search with a wild character entries using the [Contains] function. For example I would like to pick not only "Maya Angelo", but all full names that contain "Ma*" for example, and hence, I would like the iteration to show the following result:

    Maya Angelo : MayaA@anything.com
    Golda Mayeer: GlodaM@anything.com
    Mayer Lanski: MayerL@anything.com
    ...etc

    So the question now is how to get both values (fullname and InternetAddress) extracted through an Xpath Statement that will be bound to the Xpath Iterator.

    I really appreciate your help.

    Thanks
    Wednesday, August 5, 2009 1:51 PM
  • You can always evaluate an expression relative to the current XPathNavigator e.g. if you have

    foreach (XPathNavigator text in xmlNav.Select("/parent[entrydata[@name='FullName']/text='Maya Angelo']/entrydata[@name='InternetAddress']/text"))
    {
      Console.WriteLine("{InternetAddress: {0}", text.Value);
      Console.WriteLine("Full name: {0}", text.SelectSingleNode("../../entrydata[@name = 'FullName']/text").Value);
    }
    then the SelectSingleNode access the sibling entrydata element of the grandparent of the text element.

    MVP XML My blog
    • Marked as answer by Silversea Wednesday, August 5, 2009 5:57 PM
    Wednesday, August 5, 2009 2:27 PM
  • Thanks Martin,

    It did work. The final code (in VB.Net) looks like this:

            XpathLBL.Text = ""
            Dim xpathDoc As XPathDocument
            Dim xmlNav As XPathNavigator
            Dim xmlNI As XPathNodeIterator

            xpathDoc = New XPathDocument(Server.MapPath("XMLtest.xml"))
            xmlNav = xpathDoc.CreateNavigator()

            xmlNI = xmlNav.Select("/parent[entrydata[@name='FullName']/text[contains(.,'Ma')]]/entrydata[@name='InternetAddress']/text")

            For Each text As XPathNavigator In xmlNav.Select("/parent[entrydata[@name='FullName']/text='Maya Angelo']/entrydata[@name='InternetAddress']/text")
                XpathLBL.Text += String.Format("InternetAddress: {0}", text.Value)
                XpathLBL.Text += String.Format("Full name: {0}", text.SelectSingleNode("../../entrydata[@name = 'FullName']/text").Value)
            Next

    Thanks everybody for your help

    Wednesday, August 5, 2009 6:43 PM