Daily Archives: January 20, 2014
XML (part 2, basics), embedded, XDocument, XmlDocument, XmlTextReader, XPathNavigator
Posted by Bastian M.K. Ohta
We covered basic file IO for XML files yesterday. This is very useful for settings files. There are some XML files though that you want to hide from the user. I am not talking about encryption. Today we are going to embed the XML file the project itself.
We are still using yesterday’s “Walmart.xml” example. Create a folder “XmlFiles” in your Solution Explorer and drag the file into it.
Now right-click the file “Walmart.xml” and select “Properties”. Change the “Build Action” to “Embedded Resource”.
Use the following code to load the resource as an XDocument:
// since .Net 3.5 // namespace System.Xml.Linq // xPath: namespace.folder.file.ext => here: "DemoApp.XmlFiles.Walmart.xml" public static XDocument getAssemblyXDocument(string xPath) { Assembly lAssembly = Assembly.GetExecutingAssembly(); using (Stream lStream = lAssembly.GetManifestResourceStream(xPath)) { XDocument lXDocument = XDocument.Load(lStream); return lXDocument; } } //
You can also load the document as an XmlDocument.
// since .Net 1.1 // namespace System.Xml // xPath: namespace.folder.file.ext => here: "DemoApp.XmlFiles.Walmart.xml" public static XmlDocument getAssemblyXml(string xPath) { Assembly lAssembly = Assembly.GetExecutingAssembly(); using (Stream lStream = lAssembly.GetManifestResourceStream(xPath)) { XmlDocument lXmlDocument = new XmlDocument(); lXmlDocument.Load(lStream); return lXmlDocument; } } //
public static void LoadXmlExample() { string lPath = "DemoApp.XmlFiles.Walmart.xml"; XmlDocument lXml = getAssemblyXml(lPath); XDocument lXDoc = getAssemblyXDocument(lPath); } //
Using an XmlDocument is similar to XDocument. XmlDocument does not support LINQ, which is a big disadvantage.
XmlDocument reads the entire document and initializes a tree structure, which needs a lot of memory. Processing bigger Xml files can cause issues. The tree can be accessed either by browsing through the nodes or by using XPath queries.
You can browse through documents forward/backward and carry out modifications.
XDocument (LINQ to XML) is easy to code and understand. Again the entire document is loaded into memory. To read Xml files we can use the XDocument or XElement class. Both classes support Load() methods. XElement represents an XML fragment while XDocument represents an entire XML document.
XmlTextReader is very fast and memory efficient. Unlike XmlDocument it can only read in forward direction. Searching for something specific is awkward. As the name says, there is no method to write or to modify data. And data validation is also left behind.
XPathNavigator is more complex and slower than XmlReader. XPathNavigator has to read enough data to be able to execute XPath queries. XmlDocument internally uses XPathNavigator. Using XPathNavigator directly is faster than using it via XmlDocument.
Using XmlTextReader:
public static void UseTextReader() { string lPath = "DemoApp.XmlFiles.Walmart.xml"; Assembly lAssembly = Assembly.GetExecutingAssembly(); using (Stream lStream = lAssembly.GetManifestResourceStream(lPath)) { using (XmlTextReader lXmlReader = new XmlTextReader(lStream)) { while (lXmlReader.Read()) { if (!lXmlReader.IsStartElement()) continue; switch (lXmlReader.Name) { case "name": Console.WriteLine("name: " + lXmlReader.ReadString()); break; case "price": Console.WriteLine("price: " + lXmlReader.ReadString()); break; case "description": Console.WriteLine("description: " + lXmlReader.ReadString()); break; case "somethingElse": Console.WriteLine("somethingElse: " + lXmlReader.ReadString()); break; default: Console.WriteLine(Environment.NewLine + lXmlReader.Name); break; } } } } Console.ReadLine(); } //
example output:
Walmart
food
name: Banana
price: 1.99
description: Mexican deliciousfood
name: Rice
price: 0.79
description: the best you can getfood
name: Cornflakes
price: 3.85
description: buy some milkfood
name: Milk
price: 1.43
description: from happy cowselectronic
name: Kindle fire
price: 100
description: Amazon loves you
somethingElse: the perfect Xmas gift for your kidsfood
name: baked beans
price: 1.35
description: very British
Using XPathNavigator:
public static void UseXPathNavigator() { string lPath = "DemoApp.XmlFiles.Walmart.xml"; Assembly lAssembly = Assembly.GetExecutingAssembly(); using (Stream lStream = lAssembly.GetManifestResourceStream(lPath)) { XPathDocument lXPathDoc = new XPathDocument(lStream); XPathNavigator lXNavi = lXPathDoc.CreateNavigator(); lXNavi.MoveToRoot(); lXNavi.MoveToFirstChild(); do { if (lXNavi.MoveToFirstAttribute()) { Console.WriteLine(lXNavi.Name + "=" + lXNavi.Value); lXNavi.MoveToParent(); } if (!lXNavi.MoveToFirstChild()) continue; do { if (!lXNavi.MoveToFirstChild()) break; do { Console.WriteLine(lXNavi.Name + "=" + lXNavi.Value); } while (lXNavi.MoveToNext()); Console.WriteLine(); lXNavi.MoveToParent(); } while (lXNavi.MoveToNext()); lXNavi.MoveToParent(); } while (lXNavi.MoveToNext()); Console.ReadLine(); } } //
example output:
name=Banana
price=1.99
description=Mexican deliciousname=Rice
price=0.79
description=the best you can getname=Cornflakes
price=3.85
description=buy some milkname=Milk
price=1.43
description=from happy cowsname=Kindle fire
price=100
description=Amazon loves you
somethingElse=the perfect Xmas gift for your kidsname=baked beans
price=1.35
description=very British
Using XPathNavigator with query:
public static void UseXPathNavigator(string xQuery) { string lPath = "DemoApp.XmlFiles.Walmart.xml"; Assembly lAssembly = Assembly.GetExecutingAssembly(); using (Stream lStream = lAssembly.GetManifestResourceStream(lPath)) { XPathDocument lXPathDoc = new XPathDocument(lStream); XPathNavigator lXNavi = lXPathDoc.CreateNavigator(); XPathNodeIterator lIterator = lXNavi.Select(xQuery); if (lIterator.Count <= 0) { Console.WriteLine("Nothing found!"); return; } while (lIterator.MoveNext()) { Console.WriteLine(lIterator.Current.Value); } } } // public static void TestQueries() { UseXPathNavigator(@"/Walmart/electronic"); Console.WriteLine(); UseXPathNavigator(@"/Walmart/food[name='Banana']"); Console.ReadLine(); } //
example output:
Kindle fire100Amazon loves youthe perfect Xmas gift for your kidsBanana1.99Mexican delicious
My opinion is: Make use of LINQ to XML. It is very comfortable and can save you a lot of time. If you have a lot of data, then you should consider a database rather than XML files.
We will discuss XML object serialization tomorrow. Let C# save and load objects the nice way.
Posted in Advanced, Basic, C#, XML
Tags: C#, C-sharp, CSharp, embedded, Lambda, LINQ, programming, Source code, XDocument, XElement, XML, XmlDocument, XmlTextReader, XPathNavigator