Parsing, processing, and generating XML

Some apps, especially apps used with existing systems, need to be able to parse and generate XML.

Getting ready

For this recipe, we need to have an existing XML file stored in the Assets folder. The structure of the XML file that we will use in this recipe is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<bookshelf>
  <book title="book title">
    <authors>
      <author firstname="name" lastname="surname"/>
      <author ... />
    </authors>
  </book>
  <book>...</book>
</bookshelf>

How to do it...

There are many ways to handle XML, but in this recipe, we will use Language-Integrated Query (LINQ) to XML. One of the most common things to do with XML is to read it, usually from a remote source. Let's take a look at the following steps:

  1. Ensure that the project includes the System.Xml.Linq.dll reference.
  2. In this instance, we will just read an asset and load it into an XDocument instance, keeping a reference to the root XElement:
    XElement root;
    using (var asset = Resources.Assets.Open("bookshelf.xml")) {
      XDocument doc = XDocument.Load(asset);
      root = doc.Root;
    }
  3. If we wish to access the child elements with the name book, all we have to do is execute the following code:
    var books = root.Elements("book");
  4. If we wish to select all the authors in all books (in this case, the elements three levels deep), we chain the Elements() methods:
    var authors = root
      .Elements("book")
      .Elements("authors")
      .Elements("author");
  5. We can also do SQL-like queries, for example, list all the values from the title attributes from all the books:
    var titles = from book in root.Elements("book")
                 from title in book.Attributes("title")
                 select title.Value;
  6. Even more advanced queries can be created using filtering, ordering, and even grouping:
    var longTitles = from title in root.Elements("book").Attributes("title")
      where title.Value.Length > 10
      orderby title.Value
      select title.Value;

In addition to parsing XML files, we can also easily create entire XML document structures with LINQ to XML using the XDocument, XElement, and XAttribute types:

  1. By chaining and nesting the various constructors, we can construct an XML document:
    var doc = new XDocument(
      new XElement("bookshelf",
        new XElement("book",
          new XAttribute("title", "C# 5.0 in a Nutshell"),
          new XElement("authors",
            new XElement("author", "Joseph Albahari"),
            new XElement("author", "Ben Albahari")))));
  2. We can also build entire documents by chaining constructors and nesting subqueries:
    var generatedDoc = new XDocument(
      new XElement("bookshelf",
        from book in root.Elements("book")
        select new XElement ("book", 
          new XAttribute("title",
            book.Attribute("title").Value),
          from author in
            book.Elements("authors").Elements("author")
          select
            new XElement("author",
              author.Attribute("lastname").Value))));

How it works...

Working with XML on Android with Java is very similar to using the XmlReader or XmlDocument type in the .NET world. It is relatively complex and does not always produce neat and maintainable code. Using .NET, we can make use of LINQ and LINQ to XML. This makes working with XML much easier when compared to what is needed when developing with Java.

LINQ extends the .NET languages by adding query expressions, which are similar to SQL statements and can be used to conveniently extract and process data from almost any type of data collection.

As XML is basically a collection of elements and attributes, we can use LINQ when working with XML. LINQ to XML enables us to query and modify XML documents from within any .NET language. It provides a new way to work with XML, which is more lightweight and easier to work with than the original XML readers and DOM models.

The most important advantage of LINQ to XML is that it enables us to write SQL-like queries on the in-memory XML document. This ability allows us to retrieve collections of elements and attributes, similar to what an XPath would allow us to do.

Note

LINQ to XML allows the creation and parsing of entire XML documents in memory in an easy-to-understand manner.

When working with LINQ to XML, an XDocument represents the entire document along with the metadata. An XElement object is an element in the XML document that has a Value object and has a collection of XAttribute and child XElement instances. We can access these types using the corresponding methods. If we want to access the collection of child elements, we use the Elements() method, which returns an IEnumerable instance of XElement.

Using IEnumerable means that LINQ to XML can make use of deferred execution and lazy evaluation. Deferred execution means that the evaluation of an expression or chain of methods is delayed until the value is actually required, such as when iterating through the collection. Deferred execution can greatly improve performance when we have to manipulate large data collections, especially when there is a series of chained queries or manipulations.

Note

LINQ to XML makes use of deferred loading where possible, thus improving performance on large documents and with complex queries.

Another advantage of LINQ to XML is the ability to use query results as parameters to XElement and XAttribute constructors, enabling us to construct entire document trees from queries and constructors. This approach of creating documents enables us to quickly and easily transform one XML tree structure into a totally new structure.

There's more...

If the XML document uses a default namespace, we need to ensure that all our queries include the namespace. For example, in a document without namespaces, we access elements by calling the Elements() method with the name of the element:

var elements = root.Elements("book");

If the document uses a namespace for those book elements, we also use a namespace:

XNamespace ns = "http://www.cookbook.com/samples/v1";
var elements = root.Elements(ns + "book");

When creating elements, we can also specify the namespace:

XNamespace ns = "http://www.cookbook.com/samples/v1";
var element = new XElement(ns + "book");

Namespaces can be used with any XML node, such as elements or attributes.

See also

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset