2

I have an API that returns data in XML. The relevant part of the XML looks like this:

<data name="Rows">
   <data Name="Row">
     <data name="CONTACT">John Smith</data>
     <data name="PHONE1">(555)123-4567</data>
   </data>
   <data Name="Row">
     <data name="CONTACT">Jim Smith</data>
     <data name="PHONE1">(555)123-6754</data>
   </data>
</data>

I can get a collection of nodes of each Row with this:

var query = from item in xdoc.Root.Descendants("data")
            where (string)item.Attribute("Name") == "Row"
            select item;

And a collection of strings for each element if I filter by attribute:

var query2 = from item in query.Elements("data")
             where (string)item.Attribute("name") == "CONTACT" 
             select item;

returns: John Smith, James Smith

But I can't figure out how to get each contact name and phone number together.

Something like:

foreach(var row in query)
{
    contact = query.???;
    phone1 = query.????;
}

3 Answers 3

1

You need to use your first query to get collection of row elements. Then for each element you need to look for children with desired attribute:

// Find all elements  <data Name="Row">
var query = from item in xdoc.Root.Descendants("data")
     where (string)item.Attribute("Name") == "Row"
     select item;

// Loop through the elements
foreach(var row in query)
{
    // find child element, that has attribute Name="CONTACT"
    var contactElement = row.Descendants("data")
        .Where(x=>(string)x.Attribute("Name") == "CONTACT")
        .First();
    // find child element, that has attribute Name="PHONE1"
    var phoneElement = row.Descendants("data")
        .Where(x=>(string)x.Attribute("Name") == "PHONE1")
        .First();
    // get values of found elements
    var contact = contactElement.Value;
    var phone1 = phoneElement.Value;
}

Above code assumes that you will always have all elements, so function First() is used. If some elements might be missing, you need to handle that accordingly.

Sign up to request clarification or add additional context in comments.

Comments

1

Since in your XML all the nodes are data, using Descedants may result in unexpected results as it will find all the nodes no matter where it is present. I will go step by step:-

1) From the root node find all the elements using xdoc.Root.Elements("data") this will give you two nodes with attribute Name as Row.
2) Now from the collection retrieved in step 1, find the first data which have name attribute as CONTACT or PHONE1.
3) Simply project the items retrieved in step 2.

 var res = from item in xdoc.Root.Elements("data")
           let ContactRow = item.Elements("data")
                            .FirstOrDefault(x => (string)x.Attribute("name") == "CONTACT")
           let PHONE1Row = item.Elements("data")
                            .FirstOrDefault(x => (string)x.Attribute("name") == "PHONE1")
           select new
                 {
                    Contact = (string)ContactRow,
                    Phone1 = (string)PHONE1Row
                 };

Or With Method Syntax:-

 var result = xdoc.Root.Elements("data")
                  .Select(x =>
                       {
                           var ContactRow = x.Elements("data")
                            .FirstOrDefault(z => (string)z.Attribute("name") == "CONTACT");
                           var PHONE1Row = x.Elements("data")
                            .FirstOrDefault(z => (string)z.Attribute("name") == "PHONE1");
                           return new
                                  {
                                     Contact = (string)ContactRow,
                                     Phone1 = (string)PHONE1Row
                                  };
                       });

1 Comment

I could not get this to work. It may be because the XML that comes before the snippet I posted is also all formatted with "data" elements. But the snippet I posted was the "relevant" part of the XML and the solution that worked (and I accepted) wasn't confused by that.
0

Or try this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using System.Xml.Linq;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string xml =
                "<data name=\"Rows\">" +
                   "<data Name=\"Row\">" +
                     "<data name=\"CONTACT\">John Smith</data>" +
                     "<data name=\"PHONE1\">(555)123-4567</data>" +
                   "</data>" +
                   "<data Name=\"Row\">" +
                     "<data name=\"CONTACT\">Jim Smith</data>" +
                     "<data name=\"PHONE1\">(555)123-6754</data>" +
                   "</data>" +
                "</data>";

            XElement doc = XElement.Parse(xml);

            var results = doc.Descendants().Where(x => (string)x.Attribute("Name") == "Row").Select(x => new {
               contact = x.Elements().Where(y => (string)y.Attribute("name") == "CONTACT").FirstOrDefault().Value,
               phone = x.Elements().Where(y => (string)y.Attribute("name") == "PHONE1").FirstOrDefault().Value,
            }).ToList();
        }
    }
}
​

Comments

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.