Solved

Reading XML data using C#.NET Linq

Posted on 2008-09-29
12
6,269 Views
Last Modified: 2012-05-05
What is the easiest way to read through an XML document to get the values of each element in C#.NET? I am trying to use Linq but when i try to loop through each record i get a "Object reference not set to an instance of an object." error.

The document is an Order Request which may include several orders and each order has different BillTo, ShipTo, Line Item etc. sections.

The basic code I am using looks like this:

String xmlFile = @"D:\TestOrder.XML";
XDocument xDoc = XDocument.Load(xmlFile, LoadOptions.SetLineInfo);
var order = from orderRequest in xDoc.Descendants("OrderRequest")
                            select new
                            {
                                BillToCity = (string)orderRequest.Element("City").Value,
                            };
                foreach (var orderRequest in order)  // This is where the error occurs
                {
                    xmlTest = orderRequest.BillToCity;
                }

Any tips would be greatly appreciated. If there is an easier/quicker way to read through an XML file than using Linq that would help as well.

Thanks,
0
Comment
Question by:CRCInfosys
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 6
12 Comments
 
LVL 63

Expert Comment

by:Fernando Soto
ID: 22599542
Hi CRCInfosys;

The most likely cause of the error is due to the following line of code:

BillToCity = (string)orderRequest.Element("City").Value,

The reason for this is that the query returns a node that has other nodes as children in it and not all the nodes are of type "City" and therefore you get a null reference exception. Therefore you need to filter it so that it only has nodes of type "City".

If you post the XML file or a sample of it and also tell me what you need the results to look like I will be able to help more.

Fernando
0
 

Author Comment

by:CRCInfosys
ID: 22599805
FernandoSoto,

Thank you for the quick response. Sorry i forgot to attach the file i am using. I have attached it now so you can take a look. I have changed the extension to .txt so it would allow me to post it so you will have to change it to .xml.

The BilltoCity is only one node that I am trying to get. There are several SubElements that i am trying to access. That wsa just an example and i can see what your saying about the query bringing back other data as well.

Thanks,
TestOrder.txt
0
 
LVL 63

Expert Comment

by:Fernando Soto
ID: 22600594
Hi CRCInfosys;

The following snippet should work for you.

Fernando

String xmlTest = "";
XElement xElements = XElement.Load("TestOrder.xml");
 
var order = from orderRequest in xElements.Descendants("BillTo")
            // Get the City elements of the BillTo elements
            let city = orderRequest.Descendants("City")
            // Get the first and only City Element
            where city.First().Name == "City"
            // Parse out the City name as a String
            select new { City = city.First().Value };
 
foreach (var orderRequest in order)  // This is where the error occurs
{
    xmlTest += orderRequest.City + "\n";
}
 
Console.WriteLine(xmlTest);

Open in new window

0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:CRCInfosys
ID: 22600650
FernandoSoto,

Thanks again for the help. The code snippet given will work for simply getting the City, but is there a way to get all of the elements (such as City State Zip, Line Item Quantity, Price, Shipping Addresses) at once or does this code snippet need to be done for each element?

thanks,
0
 
LVL 63

Expert Comment

by:Fernando Soto
ID: 22601612
Hi CRCInfosys;

This will show you how to do that. Just follow the same pattern to select other nodes.

Fernando

String xmlTest = "";
XElement xElements = XElement.Load("TestOrder.xml");
 
var order = from orderRequest in xElements.Descendants("OrderRequest")
            let reqHeader = orderRequest.Element("OrderRequestHeader")
            let billTo = reqHeader.Element("BillTo")
            let billToAddress = billTo.Element("Address")
            let billToPostalAddress = billToAddress.Element("PostalAddress")
            let billToCity = billToPostalAddress.Element("City")
            let billToState = billToPostalAddress.Element("State")
            let billToPostalCode = billToPostalAddress.Element("PostalCode")
            let itemOut = orderRequest.Element("ItemOut")
            let shipTo = itemOut.Element("ShipTo")
            let shipToAddress = shipTo.Element("Address")
            let shipToPostalAddress = shipToAddress.Element("PostalAddress")
            let shipToCity = shipToPostalAddress.Element("City")
            let shipToState = shipToPostalAddress.Element("State")
            let shipToPostalCode = shipToPostalAddress.Element("PostalCode")
            select new
            {
                BillToCity = billToCity.Value,
                BillToState = billToState.Value,
                BillToPostalCode = billToPostalCode.Value,
                ShipToCity = shipToCity.Value,
                ShipToState = shipToState.Value,
                ShipToPostalCode = shipToPostalCode.Value
            };
 
