<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TiMoch &#187; xml</title>
	<atom:link href="https://timoch.com/blog/tag/xml/feed/" rel="self" type="application/rss+xml" />
	<link>https://timoch.com/blog</link>
	<description>on edge</description>
	<lastBuildDate>Tue, 29 Apr 2014 15:02:50 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>Testing XPathNavigator</title>
		<link>https://timoch.com/blog/2013/06/testing-xpathnavigator/</link>
		<comments>https://timoch.com/blog/2013/06/testing-xpathnavigator/#comments</comments>
		<pubDate>Mon, 03 Jun 2013 09:11:47 +0000</pubDate>
		<dc:creator><![CDATA[timoch]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[xpath]]></category>

		<guid isPermaLink="false">http://timoch.com/blog/?p=304</guid>
		<description><![CDATA[In my previous post about XPathNavigator, I explained in what circumstances the default implementation of XPathNavigator is troublesome. I went over the design of the class and highlighted how that design helps us re-implement XPathNavigator to address the issue. Testing XPathNavigator First things first, before attacking the new implementation proper, we want to make sure [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>In my <a title="So what’s wrong with XPathDocument ?" href="http://timoch.com/blog/2013/05/so-whats-wrong-with-xpathdocument/">previous post about XPathNavigator</a>, I explained in what circumstances the default implementation of XPathNavigator is troublesome. I went over the design of the class and highlighted how that design helps us re-implement XPathNavigator to address the issue.</p>
<h2>Testing XPathNavigator</h2>
<p>First things first, before attacking the new implementation proper, we want to make sure our implementation is compatible with the default implementation. To do so, we will write tests that will be run both against the Microsoft implementation as well as our implementation once it exists. Our goal here is really twofold. On the one hand, we want to ensure the existing implementation actually works as documented. On the other hand, we want to check our own implementation against the specification tests.</p>
<h3>What should we test ?</h3>
<p>XPathNavigator is a complex class. So we want to limit my tests to what actually matters for the new implementation. Otherwise, we may be writing literally hundreds of tests.</p>
<p>It is obviously not necessary to test methods that will not be re-implemented. In the previous post, we identified a subset of methods that we will need to re-implement. All other methods are somehow using this basic subset to implement their functionality. The subset is the list of abstract members:</p><pre class="crayon-plain-tag">public abstract string BaseURI { get; }
    public abstract bool IsEmptyElement { get; }
    public abstract string LocalName { get; }
    public abstract string Name { get; }
    public abstract string NamespaceURI { get; }
    public abstract XmlNameTable NameTable { get; }
    public abstract XPathNodeType NodeType { get; }
    public abstract string Prefix { get; }

    public abstract bool MoveTo(XPathNavigator other);
    public abstract bool MoveToFirstAttribute();
    public abstract bool MoveToFirstChild();
    public abstract bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope);
    public abstract bool MoveToId(string id);
    public abstract bool MoveToNext();
    public abstract bool MoveToNextAttribute();
    public abstract bool MoveToNextNamespace(XPathNamespaceScope namespaceScope);
    public abstract bool MoveToParent();
    public abstract bool MoveToPrevious();</pre><p>As you can see, we have two distinct groups:</p>
<ul>
<li><span style="line-height: 13px;">The abstract properties expose information about the current node. Our tests will ensure that we get consistent information for all types of node.<br />
</span></li>
<li>The abstract methods are all concerned about moving the navigator to another node. The tests need to check that the move operations result in the navigator pointing to the right node given a known starting position.</li>
</ul>
<h3>How should we test it ?</h3>
<p>We will test the properties by setting up a XPathNavigator that points to specific nodes of an xml document. Once setup, we simply check the properties expose consistent values. We will test the Move() operations in a very similar way. We will setup the XPathNavigator instance on a specific node, execute the Move() operation we want to test and then check that the XPathNavigator yields values through its properties that are consistent with the navigator&#8217;s new position.</p>
<p>This is actually very similar. The only difference is the Move() operation. The similarity will let us factor our most of the test code into a few utility functions.</p><pre class="crayon-plain-tag">private void CanMoveImpl(MoveTestArgs args, Func&lt;XPathNavigator, bool&gt; moveOperation) {
    CheckInconclusive(args);

    // Arrange - get a navigator on requested node
    var nav = CreateNavigatorOnSelected(args.Xml, args.InitialPosition);

    // Act - move thenode
    var success = moveOperation(nav);

    // Assert -- check if success consistent with ShouldSucceed
    Expect(success, args.ShouldSucceed ? (Constraint)True : False, "inconsistent success state");
    // Assert -- check node properties 
    ExpectNodeProperties(nav, args);
}</pre><p>CanMoveImpl() acts as a parametrized test. It takes 2 arguments:</p>
<ul>
<li><span style="line-height: 13px;">args: a MoveTestArgs instance. This argument describes the test&#8217;s original state and the resulting state we should test against.</span></li>
<li>moveOperation: A delegate to the Move() operation to test. Passing the operation to test as a parameter let us also write non-Move() tests by simply passing a no-op callback.</li>
</ul>
<p><em>NUnit: I am using NUnit to write the unit tests. It is only a matter of preference. You can adapt the tests to work against another testing framework such as <a href="http://msdn.microsoft.com/en-us/library/ms243147.aspx">Microsoft Unit Testing Framework</a>. I find NUnit to be simple to use, non-obstrusive and very flexible. </em></p>
<p>CanMoveImpl() is called by actual test methods like the following:</p><pre class="crayon-plain-tag">[TestCaseSource("CanMoveToNext_Source")]
public void CanMoveToNext(MoveTestArgs args) {
    CanMoveImpl(args, n =&gt; n.MoveToNext());
}</pre><p>It is a parametrized test. The TestCaseSource attribute tells NUnit which method to call to get the MoveTestArgs instance for each test.</p><pre class="crayon-plain-tag">public IEnumerable&lt;MoveTestArgs&gt; CanMoveToNext_Source() {
    yield return new MoveTestArgs() {
        Xml = @"&lt;root&gt;&lt;/root&gt;",
        InitialPosition = "/", // selects root
        ShouldSucceed = false
    };

    yield return new MoveTestArgs() {
        Xml = @"&lt;root&gt;&lt;child/&gt;&lt;/root&gt;",
        InitialPosition = "/root/child",
        ShouldSucceed = false
    };

    yield return new MoveTestArgs() {
        Xml = @"&lt;root&gt;&lt;child/&gt;&lt;child2/&gt;&lt;/root&gt;",
        InitialPosition = "/root/child",
        NodeType = XPathNodeType.Element,
        LocalName = "child2",
    };

    /* ... */
}</pre><p>Method CanmoveToNext_Source() returns each test case for a given operation. In the above example, we have the test cases for &#8220;when position on document root, MoveToNext() should fail&#8221;, &#8220;When positioned on element whith no next sibling, MoveToNext() should fail&#8221; and &#8220;when positioned on an element with a next sibling, MoveToNext() should succeed and point to the specific node&#8221;.</p>
<p>Each test case is defined by specifying values for the fields of class CanMoveArgs.</p><pre class="crayon-plain-tag">public class MoveTestArgs {
    // Xml document
    public string Xml;
    // XPath to select starting first position
    public string InitialPosition;

    // value to test against - no assertion for a given property when not set
    public string BaseURI;
    public bool? IsEmptyElement;
    public string LocalName;
    public string Name;
    public string NamespaceURI;
    public string NameTable;
    public XPathNodeType? NodeType;
    public string Prefix;
    public string Value;

    // Indicates whether the move should succeed or not
    public bool ShouldSucceed = true;

    // indicates whether the test is inconclusive
    public string Inconclusive;

    // TestCaseSource calls ToString() on each test case argument to create the test case name.
    public override string ToString() {
        if (ShouldSucceed)
            return string.Format("{0} -- {1} -- {2} -- {3}", Xml, InitialPosition, NodeType, LocalName);
        else
            return string.Format("{0} -- {1} -- fails", Xml, InitialPosition);
    }
}</pre><p>Method ExpectNodeProperties() implements the assertions depending on the configuration of its MoveTestArgs instance:</p><pre class="crayon-plain-tag">private void ExpectNodeProperties(XPathNavigator navigator, MoveTestArgs args) {
    if (args.LocalName != null) Expect(navigator.LocalName, EqualTo(args.LocalName), "bad localname");
    if (args.Name != null) Expect(navigator.Name, EqualTo(args.Name), "bad name");
    if (args.Prefix != null) Expect(navigator.Prefix, EqualTo(args.Prefix), "bad prefix");
    if (args.NamespaceURI != null) Expect(navigator.NamespaceURI, EqualTo(args.NamespaceURI), "bad namespace uri");
    if (args.NodeType != null) Expect(navigator.NodeType, EqualTo(args.NodeType), "bad node type");
    if (args.Value != null) Expect(navigator.Value, EqualTo(args.Value), "bad value");
}</pre><p></p>
<h3>Executing our tests</h3>
<p>We want our tests to be executed against the Microsoft implementation as well as our own implementation. The most straight-forward way of achieving this is to implement our tests in an abstract test fixture. The abstract fixture has an factory method to create an instance of XPathNavigator to test against. For each implementation, we create a subclass of our fixture and override the factory method.</p>
<p>CreateNavigable returns an IXPathNavigable. In turn IXpathNavigable lets us create a navigator positioned on the document root thanks to its CreateNavigator() method.</p><pre class="crayon-plain-tag">[TestFixture]
public abstract class XPathDocumentTests : AssertionHelper {
    protected abstract IXPathNavigable CreateNavigable(string xml);
    /* tests implementations */
}

public class MsXPathDocumentTests : XPathDocumentTests {
    protected override IXPathNavigable CreateNavigable(string xml) {
        TextReader textReader = new StringReader(xml);
        XmlReaderSettings settings = new XmlReaderSettings();
        settings.IgnoreWhitespace = false;
        XmlReader reader = XmlReader.Create(textReader, settings);
        return new XPathDocument(reader, XmlSpace.Preserve);
    }
}</pre><p>We&#8217;ll add the test fixture for our own implementation when we have the skeleton available. In the mean time, this lets us verify our expectations against the actual implementation of XPathNavigator.</p>
<p>The next post on the topic will tackle the new implementation&#8217;s design. I&#8217;ll make the implementation and test available as a source code download at the end of this series of articles.</p>
]]></content:encoded>
			<wfw:commentRss>https://timoch.com/blog/2013/06/testing-xpathnavigator/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>XPathDocument and whitespaces</title>
		<link>https://timoch.com/blog/2013/05/xpathdocument-and-whitespaces/</link>
		<comments>https://timoch.com/blog/2013/05/xpathdocument-and-whitespaces/#comments</comments>
		<pubDate>Fri, 24 May 2013 11:57:32 +0000</pubDate>
		<dc:creator><![CDATA[timoch]]></dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[xpath]]></category>

		<guid isPermaLink="false">http://timoch.com/blog/?p=287</guid>
		<description><![CDATA[Writing code is fun. At least it is for me. But sometimes it gets irritating. You know, you&#8217;re busy on something, you write the code, you know it&#8217;s right but it doesn&#8217;t work&#8230; You keep your focus on that one piece of code you just wrote and it keeps on not working. Sometimes, the reason [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Writing code is fun. At least it is for me. But sometimes it gets irritating. You know, you&#8217;re busy on something, you write the code, you know it&#8217;s right but it doesn&#8217;t work&#8230; You keep your focus on that one piece of code you just wrote and it keeps on not working. Sometimes, the reason it doesn&#8217;t work is obvious but sometimes, you keep reviewing your code, its surrounding, you debug away several variants of your solution and it keeps on not working &#8230;</p>
<p>I just had one of those moments&#8230;</p>
<p>And then, bang ! The solution jumps at me and it&#8217;s so obvious I almost felt shame <img src="https://timoch.com/blog/wp-includes/images/smilies/icon_neutral.gif" alt=":-|" class="wp-smiley" /> </p>
<p>I was writing the unit tests in preparation for my next article on creating a <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx">XPathNavigator</a> implementation. The code basically boils down to this:</p><pre class="crayon-plain-tag">TextReader textReader = new StringReader("&lt;root&gt;    &lt;/root&gt;");
XmlReaderSettings settings = new XmlReaderSettings();
settings.IgnoreWhitespace = false;
XmlReader reader = XmlReader.Create(textReader, settings);
XPathDocument doc = new XPathDocument(reader);
var nav = doc.CreateNavigator().SelectSingleNode("/root/text()");
var success = nav.MoveToParent();</pre><p>I am testing <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.movetoparent.aspx">MoveToParent()</a> from a whitespace node. <pre class="crayon-plain-tag">"/root/text()"</pre>  is expected to give me an <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx">XPathNavigator </a>located on the whitespace node inside the &lt;root&gt; element. And nav just keeps on being null. Since I had been busy writing pairs of xml samples and xpath queries to put my test in each situation I needed to test. I immediately assumed my xpath query was not correct. i just kept on tweaking here, there. nav is null still &#8230;</p>
<p>After some time, I decided to not put more effort into it and come back to it later, once I can take the necessary step back. I posted a question on <a href="http://stackoverflow.com/questions/16732622/select-whitespace-node-with-xpath-in-c-sharp">stackoverflow.com</a> and worked on something else.</p>
<p>I was busy on something completely different when it struck me. One of those &#8220;Haha&#8221; moments. <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathdocument.aspx">XPathDocument</a> has a constructor that takes a <a href="http://msdn.microsoft.com/en-us/library/system.xml.xmlspace.aspx">XmlSpace</a> enum value. By default, if you don&#8217;t specify it, XPathDocument will simply skip all non-significant whitespace node.</p><pre class="crayon-plain-tag">// skips ignorable whitespaces
XPathDocument doc = new XPathDocument(reader);
// skips also
XPathDocument doc = new XPathDocument(reader, XmlSpace.Default);
// keeps non-significant whitespaces
XPathDocument doc = new XPathDocument(reader, XmlSpace.Preserve);</pre><p>That&#8217;s it &#8230; annoying.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://timoch.com/blog/2013/05/xpathdocument-and-whitespaces/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>So what’s wrong with XPathDocument ?</title>
		<link>https://timoch.com/blog/2013/05/so-whats-wrong-with-xpathdocument/</link>
		<comments>https://timoch.com/blog/2013/05/so-whats-wrong-with-xpathdocument/#comments</comments>
		<pubDate>Fri, 24 May 2013 07:20:40 +0000</pubDate>
		<dc:creator><![CDATA[timoch]]></dc:creator>
				<category><![CDATA[Development]]></category>
		<category><![CDATA[.net]]></category>
		<category><![CDATA[c#]]></category>
		<category><![CDATA[xml]]></category>
		<category><![CDATA[xpath]]></category>

		<guid isPermaLink="false">http://timoch.com/blog/?p=224</guid>
		<description><![CDATA[This post is the first in a series of posts related to [crayon-69d57b0c82c2b840675293-i/] and [crayon-69d57b0c82c30992737878-i/]. I will highlight the qualities and drawbacks of the standard .Net implementations and go through the design and development of a new implementation that fits better to my needs. First, what is an XPathDocument ? An [crayon-69d57b0c82c34832023690-i/] is used when you [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>This post is the first in a series of posts related to <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathdocument.aspx"><pre class="crayon-plain-tag">XPathDocument</pre></a> and <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx"><pre class="crayon-plain-tag">XPathNavigator</pre></a>. I will highlight the qualities and drawbacks of the standard .Net implementations and go through the design and development of a new implementation that fits better to my needs.</p>
<h3><span style="font-size: 1.17em;">First, what is an XPathDocument ?</span></h3>
<p>An <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathdocument.aspx"><pre class="crayon-plain-tag">XPathDocument</pre></a> is used when you need to query xml data using XPath. For example, you can get a list of article id and ordered quantity from the following xml file:</p><pre class="crayon-plain-tag">&lt;order&gt;
  &lt;article id="1"&gt;
    &lt;quantity&gt;12&lt;/quantity&gt;
  &lt;/article&gt;
  &lt;article id="5"&gt;
    &lt;quantity&gt;8&lt;/quantity&gt;
  &lt;/article&gt;
  &lt;article id="6"&gt;
    &lt;quantity&gt;1&lt;/quantity&gt;
  &lt;/article&gt;
&lt;/order&gt;</pre><p>using the following code:</p><pre class="crayon-plain-tag">class Program {
    static void Main(string[] args) {
        XPathDocument doc = new XPathDocument(@"order.xml");

        XPathNavigator nav = doc.CreateNavigator();
        var articles = nav.Select("//article");
        foreach (XPathNavigator article in articles) {
            Console.WriteLine("{0}:{1}", 
                article.SelectSingleNode("@id").Value, 
                article.SelectSingleNode("quantity").Value);
        }
    }
}</pre><p>XPath, once you get a hang of it, is very powerful and flexible for accessing Xml data. It allows for complex queries and computation.</p>
<h3>Where&#8217;s the catch?</h3>
<p>This is great but there is a drawback. As per the documentation, <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathdocument.aspx"><pre class="crayon-plain-tag">XPathDocument</pre></a> <em>provides a fast, read-only, in-memory representation of an XML document by using the XPath data model. </em>This does not scale well with file sizes. If your files grow to tens of MB or larger, it will be as much data that will be loaded in memory. I recently built a mapping utility based on XPath. The starting requirements were to handle lots of small files. It turned out that once in the field, clients were using feeding it a small number of large files instead. Loading these large files in memory caused a lot of issues from bad responsiveness due to excessive swapping to plain <a href="http://msdn.microsoft.com/en-us/library/system.outofmemoryexception.aspx"><pre class="crayon-plain-tag">OutOfMemoryException</pre></a>.</p>
<p>The good news is that we can do something about it.</p>
<h2>How does XPath work in .Net?</h2>
<p>In the above code snippet, you can see that the only reference to <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathdocument.aspx"><pre class="crayon-plain-tag">XPathDocument</pre></a> is to create it. We then use it only once to create an <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx"><pre class="crayon-plain-tag">XPathNavigator</pre></a>. The rest of the XPath querying involves only XPathNavigators.</p>
<h4>XPathNavigator class</h4>
<p>An <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx"><pre class="crayon-plain-tag">XPathNavigator</pre></a> is a cursor on an xml data structure. As a cursor, it provides basic operations to move the cursor, to query information about the data it points to and also to clone itself. <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx"><pre class="crayon-plain-tag">XPathNavigator</pre></a> can also be used to update the underlying data if the implementation supports it.</p>
<p>The data of the node pointed to by a navigator can be accessed using a set of properties. The most commonly used would be LocalName, NamespaceURI, Prefix but most importantly Value and its variants. NodeType is also important. The type of a node determines the allowed move operations supported.</p><pre class="crayon-plain-tag">public abstract string BaseURI { get; }
    public virtual bool HasAttributes { get; }
    public virtual bool HasChildren { get; }
    public virtual string InnerXml { get; set; }
    public abstract bool IsEmptyElement { get; }
    public abstract string LocalName { get; }
    public abstract string Name { get; }
    public abstract string NamespaceURI { get; }
    public abstract XmlNameTable NameTable { get; }
    public abstract XPathNodeType NodeType { get; }
    public virtual string OuterXml { get; set; }
    public abstract string Prefix { get; }
    public virtual IXmlSchemaInfo SchemaInfo { get; }
    public override object TypedValue { get; }
    public virtual object UnderlyingObject { get; }
    public override bool ValueAsBoolean { get; }
    public override DateTime ValueAsDateTime { get; }
    public override double ValueAsDouble { get; }
    public override int ValueAsInt { get; }
    public override long ValueAsLong { get; }
    public override Type ValueType { get; }
    public virtual string XmlLang { get; }
    public override XmlSchemaType XmlType { get; }</pre><p>To move a validator around, the following methods can be used. Notice that all but one of them return a boolean. It indicates whether the move operation succeeded. True means the navigator now points to the new node, false, means it has not moved and still point to the original node. The only method that does not return a boolean is MoveToRoot() because it always succeeds.</p>
<p>An operation may fail for various reasons. For example, MoveToNext() will fail if the current node has no next sibling (eg. the last element of a sequence) or if the current node is an attribute. MoveToChild() will fail if there is no child of the current node that satisfies the conditions.</p><pre class="crayon-plain-tag">public abstract bool MoveTo(XPathNavigator other);
    public virtual bool MoveToAttribute(string localName, string namespaceURI);
    public virtual bool MoveToChild(XPathNodeType type);
    public virtual bool MoveToChild(string localName, string namespaceURI);
    public virtual bool MoveToFirst();
    public abstract bool MoveToFirstAttribute();
    public abstract bool MoveToFirstChild();
    public bool MoveToFirstNamespace();
    public abstract bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope);
    public virtual bool MoveToFollowing(XPathNodeType type);
    public virtual bool MoveToFollowing(string localName, string namespaceURI);
    public virtual bool MoveToFollowing(XPathNodeType type, XPathNavigator end);
    public virtual bool MoveToFollowing(string localName, string namespaceURI, XPathNavigator end);
    public abstract bool MoveToId(string id);
    public virtual bool MoveToNamespace(string name);
    public abstract bool MoveToNext();
    public virtual bool MoveToNext(XPathNodeType type);
    public virtual bool MoveToNext(string localName, string namespaceURI);
    public abstract bool MoveToNextAttribute();
    public bool MoveToNextNamespace();
    public abstract bool MoveToNextNamespace(XPathNamespaceScope namespaceScope);
    internal bool MoveToNonDescendant();
    public abstract bool MoveToParent();
    public abstract bool MoveToPrevious();
    public virtual void MoveToRoot();</pre><p></p>
<h4>XPath queries?</h4>
<p>That&#8217;s all very good but you might ask &#8216;what about XPath queries?&#8217;. XPath queries can be executed using the following functions:</p><pre class="crayon-plain-tag">public virtual object Evaluate(string xpath);
    public virtual object Evaluate(XPathExpression expr);
    public virtual object Evaluate(string xpath, IXmlNamespaceResolver resolver);
    public virtual object Evaluate(XPathExpression expr, XPathNodeIterator context);
    public virtual bool Matches(string xpath);
    public virtual bool Matches(XPathExpression expr);
    public virtual XPathNodeIterator Select(string xpath);
    public virtual XPathNodeIterator Select(XPathExpression expr);
    public virtual XPathNodeIterator Select(string xpath, IXmlNamespaceResolver resolver);
    public virtual XPathNodeIterator SelectAncestors(XPathNodeType type, bool matchSelf);
    public virtual XPathNodeIterator SelectAncestors(string name, string namespaceURI, bool matchSelf);
    public virtual XPathNodeIterator SelectChildren(XPathNodeType type);
    public virtual XPathNodeIterator SelectChildren(string name, string namespaceURI);
    public virtual XPathNodeIterator SelectDescendants(XPathNodeType type, bool matchSelf);
    public virtual XPathNodeIterator SelectDescendants(string name, string namespaceURI, bool matchSelf);
    public virtual XPathNavigator SelectSingleNode(string xpath);
    public virtual XPathNavigator SelectSingleNode(XPathExpression expression);
    public virtual XPathNavigator SelectSingleNode(string xpath, IXmlNamespaceResolver resolver);</pre><p>Evaluate() returns a value dependent on the XPath query. The result can be an integer, a string or a node set etc. Matches() tells you whether the current satisfies conditions expressed as an XPath expression. The Select() functions return a node iterator over their result. That is a set of XPathNavigators each pointing to a node in the XPath expression result set.</p>
<h2>So how do we solve our problem?</h2>
<p>The key element that will help us solve our scaling issue lies in the implementation of the XPath querying methods (Evaluate, Match and Select). Their implementation is actually expressed in terms of Move() operations and property checks on XPathNavigators.</p>
<p>The following example uses on one hand Select() to find the &lt;article&gt; nodes of root element &lt;order&gt;, on the other hand, it uses a series of Move() operations to do the same.</p><pre class="crayon-plain-tag">private static void Example2Select() {
            XPathDocument doc = new XPathDocument(@"order.xml");

            XPathNavigator nav = doc.CreateNavigator();
            var articles = nav.Select("/order/article");
            foreach (XPathNavigator article in articles) {
                Console.WriteLine("node inner xml : {0}", article.OuterXml);
            }
        }

        private static void Example2Move() {
            XPathDocument doc = new XPathDocument(@"order.xml");

            XPathNavigator nav = doc.CreateNavigator();
            nav.MoveToChild("order", ""); // move to element order
            nav.MoveToChild("article", ""); // move to first element article

            do {
                Console.WriteLine("node inner xml : {0}", nav.OuterXml);
            } while (nav.MoveToNext("article", ""));

        }</pre><p>All XPath queries can be expressed as a series of Move() and Clone() operations. This is exactly what Select() does behind the scene. This is where the design of the <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx"><pre class="crayon-plain-tag">XPathNavigator</pre></a> class shines. Select() is implemented exclusively in terms of Move() and Clone() operations. This means that any implementation of <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx"><pre class="crayon-plain-tag">XPathNavigator</pre></a> that supports these operations can benefit from the XPath query language.</p>
<p>Did you notice earlier that some of the Move() operations are virtual, others abstract ? In the same manner that XPath queries can be expressed as a series of Move() operations, most Move() operations can be expressed as a series of some of the most basic move operations. For example, the default implementation of MoveToRoot() is simply <pre class="crayon-plain-tag">while (this.MoveToParent()) {}</pre> Properties of <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx"><pre class="crayon-plain-tag">XPathNavigator</pre></a> also follow the same pattern. Virtual properties have a default implementation that relies on the abstract properties.</p>
<p>This design hepls a lot in our case. We can get rid of the default .Net-provided <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx"><pre class="crayon-plain-tag">XPathNavigator</pre></a> implementation without changing our usage. We will create a new implementation that will not load all the xml data in memory ; instead, it will cache this information to disk. Of course, since disk IO will occur, our implementation will probably be slower. We will see what we can do about it in a later post.</p>
<p>Below are the limited list of methods and properties that must be implemented in order to support XPath querying.</p><pre class="crayon-plain-tag">public abstract string BaseURI { get; }
    public abstract bool IsEmptyElement { get; }
    public abstract string LocalName { get; }
    public abstract string Name { get; }
    public abstract string NamespaceURI { get; }
    public abstract XmlNameTable NameTable { get; }
    public abstract XPathNodeType NodeType { get; }
    public abstract string Prefix { get; }

    public abstract bool MoveTo(XPathNavigator other);
    public abstract bool MoveToFirstAttribute();
    public abstract bool MoveToFirstChild();
    public abstract bool MoveToFirstNamespace(XPathNamespaceScope namespaceScope);
    public abstract bool MoveToId(string id);
    public abstract bool MoveToNext();
    public abstract bool MoveToNextAttribute();
    public abstract bool MoveToNextNamespace(XPathNamespaceScope namespaceScope);
    public abstract bool MoveToParent();
    public abstract bool MoveToPrevious();</pre><p>As you can see, the minimum interface we need to support is not as big as we could have thought. We still have a lot to do though. We have to design our solution and implement it but more importantly, we need to write tests for it.</p>
<h2>Conclusion</h2>
<p>In a next post, we will setup a series of unit tests. These tests will be run against both the standard implementation (to ensure we understand the requirements correctly) and our new implementation (to make sure we stick to the requirements).</p>
<p>The design of <a href="http://msdn.microsoft.com/en-us/library/system.xml.xpath.xpathnavigator.aspx"><pre class="crayon-plain-tag">XPathNavigator</pre></a> is quite clever. Basing the implementation of XPath queries on the abstract implementation of primitive Move() and Clone() operations enables implementors to keep their internal representation of the data completely decoupled. An implementation could very well provide an Xml-compatible view on a data structure completely unrelated to Xml. For instance, it is quite simple to expose the information of a tree of POCOs using Reflection. Another example would be to expose other data formats such as JSON to XPath-only consumers.</p>
]]></content:encoded>
			<wfw:commentRss>https://timoch.com/blog/2013/05/so-whats-wrong-with-xpathdocument/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
