user3202862
user3202862

Reputation: 217

Reading XML Nodes

I have the following XML file. I am trying to read the startDate node of the dept element but don't want to read the "startDate" node of any of the rest of the child elements like "DeptRoles".

<dept operationalStatus="active" primaryRole="Admin" depChangeDate="20130420">      
    <startDate type="legal">20130401</startDate>
    <endDate type="legal"></endDate>
    <startDate type="operational">20130320</startDate>
    <endDate type="operational"></endDate>  
    <DeptRoles>         
        <DeptRole name="Other dept" status="active">
            <startDate type="legal">20130401</startDate>
            <endDate type="legal"></endDate>
            <startDate type="operational">20130320</startDate>
            <endDate type="operational"/>
            <isPrimary/>                
        </DeptRole>
    </DeptRoles>
</dept>

This is my c# code. This code is also getting the DeptRole startDate element, which I dont want.

public static List<organisation> Getorgdata(string data)
    {
        List<organisation> listorgdata = new List<organisation>();
        XmlReader xmlReader = XmlReader.Create(new StringReader(data));
        while (xmlReader.Read())
        {
            if (xmlReader.NodeType == XmlNodeType.Element)
            {
                organisation record = new organisation();
                if (xmlReader.HasAttributes && xmlReader.Name == "dept")
                {
                    record.orgOperationalStatus = xmlReader.GetAttribute("operationalStatus");
                    record.orgLegalStatus = xmlReader.GetAttribute("legalStatus");
                }
                else if (xmlReader.Name == "name")
                {
                    record.orgName = xmlReader.ReadElementString("name");
                }

                else if (xmlReader.Name == "startDate" || xmlReader.Name == "endDate")
                {
                    if (xmlReader.GetAttribute("type") == "legal")
                    {
                        record.orgLegalStartDate = xmlReader.ReadElementString("startDate");
                        record.orgLegalEndDate = xmlReader.ReadElementString("endDate");
                    }
                    else if (xmlReader.GetAttribute("type") == "operational")
                    {
                        record.orgOperationalStartDate = xmlReader.ReadElementString("startDate");
                        record.orgOperationalEndDate = xmlReader.ReadElementString("endDate");
                        listorgdata.Add(record);
                    }
                }
            }
        }
        return listorgdata;
    }

Upvotes: 0

Views: 98

Answers (4)

Thirisangu Ramanathan
Thirisangu Ramanathan

Reputation: 614

Try this :

var readSpecific = from a in xd.Descendants("departments")

                      select new
                      {

                          LegalStartDate = a.Element("dept").Elements("startDate").First(cc => cc.Attribute("type").Value == "legal").Value,
                          LegalEndDate = a.Element("dept").Elements("endDate").First(cc => cc.Attribute("type").Value == "legal").Value,

                          OperationalStartDate = a.Element("dept").Elements("startDate").First(cc => cc.Attribute("type").Value == "operational").Value,
                          OperationEndDate = a.Elements("dept").Elements("endDate").First(cc => cc.Attribute("type").Value == "operational").Value
                       };

Upvotes: 0

Tim
Tim

Reputation: 28520

I would use LINQ to XML (as others have suggested). Below is sample code that somewhat matches your posted code - explanation of the code follows.

public static List<organisation> Getorgdata(string data)
{

    List<organisation> listorgdata = new List<organisation>();
    XDocument xDoc = XDocument.Parse(data);

    listorgdata = xDoc.Root.Elements("dept")
                  .Select(x => new organisation()
                  {
                      orgOperationalStatus = (string)x.Attribute("operationalStatus"),
                      orgLegalStartDate = (string)x.Elements("startDate")
                                          .Where(x1 => (string)x1.Attribute("type") == "legal")
                                          .First(),
                      orgOperationalStartDate = (string)x.Elements("startDate")
                                                .Where(x1 => (string)x1.Attribute("type") == "operational")
                                                 .First()
                  }).ToList();

     return listorgdata;
}    

The first thing the above code does is load the XML into an XDocument with the XDocument.Parse method.

The query then parses the XML document and returns a list of populated organization objects. It goes something like this.

  1. Get all the <dept> elements (and the child elements).
  2. With each <dept> element, create a new instance of organisation and assign the value of the "operationalStatus" attribute to the operationalStatus property of organisation. The (string) cast will gracefully handle the situation where the specified attribute is not present.
  3. For the legal start date, we do a query on the <startDate> children of the <dept> element, taking the first one that has an attribute "type" equal to "legal".
  4. For the operational start date, we do a similar query to number 3, except it's looking for "operational".
  5. Convert the IEnumerabale<T> result to a list by calling the .ToList() extension method.

This may not be the most efficient, and it doesn't cover all the properties you have in your original code, but it should at least get you going in the right direction. For example, if you wanted to get the "primaryRole" attribute, you'd simply add the following line in the new organisation() block:

orgPrimaryRole = (string)x.Attribute("primaryRole"), 

If you need the data from <DeptRoles> you can get that to, but it's a little more involved.

If you prefer query syntax over method syntax, it would look like this:

listorgdata = (from x in xDoc.Root.Elements("dept")
               select new
                   {
                       orgOperationalStatus = (string)x.Attribute("operationalStatus"),
                       orgLegalStartDate = (from x1 in x.Elements("startDate")
                                            where (string)x1.Attribute("type") == "legal"
                                            select (string)x1).First(),
                        orgOperationalStartDate = (from x1 in x.Elements("startDate")
                                                   where (string)x1.Attribute("type") == "operational"
                                                   select (string)x1).First()
                    }).ToList();

Upvotes: 1

user3753166
user3753166

Reputation: 1

I'm not sure how to create a query that fits your needs exactly. Try to append this query to your needs. http://msdn.microsoft.com/en-us/library/bb387061.aspx contains some info on linq2xml queries

XmlReader xmlReader = XmlReader.Create(new StringReader(data));

XDocument d = XDocument.Load(xmlReader);

var startDates = from item in d.Root.Descendants()
                where item.Name == "startDate" && item.Parent.Name == "dept" && item.Parent.Attribute("deptid").Value == "anynumber"
                select item;

        // iterate over the startDates and do your magic

Upvotes: 0

Mehdi Souregi
Mehdi Souregi

Reputation: 3265

If I Add CATALOG

<CATALOG>
<dept operationalStatus="active" primaryRole="Admin" depChangeDate="20130420">      
<startDate type="legal">20130401</startDate>
<endDate type="legal"></endDate>
<startDate type="operational">20130320</startDate>
<endDate type="operational"></endDate>  
<DeptRoles>         
<DeptRole name="Other dept" status="active">
<startDate type="legal">20130401</startDate>
<endDate type="legal"></endDate>
<startDate type="operational">20130320</startDate>
<endDate type="operational"/>
<isPrimary/>                
</DeptRole>
</DeptRoles>
</dept>
</CATALOG>

by using System.Xml.Linq; You can get Your List :

XElement myXML = XElement.Load(@"C:\Users\User\Desktop\myXML.xml");
var deptDescendantsList = (from ep in myXML.Descendants("dept")
                           select ep.Elements("startDate")).ToList();

Upvotes: 0

Related Questions