foreach (var orderRequest in order)  // This is where the error occurs
{
    xmlTest += orderRequest.BillToCity + " - " + orderRequest.BillToState + " - " + orderRequest.BillToPostalCode + "\n";
    xmlTest += orderRequest.ShipToCity + " - " + orderRequest.ShipToState + " - " + orderRequest.ShipToPostalCode + "\n";
}
 
Console.WriteLine(xmlTest);

Open in new window

0
 

Author Comment

by:CRCInfosys
ID: 22625561
Thank you Fernando, what you posted works out perfectly. A couple more questions, In the XML document I attached there are several Elements with the same tag such as the BillToor ShipTo Street fields. There are two of the fields there. Or in the ItemOut section there are several "Extrinsic Name" fields that are identified by different names such as "quantityMultiplier", "costCenter", "ProductSpecs" etc. How do i distinguish between them in my code?

Thanks again for all the help as everything you have given me is exactly what im looking for.
0
 
LVL 63

Expert Comment

by:Fernando Soto
ID: 22629294
Hi CRCInfosys;

Here is how to handle multiple items with the same name. The snippet uses a query within a query or just sub-query.

Fernando

String xmlTest = "";
XElement xElements = XElement.Load("TestOrder.xml");
 
var order = from orderRequest in xElements.Descendants("OrderRequest")
            let reqHeader = orderRequest.Element("OrderRequestHeader")
            let billTo = reqHeader.Element("BillTo")
            let billToAddress = billTo.Element("Address")
            let billToPostalAddress = billToAddress.Element("PostalAddress")
            let billToCity = billToPostalAddress.Element("City")
            let billToStreet = billToPostalAddress.Elements("Street")					//New Line
            let billToState = billToPostalAddress.Element("State")
            let billToPostalCode = billToPostalAddress.Element("PostalCode")
            let itemOut = orderRequest.Element("ItemOut")
            let shipTo = itemOut.Element("ShipTo")
            let shipToAddress = shipTo.Element("Address")
            let shipToPostalAddress = shipToAddress.Element("PostalAddress")
            let shipToStreet = shipToPostalAddress.Elements("Street")					//New Line
            let shipToCity = shipToPostalAddress.Element("City")
            let shipToState = shipToPostalAddress.Element("State")
            let shipToPostalCode = shipToPostalAddress.Element("PostalCode")
            let itemDetail = itemOut.Element("ItemDetail")										//New Line
            let extrinsic = itemDetail.Elements("Extrinsic")									//New Line
            select new
            {
                BillToStreet = (from str in billToStreet							  			//New Line
                                select str.Value).ToList(),
                BillToCity = billToCity.Value,
                BillToState = billToState.Value,
                BillToPostalCode = billToPostalCode.Value,
                ShipToStreet = (from str in shipToStreet											//New Line
                                select str.Value).ToList(),
                ShipToCity = shipToCity.Value,
                ShipToState = shipToState.Value,
                ShipToPostalCode = shipToPostalCode.Value,
                Extrinsic = (from ext in extrinsic				  									//New Line
                             select (ext.Attribute("name").Value + " : " + ext.Value)).ToList()
            };
 
foreach (var orderRequest in order)  // This is where the error occurs
{
    xmlTest += GetStreetParts(orderRequest.BillToStreet) + " - " + 
                orderRequest.BillToCity + " - " + orderRequest.BillToState + " - " + 
                orderRequest.BillToPostalCode + "\n\n";
    xmlTest += GetStreetParts(orderRequest.ShipToStreet) + " - " + 
                orderRequest.ShipToCity + " - " + orderRequest.ShipToState + " - " + 
                orderRequest.ShipToPostalCode + "\n\n";
    xmlTest += GetExtrinsicParts(orderRequest.Extrinsic);
    xmlTest += "\n===============================================\n";
 
}
 
