True, it sounds a bit odd. Let me explain.
Using recursion we construct a nested set of objects. These objects are eventually translated into XML. This XML file is translated using an XSL template into a formatted report.
Early in the development process we realized that this particular algorithm would benefit from storing the XPath of the yet-to-be-created node in the object. This allowed us to maintain a relative identity for each node independent of the level of recursion.
Once the XDocument is created there is additional post-processing that uses XPath queries to locate particular nodes and replace element values in particular cases using XPathSelectElement and the appropriate expression.
Applying Rules to the XML
The next phase of development required a slightly different implementation. The above case was a simple “search and replace” operation. Our next task required each node to be evaluated against a set of rules at the time the node object was created. This was necessary for the following reasons:
- The name of the rule that applied is stored in the node object
- This property is evaluated by parent nodes during recursion
- The rule names may or may not be passed to the parent
A rule is applied if the node’s eventual position in the XML matches the rule’s XPath query. The rules must be applied during the recursion process before all of the node data is constructed. Therefore, we had to come up with an alternative that did not require the full tree.
Can an XPath be Compared to an XPath?
Since the XPath for the node object is created prior to the rule application it seemed natural to compare the XPath of the rule to that of the object. That limited our matching to a simple string comparison and of course fell far short of a true XPath query.
After considerable research it became clear that an XPath query must be run against an instance of XPathNavigator created from an XPathDocument.
Building a Tree
I get the feeling that turning XPaths into XPathDocuments is not a common occurrence. I finally found one post that presented a quite complex way of doing something similar. All I needed to do is to construct XML that contained each element along with its attributes.
Consider this XPath statement:
- //Root/Movies/Movie[Name=”Foo”]/Actors/Actor/@gender=”female”
Consider this rule:
- //Root/Movies/Movie/Actors/Actor[@gender=”female”]
The rule applies for all movies that have at least one female actor.
In order to process the rule a XML representation of the node XPath must be created.
The Code
This method takes the node XPath as a parameter and returns an XPathNavigator instance.
Performance
My concern with this approach was performance. I suspected that building a tree for hundreds of rules applied against thousands of nodes would be sluggish. To my surprise the evaluation of 500 rules against each of 3000 nodes took under 30 seconds. This increase in processing time was negligible compared to the overall time.