Some apps, especially apps used with existing systems, need to be able to parse and generate XML.
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>
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:
System.Xml.Linq.dll
reference.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; }
book
, all we have to do is execute the following code:var books = root.Elements("book");
Elements()
methods:var authors = root .Elements("book") .Elements("authors") .Elements("author");
var titles = from book in root.Elements("book") from title in book.Attributes("title") select title.Value;
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:
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")))));
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))));
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.
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.
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.
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.