Console.WriteLine(xmlTest);
 
// New code to handle the multiple line returns in the new items
private String GetStreetParts(List<String> street)
{
    String retString = String.Empty;
    foreach (String str in street)
    {
        retString += str + "; ";
    }
    if (retString.Length > 1)
    {
        retString = retString.Substring(0, retString.Length - 2);
    }
 
    return retString;
}
 
private String GetExtrinsicParts(List<String> extrinsic)
{
    String retString = String.Empty;
    foreach (String ext in extrinsic)
    {
        retString += ext + "\n";
    }
    if (retString.Length > 1)
    {
        retString = retString.Substring(0, retString.Length - 2);
    }
 
    return retString;
}

Open in new window

0
 

Author Comment

by:CRCInfosys
ID: 22652371
Fernando,

Thanks again as that is helping out very much. A couple more questions, I am not able to get the value of the "orderType" attribute from the OrderRequestHeader in the xml document. When i try to return the value i get the same error as before (Object reference not set to an instance of an object). Do you know what that would be or how i can get that value? Also when i originally wrote the test code for you to look at i simply had one variable xmlTest. In fact, i have a different variable for each value. With that in mind can you return an array or list of data using LINQ so i can get individual values? such as: strStreet1 = BillToStreet1.Value,
strStreet2 = BillToStreet2.Value,

Also can i do that as well with the Extrinsic fields so i can set different values based on the tag? For example setting different variables equal to the Extrinsic name "PaymentType" and Extrinsic name "PaymentSource" in the OrderRequestHeader. And going off of that, how would i access the "PaymentType" and "Amount" values from the "PaymentSource" section?

Thank you so much for all your help.

0
 

Author Comment

by:CRCInfosys
ID: 22652493
Please disregard the question about the array concerning the Streets as that is simple and i have that already sorry. However i still am not sure how to get the array or list of values for the extrinsic values.

Thanks,
0
 
LVL 63

Accepted Solution

by:
Fernando Soto earned 500 total points
ID: 22654011
Hi CRCInfosys;

To your question, "am not able to get the value of the "orderType" attribute from the OrderRequestHeader in the xml document. When i try to return the value i get the same error as before (Object reference not set to an instance of an object). Do you know what that would be or how i can get that value?", see the posted code. Basically you add another Let local variable that references that node in the documnet and then in the select clause place it in the list that will be returned and the error message always means that the object you wanted to create or get was not created or never existed.

To your question, "Also can i do that as well with the Extrinsic fields so i can set different values based on the tag? ", I rewrote the Extrinsic field format so that it returns back a structure of Extrinsic with two fields the attribute and its value see code.

To the question, "the Extrinsic name "PaymentType" and Extrinsic name "PaymentSource" in the OrderRequestHeader." to get that information you build a local variable as shown in the next line:

let reqHeaderExtrinsic = orderRequest.Element("Extrinsic")

That will get you a reference to the Extrinsic nodes in the OrderRequestHeader node. Then in the select clause you select the information as I did for the other Extrinsic node in the other part of the document.

Fernando


// To create a concreate data type for use in linq to store 
// Attribute and its value
private struct Extrinsic
{
    public String attribute;
    public String value;
}
 
private void button5_Click(object sender, EventArgs e)
{
    String xmlTest = "";
    XElement xElements = XElement.Load("TestOrder.xml");
 
    var order = from orderRequest in xElements.Descendants("OrderRequest")
                let reqHeader = orderRequest.Element("OrderRequestHeader")
                let billTo = reqHeader.Element("BillTo")
                let billToAddress = billTo.Element("Address")
                let billToPostalAddress = billToAddress.Element("PostalAddress")
                let billToCity = billToPostalAddress.Element("City")
                let billToStreet = billToPostalAddress.Elements("Street")
                let billToState = billToPostalAddress.Element("State")
                let billToPostalCode = billToPostalAddress.Element("PostalCode")
                let itemOut = orderRequest.Element("ItemOut")
                let shipTo = itemOut.Element("ShipTo")
                let shipToAddress = shipTo.Element("Address")
                let shipToPostalAddress = shipToAddress.Element("PostalAddress")
                let shipToStreet = shipToPostalAddress.Elements("Street")
                let shipToCity = shipToPostalAddress.Element("City")
                let shipToState = shipToPostalAddress.Element("State")
                let shipToPostalCode = shipToPostalAddress.Element("PostalCode")
                let itemDetail = itemOut.Element("ItemDetail")
                let extrinsic = itemDetail.Elements("Extrinsic")
                select new
                {
                    // The next three lines are new
                    RequestHeaderOrderID = reqHeader.Attribute("orderID").Value,
                    RequestHeaderOrderDate = reqHeader.Attribute("orderDate").Value,
                    RequestHeaderType = reqHeader.Attribute("type").Value,
                    BillToStreet = (from str in billToStreet
                                    select str.Value).ToList(),
                    BillToCity = billToCity.Value,
                    BillToState = billToState.Value,
                    BillToPostalCode = billToPostalCode.Value,
                    ShipToStreet = (from str in shipToStreet
                                    select str.Value).ToList(),
                    ShipToCity = shipToCity.Value,
                    ShipToState = shipToState.Value,
                    ShipToPostalCode = shipToPostalCode.Value,
                    Extrinsic = (from ext in extrinsic
                                 select new Extrinsic { attribute = ext.Attribute("name").Value, value = ext.Value }).ToList()
                };
 
    foreach (var orderRequest in order)  // This is where the error occurs
    {
        // The next three lines are new
        xmlTest += "Order ID = " + orderRequest.RequestHeaderOrderID + "\n";
        xmlTest += "Order Date = " + orderRequest.RequestHeaderOrderDate + "\n";
        xmlTest += "Order Type = " + orderRequest.RequestHeaderType + "\n";
        xmlTest += GetStreetParts(orderRequest.BillToStreet) + " - " + 
                    orderRequest.BillToCity + " - " + orderRequest.BillToState + " - " + 
                    orderRequest.BillToPostalCode + "\n\n";
        xmlTest += GetStreetParts(orderRequest.ShipToStreet) + " - " + 
                    orderRequest.ShipToCity + " - " + orderRequest.ShipToState + " - " + 
                    orderRequest.ShipToPostalCode + "\n\n";
        xmlTest += GetExtrinsicParts(orderRequest.Extrinsic);
        xmlTest += "\n===============================================\n";
 
    }
 
    Console.WriteLine(xmlTest);
 
}
 
private String GetStreetParts(List<String> street)
{
    String retString = String.Empty;
    foreach (String str in street)
    {
        retString += str + "; ";
    }
    if (retString.Length > 1)
    {
        retString = retString.Substring(0, retString.Length - 2);
    }
 
    return retString;
}
 
private String GetExtrinsicParts(List<Extrinsic> extrinsic)
{
    String retString = String.Empty;
    foreach (Extrinsic ext in extrinsic)
    {
        retString += ext.attribute + " = " + ext.value + "\n";
    }
    if (retString.Length > 1)
    {
        retString = retString.Substring(0, retString.Length - 2);
    }
 
    return retString;

Open in new window

0
 

Author Closing Comment

by:CRCInfosys
ID: 31501268
Thank you very much for helping with all the questions. Everything you suggested worked as expected.

Thanks,
0
 
LVL 63

Expert Comment

by:Fernando Soto
ID: 22713021
Not a problem, glad I was able to help.  ;=)
0

Featured Post

Instantly Create Instructional Tutorials

Contextual Guidance at the moment of need helps your employees adopt to new software or processes instantly. Boost knowledge retention and employee engagement step-by-step with one easy solution.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

It was really hard time for me to get the understanding of Delegates in C#. I went through many websites and articles but I found them very clumsy. After going through those sites, I noted down the points in a easy way so here I am sharing that undeā€¦
This article aims to explain the working of CircularLogArchiver. This tool was designed to solve the buildup of log file in cases where systems do not support circular logging or where circular logging is not enabled
The viewer will learn how to implement Singleton Design Pattern in Java.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

739 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question