Friday, October 21, 2011

Adding new nodes into XML document using LINQ

Today example using LINQ with xml, will be used to show example to add new elements in the XML document and to update the existing values of the element nodes.

Using the .Net earlier classes XmlDocument, XmlTextReader,XPathNavigator etc, bulky code was required to traverse through the XML nodes and finding out the node we wanted to modify. But with the help of LINQ, traversing through the XML document is really easy.

Basic definitions:-

a) XDocument class - Represents an XML document.
b) XElement class- Represents an XML element.
c) XDocument.Load method - Creates a new XDocument from a file specified by a URI, 
    from an TextReader, or from an XmlReader.

Lets start the example to see how modifying and addition of nodes can be achieved with the help of LINQ.

Step 1:-

From my previous example i have copied here the same XML document customer.xml file, which contains the details about the customer. Ex:- Name, CompanyName, JobTitle etc.



<?xml version="1.0" encoding="utf-8" ?>
<Customers>
  <Customer Id="1">
    <Name>B. K. Mishra</Name>
    <CompanyName>FIC Limited</CompanyName>
    <JobTitle>Sales Representative</JobTitle>
    <Address>1st Block, 19th cross,sector 7</Address>
    <City>Bangalore</City>
    <Country>India</Country>
    <Fax>080-98765457</Fax>
    <EmailId>B.k.mishra@fic.com</EmailId>
  </Customer>
  <Customer Id="2">
    <Name>A. K. Mitra</Name>
    <CompanyName>Sourcesoft Ltd</CompanyName>
    <JobTitle>Maketing Manager</JobTitle>
    <Address>Building no-10, second floor,1st block</Address>
    <City>Delhi</City>
    <Country>India</Country>
    <Fax>011-23456789</Fax>
    <EmailId>AKMitra@sourcesoft.com</EmailId>
  </Customer>
  <Customer Id="3">
    <Name>S. Reddy</Name>
    <CompanyName>Edge solution</CompanyName>
    <JobTitle>Sales Representative</JobTitle>
    <Address>Raheja arcade,3rd floor, sector 1</Address>
    <City>Bangalore</City>
    <Country>India</Country>
    <Fax>080-22224455</Fax>
    <EmailId>SReddy@EdgeSol.com</EmailId>
  </Customer>
  <Customer Id="4">
    <Name>K. Manakotte</Name>
    <CompanyName>Info Ltd</CompanyName>
    <JobTitle>Marketing Manager</JobTitle>
    <Address>Citi tower, MG Road</Address>
    <City>Bangalore</City>
    <Country>India</Country>
    <Fax>080-20224554</Fax>
    <EmailId>k.manakotte@info.com</EmailId>
  </Customer>
</Customers>

Step 2:-

Now i will be writing the code in code behind file to load the xml document and then to add element to the existing xml tree.

XDocument xDoc = XDocument.Load("Customers.xml");
//retrieving the maximum value of Id attribute from the customer node 
var maxID = (from p in xDoc.Descendants("Customer")
                        select p.Attribute("Id").Value).Max();

//incrementing the ID value by 1
int newID = Convert.ToInt16(maxID)+1;

//creating a new customer element with Id attribute having newly created Id value
// then creating all the child elementes with respected value to each node
XElement xeCustomer = new XElement("Customer"new XAttribute("Id", newID + 1), 
                                                                   new XElement("Name""Stephen Smith"),
                                                                   new XElement("CompanyName""Nous System"),
                                                                   new XElement("JobTitle""Marketing Manager"), 
                                                                   new XElement("Address""Sky arcade,Karol Bagh"), 
                                                                   new XElement("City""Delhi"),
                                                                   new XElement("Country""India"), 
                                                                   new XElement("Fax""011-23455555"), 
                                                                   new XElement("EmailId""steve.smith@nous.com"));

//adding the newly created XElement to the xDoc object parent xml tree
xDoc.Element("Customers").Add(xeCustomer);

//Retrieving all the customer details from the xDoc
var customerList = from cust in xDoc.Descendants("Customer")
                                 select new
                                 {
                                     CustomerName = cust.Element("Name").Value,
                                     JobTitle = cust.Element("JobTitle").Value,
                                     Fax = cust.Element("Fax").Value,
                                     EmailId = cust.Element("EmailId").Value
                                 };

//displaying the customer details in the 
foreach (var cust in customerList)
{
    Console.WriteLine(cust.CustomerName + ";" + cust.JobTitle + ";" + cust.Fax + ";" + 
                                     cust.EmailId);
}

Output

After creation of new elements, the xDoc object can be passed to any database for record creation or can be used to write Xml document into a new file.

I hope this example has served the purpose of giving an idea on how to add new elements into the existing xml document using LINQ.

Happy coding....

Thursday, October 20, 2011

Reading XML values using LINQ

Today i will be using examples to show the ways to read XML nodes and attributes value using LINQ. Everyone is aware of the powerful features LINQ provides, and the best thing about LINQ is simple and easy way to use it.

Step 1:-

I have created a customer.xml file, which contains the details about the customer. Ex:- Name, CompanyName, JobTitle etc.

<?xml version="1.0" encoding="utf-8" ?>
<Customers>
  <Customer Id="1">
    <Name>B. K. Mishra</Name>
    <CompanyName>FIC Limited</CompanyName>
    <JobTitle>Sales Representative</JobTitle>
    <Address>1st Block, 19th cross,sector 7</Address>
    <City>Bangalore</City>
    <Country>India</Country>
    <Fax>080-98765457</Fax>
    <EmailId>B.k.mishra@fic.com</EmailId>
  </Customer>
  <Customer Id="2">
    <Name>A. K. Mitra</Name>
    <CompanyName>Sourcesoft Ltd</CompanyName>
    <JobTitle>Maketing Manager</JobTitle>
    <Address>Building no-10, second floor,1st block</Address>
    <City>Delhi</City>
    <Country>India</Country>
    <Fax>011-23456789</Fax>
    <EmailId>AKMitra@sourcesoft.com</EmailId>
  </Customer>
  <Customer Id="3">
    <Name>S. Reddy</Name>
    <CompanyName>Edge solution</CompanyName>
    <JobTitle>Sales Representative</JobTitle>
    <Address>Raheja arcade,3rd floor, sector 1</Address>
    <City>Bangalore</City>
    <Country>India</Country>
    <Fax>080-22224455</Fax>
    <EmailId>SReddy@EdgeSol.com</EmailId>
  </Customer>
  <Customer Id="4">
    <Name>K. Manakotte</Name>
    <CompanyName>Info Ltd</CompanyName>
    <JobTitle>Marketing Manager</JobTitle>
    <Address>Citi tower, MG Road</Address>
    <City>Bangalore</City>
    <Country>India</Country>
    <Fax>080-20224554</Fax>
    <EmailId>k.manakotte@info.com</EmailId>
  </Customer>
</Customers>

Step 2:

XDocument class represents a XML document. XDocument.Load method Creates a new System.Xml.Linq.XDocument object from a file.

(i) Following query will be used to retrieve all the customer details from the xml document
    
    //retrieving all the customer details
    var customerList =from cust in xDoc.Descendants("Customer")
                      select cust;
    foreach (var cust in customerList)
    {
      //writing output to the console output window
      Console.WriteLine(cust.Element("Name").Value + ";" +  
                        cust.Element("CompanyName").Value+";"+cust.Element("JobTitle").Value  
                        + ";"+cust.Element("Fax").Value + ";" +cust.Element("EmailId").Value
                       );
    }
  
  Output

(ii) In this query anonymous class will be used to retrieve all the customer details from the xml document.
     
     "Anonymous types typically are used in the select clause of a query expression to return a subset of the
   properties from each object in the source sequence."
     
     If we do not specify member names in the anonymous type, the compiler gives the 
     anonymous type members the same name as the property being used to initialize them.

    Using Anonymous type, custom name can be assigned to the properties to select values.

    var custList = from cust in xDoc.Descendants("Customer")
                             select new
                                {
                                    CustomerName = cust.Element("Name").Value,
                                    JobTitle = cust.Element("JobTitle").Value,
                                    Fax = cust.Element("Fax").Value,
                                    EmailId = cust.Element("EmailId").Value
                                };
    foreach (var cust in custList)
    {
        Console.WriteLine(cust.CustomerName+";"+cust.JobTitle+";"+cust.Fax+";"+
        cust.EmailId);
    }

   Output
(iii) Retrieving all the records where city=Bangalore
    
  var blrCustomer = from custList in xDoc.Descendants("Customer")
                                     where custList.Element("City").Value == "Bangalore"
                                     select new
                                     {
                                             CustomerName = custList.Element("Name").Value,
                                            JobTitle = custList.Element("JobTitle").Value,
                                            Fax = custList.Element("Fax").Value,
                                            EmailID = custList.Element("EmailId").Value
                                      };
    foreach (var cust in blrCustomer)
    {
         Console.WriteLine(cust.CustomerName + ";" + cust.JobTitle + ";" + cust.Fax + ";"
                                           cust.EmailID);
    }

    Output

(iv) Retrieving all the emailids from the xml document

    var custEmailIDList = from custList in xDoc.Descendants("Customer")
                                           select new {EmailID=custList.Element("EmailId").Value};

    foreach (var email in custEmailIDList)
    {
         Console.WriteLine(email.EmailID);
    }

   Output
(v) Counting the length of character in name and then retrieving the customer records        matching with the maximum value.
    
    var custLength = from custList in xDoc.Descendants("Customer")
                                   where custList.Element("Name").Value.Length== 
                                                               ( from n in xDoc.Descendants("Customer")
                                                                  orderby n.Element("Name").Value.Length descending
                                                                  select n.Element("Name").Value.Length).First()
                                  select new
                                             {
                                                     CustomerName = custList.Element("Name").Value,
                                                     JobTitle = custList.Element("JobTitle").Value,
                                                     Fax = custList.Element("Fax").Value,
                                                     EmailID = custList.Element("EmailId").Value
                                             };
   foreach (var cust in custLength)
   {
        Console.WriteLine(cust.CustomerName + ";" + cust.JobTitle + ";" + cust.Fax + ";"
                                         cust.EmailID);
   }

Output
As you can see from the output that only those names, of which length is matching with the name of maximum length is displayed in the output.

I hope these examples gives clear idea about LINQ to XML features.

Happy Coding.....