简体   繁体   中英

Getting XML data from attributes in C#

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.????;
}

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.

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
                                  };
                       });

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();
        }
    }
}
​

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM