Confessions of a .NET Developer!

Basic Linq to XML operations

This post shall deal with Inserting, Deleting and Modifying XML data using Linq to XML.

Here is how the XML will look like:

<?xml version="1.0" encoding="utf-8" ?>
<access>
  <user id="149">
    <name>Tarun</name>
    <age>22</age>
    <company>ABC</company>
  </user>
  <user id="13">
    <name>Gagan</name>
    <age>23</age>
    <company>Birla</company>
  </user>
  <user id="45">
    <name>Sachin</name>
    <age>24</age>
    <company>Steria</company>
  </user>
</access>

Add this XML to your project or create one using the XML Editor and set its Build Action to “Content” instead of Resource and also set Copy to Output Directory to “Copy if Newer”. With its build action set to content, I can modify the XML.

The code to Load the XML using the XDocument class under the namespace System.Xml.Linq

XDocument xDoc = XDocument.Load("XMLAccess.xml");
XElement rootElem = xDoc.Root;

And here is the way to Insert a new Record(User) into the XML :

            rootElem.Add(new XElement("user",
                new XAttribute("id", 90),
                new XElement("name", "Pulkit"),
                new XElement("age", 19),
                new XElement("company", "Infosys")));

            xDoc.Save("XMLAccess.xml");

Its quite simple using Linq, and a lot messier in case of the standard XmlDocument class.

The code to delete a User:

            XElement delElem = (from XElement elem in xDoc.Descendants("user")
                                where int.Parse(elem.Attribute("id").Value) == 90
                                select elem).Single<XElement>();

            delElem.Remove();
            xDoc.Save("XMLAccess.xml");

So the above Linq expression will return a single XElement of type user of id=90 and gets removed using a simple Remove() function.

And the code to update the XML :

            XElement updElem = (from XElement elem in xDoc.Descendants("age")
                                where int.Parse(elem.Parent.Attribute("id").Value)==45
                                select elem).Single<XElement>();

            updElem.SetValue(48);
            xDoc.Save("XMLAccess.xml");

That’s it for now. Happy coding.

Advertisements

May 4, 2011 Posted by | LINQ, XML | Leave a comment

Read Huge XML files faster

Most developers use the XmlDocument class to read XML files. LINQ has given us an excellent class XDocument which is much better than XmlDocument, inserting and deleting has become easy with XDocument. But both these classes are inefficient in handling huge XML files which are for example 500MB or 2-3 GB.

The problem is that once you load the XML using these classes, they store the whole XML in memory which eventually creates memory overheads. If you load these huge files into the memory then you might get an exception like this :
“System out of memory exception”.

So the solution for this will be to use XmlTextWriter and XmlTextReader class which is a stream-based XML reader rather than an in-memory XML reader.
These two classes read the XML node by node instead of loading the whole document. Its very much similar to using StreamWriter or StreamReader!

Lets take an example of creating an xml file from scratch.

        Dim filePath As String = "C:\Users\Tarun\Desktop\Prac.xml"
        Dim fs As FileStream = New FileStream(filePath, FileMode.Create, FileAccess.Write)
        Dim xtw As XmlTextWriter = New XmlTextWriter(fs, Text.Encoding.UTF8)

        xtw.Formatting = Formatting.Indented  ' Used so that it can be easily read while opening in Notepad
        xtw.Indentation = 4

        xtw.WriteStartDocument(True)
        xtw.WriteStartElement("Products")
        xtw.WriteComment("This is a comment")

        xtw.WriteStartElement("Product")
        xtw.WriteAttributeString("ID", "1")
        xtw.WriteAttributeString("Name", "Sony")

        xtw.WriteStartElement("Price")
        xtw.WriteString("40.33$")
        xtw.WriteEndElement()  'Closes the Price element
        xtw.WriteEndElement()  'Closes the Product element

        xtw.WriteStartElement("Product")
        xtw.WriteAttributeString("ID", "2")
        xtw.WriteAttributeString("Name", "Dell")

        xtw.WriteStartElement("Price")
        xtw.WriteString("80$")
        xtw.WriteEndElement()  'Closes the Price element
        xtw.WriteEndElement()  'Closes the Product element

        xtw.WriteEndElement()  'Closes the Products element
        'xtw.WriteEndDocument()
        xtw.Close()  'Close the XmlTextWriter stream
        fs.Close()  'Close the FileStream

The functions used are self-explanatory. But writing an XML file was not our purpose. Now lets read this XML.

        Using fs As FileStream = New FileStream(filePath, FileMode.Open, FileAccess.Read)

            Dim xtr As XmlTextReader = New XmlTextReader(fs)
            Dim writer As StringWriter = New StringWriter()
            'Read each and every node encountered
            While (xtr.Read())
                writer.Write("Type:")
                writer.Write(xtr.NodeType.ToString())

                If (xtr.Name <> "") Then
                    writer.Write("Name:")
                    writer.Write(xtr.Name)
                End If

                If (xtr.Value <> "") Then
                    writer.Write("Value:")
                    writer.Write(xtr.Value)
                End If

                If (xtr.AttributeCount > 0) Then
                    writer.Write("Attributes")
                    For i As Integer = 0 To xtr.AttributeCount - 1
                        writer.Write(" ")
                        writer.Write(xtr.GetAttribute(i))
                        writer.Write(" ")
                    Next
                End If

            End While

            Dim s As String = writer.ToString()
            Dim strm as StreamWriter = new StreamWriter("C:\HereisTheResult.txt",false);
            strm.Write(s); //Write the result to the txt file.

        End Using

April 8, 2011 Posted by | XML | Leave a comment