Posted by: Cirilo Meggiolaro | 01/17/2009

Tip of the day #95 – Querying a XML file with LINQ to XML

Let’s check today how to load a XML file with purchase orders and loop through its nodes to display the order information.

XML example file

The following is a simple purchase order XML file to be used in our code:

<?xml version=1.0 encoding=utf-8 ?>

<Orders>

  <Order OrderNumber=1 CustomerNumber=5543 OrderDate=18/01/2009 7:45:21 Branch=23>

    <Items>

      <Item ItemNumber=1>

        <ProductName>Wireless Mouse</ProductName>

        <Quantity>1</Quantity>

        <UnitPrice>123.33</UnitPrice>

      </Item>

      <Item ItemNumber=2>

        <ProductName>Photo Paper</ProductName>

        <Quantity>5</Quantity>

        <UnitPrice>12.33</UnitPrice>

      </Item>

      <Item ItemNumber=3>

        <ProductName>22″ LCD Monitor</ProductName>

        <Quantity>1</Quantity>

        <UnitPrice>499.99</UnitPrice>

      </Item>

    </Items>

  </Order>

</Orders>

 

XElement class

 

The XElement class is the main object you need to perform this task. To create a new XML file or to load an existing one, the XElement class is the start point to achieve your goals. It’s the one that holds the XML file content.

 

For our example, we are going to load an existing XML file using the static method Load available under the XElement class as described below:

 

public static XElement Load(string uri);

public static XElement Load(TextReader textReader);

public static XElement Load(XmlReader reader);

public static XElement Load(string uri, LoadOptions options);

public static XElement Load(TextReader textReader, LoadOptions options);

public static XElement Load(XmlReader reader, LoadOptions options);

 

Descendants method

 

The Descendants method is used to filter results and retrieve a collection of elements based on a start element node or document. The items are retrieved in the document order. There are two overloads available:

 

public IEnumerable<XElement> Descendants();

public IEnumerable<XElement> Descendants(XName name);

 

If you want to search an order by the “OrderName” attribute, you need to search at the Order level, right? So, if you have the XML file loaded you need to invoke the Descendants method passing the element name “Order” so you may start filtering by that level. If you want to search the order details, from the order element level you need to invoke the Descendants method passing the element name “Item” as parameter and so on.

 

Attributes and Elements

 

The XElement class contains several collections of objects and methods to get or set attribute and element values. You may access the attribute or element by its name (called XName) and access the Value property as the following overloads and code snippet demonstrate:

 

public XAttribute Attribute(XName name);

public XElement Element(XName name);

 

order.Attribute(“OrderNumber”).Value;

item.Element(“ProductName”).Value;

 

Having all this information in mind we can have a console application that loads a XML file and based on a user input, search an order and display its details. The code is commented and must be similar to the following:

 

        /// <summary>

        /// Console application entry point method.

        /// </summary>

        /// <param name=”args”></param>

        static void Main(string[] args)

        {

            /// Stores the order id typed by the user.

            int orderID = 0;

 

            /// Displays a message to the user

            /// to enter the order number.

            Console.WriteLine(“Enter the order number and press Enter:”);

 

            /// Check if the order id is a valid integer

            /// before invoke the search method. Even though

            /// the searches and values in the XML file are

            /// based on strings, this check is just to make

            /// sure that a numeric type has been entered by

            /// the user.

            if (int.TryParse(Console.ReadLine(), out orderID))

            {

                /// Search order.

                SearchOrder(orderID);

            }

        }

 

        #region SearchOrder

        /// <summary>

        /// Search a purchase order.

        /// </summary>

        /// <param name=”orderID”>Order ID.</param>

        private static void SearchOrder(int orderID)

        {

            /// Loads the xml file.

            XElement xml = XElement.Load(@”Orders.xml”);

 

            if (xml != null)

            {

                /// Search an order within the orders collection

                /// using Descendants method to go down until the

                /// order level and execute the check against the

                /// attribute OrderNumber.

                var order = (from o in xml.Descendants(“Order”)

                             where o.Attribute(“OrderNumber”).Value == orderID.ToString()

                             select o).First();

 

                /// If an order has been found,

                /// invoke the DisplayOrder method

                /// to display its information.

                if (order != null)

                    DisplayOrder(order);

                else

                    Console.WriteLine(“Order number {0} not found.”, orderID);

            }

            else

                Console.WriteLine(“Orders XML file could not be loaded.”);

        }

        #endregion

 

        #region DisplayOrder

        /// <summary>

        /// Display the order attributes.

        /// </summary>

        /// <param name=”order”>XElement order object.</param>

        private static void DisplayOrder(XElement order)

        {

            /// Checks if the XElement is

            /// a valid instance.

            if (order != null)

            {

                /// Display purchase order header information

                Console.WriteLine(“Order number: {0}”, order.Attribute(“OrderNumber”).Value);

                Console.WriteLine(“Customer number: {0}”, order.Attribute(“CustomerNumber”).Value);

                Console.WriteLine(“Order date: {0}”, order.Attribute(“OrderDate”).Value);

                Console.WriteLine(“Branch: {0}”, order.Attribute(“Branch”).Value);

 

                /// Invoke a method to display the order items.

                DisplayOrderItems(order.Descendants(“Item”));

            }

        }

        #endregion

 

        #region DisplayOrderItems

        /// <summary>

        /// Display the order items.

        /// </summary>

        /// <param name=”orderItems”>IEnumerable XElement object.</param>

        private static void DisplayOrderItems(IEnumerable<XElement> orderItems)

        {

            /// Check if the collection is a valid instance

            /// and whether there are order items available.

            if ((orderItems != null) && (orderItems.Count() > 0))

            {

                Console.WriteLine(“Order items:”);

 

                /// Loop through the IEnumerable object to

                /// display the order items information.

                foreach (var item in orderItems)

                {

                    Console.WriteLine(“Product name: {0}”, item.Element(“ProductName”).Value);

                    Console.WriteLine(“Quantity: {0}”, item.Element(“Quantity”).Value);

                    Console.WriteLine(“Unit price: {0}”, item.Element(“UnitPrice”).Value);

                }

            }

            else

                Console.WriteLine(“No items available for the order.”);

        }

        #endregion


Responses

  1. Needing this now… Thanks!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Categories

%d bloggers like this: