Probably a very special problem...
I got several XmlDocuments which I want to temporarlily combine for xpath operations and manipulation, e.g.
XmlDocument1:
<A>123</A>
XmlDocument2:
<B>456</B>
XmlDocument3:
<C></C>
After combining:
<Root>
<A>123</A><B>456</B><C></C>
</Root>
A possible operation executed with an XPathNavigator/XPathExpressions
XPathExpression expression = XPathExpression.Compile("number(/Root/A)+number(/Root/B)");
int val = (int)navigator.Evaluate(expression);
navigator.SelectSingleNode("/Root/C").SetTypedValue(val);
And after the operation is complete I need all the documents separatly again, so I have to disassemble the combined document again.
How I did it now is to create a new document and merge the root nodes under the new "Root" node before executing the xpath operations which should run on the whole document. Then I split the document again by the child nodes of the root node and put them back to where they were.
Is there a slicker way to do this E.g. something like combining the documents virtually in an XPathNavigator, so that I can perform these operations, but do not have to disassemble the document again, because the changes would affect directly the original documents

temporarily combine XmlDocuments
TMHerring
I don't see why node addition would make any difference in this design. You may not be able to add nodes on top level (Root/D) but everything else seems to be straight forward.
I forgot to motioned that to do this efficiently all XPathNavigators you merge under common virtual root (Root) should share the same XmlNameTable. Not just to MoveToParent() but almost all MoveTo*() method will have special logic.
If you are interested in this such design let's do this together to produce publicly available sample.
RoyHsu
XPath engine uses Move*() methods of XPathNavigator.
XPathNavigator is abstraction over data store and the reason for it to make XPath work everywhere. So XPath engine uses only public methods of XPathNavigator.
There is nothing wrong in physically moving set of DocumentElements to common root and then splitting them back. This may work even faster (because Clone() method on virtual XPathNavigator will need to clone all 3 aggregated navigators).
The advantages of writing custom XPathNavigator:
1. It will work on any set of navigators, not only on DOM.
2. The same data store will be visible in virtual XPathNavigator and in original XPathNavigator simultaneously.
3. This is just cool!
Cahyo Sasongko
Hi John.Doe
A while back, I responded to a similar question (on an old account) on how to join two xml documents together ("virtually"). Here's the thread:
http://forums.microsoft.com/MSDN/ShowPost.aspx PostID=104740&SiteID=1
In the thread, I outline a couple ways to do it, so be sure to read the thread in its entirety :)
kjm2dba
to answer my question myself... after a short test, it really seems, it does - so that changes of course the situation somewhat and I finally understood your approach ;)
So that seems like a viable solution to combine all XmlDocuments under a virtual own XPathNavigator and do the navigation myself, thanks for pushing me in that direction.
jms04081974
You can actually merge them virtually indeed . Without producing new document that merges all of them together. < xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />
I’d do this by writing my own implementation of XPathNavigator that aggregates three navigators positioned on each of your documents. When your navigator is positioned on node of one of three documents you translate all calls to it to the correspondent navigator. When it positioned on root or on virtual document element you handling all calls yourself.
MoveToRoot() and MoveToParent() should be handled specially as well.
This would be tricky but fun project.
Wolfgang Rues
As far as I understand your description, you would not really merge them, but detect if you are in one of the subdocuments and use the navigator there. I guess that would only work for straight node selection/xpath calls, but how would you imagine to handle cross document node (which is the purpose of merging them) like the addition of the nodes in the above example
Although... if I can find some more time somewhere , I might investigate this approach...
TigerMan90
So, if I understand you correctly, based on the example, you would end up with something like this:
original:
XPathNavigator A
XPathNavigator B
XPathNavigator C
you would create a new root navigator and append the original navigators:
XPathNavigator: Root
XPathNavigator: A' (copy of XPathNavigator A)
XPathNavigator: B' (copy of XPathNavigator B)
XPathNavigator: C' (copy of XPathNavigator C)
Execute aggregation functions like the addition to get a value and then if it comes to assigning, you would do what
Assuming you have an XPath statement that selects a target node, the only possibility I see is to:
- execute it once, to figure out which node in the root navigator would be selected
- get the full path of the node
- figure out which of the original navigators it would be in by the second node in the path
- navigate to that node in the original navigator and assign the value
If that is right, then I guess that just splitting the XmlDocuments again by the root children is cheaper because you skip all the node navigation.
Or does the XPath execution actually use the Move* methods of the XPathNavigator for its own execution
It would be nice if one could append the original navigators as children to the new root navigator, then everything would be fine...
amzayle
I do merge the documents already very similar to how you describe it there (importing nodes), but that is not the issue. The problem is more to split the documents again to reflect the changes back into the original documents. To follow the example above:
I want to end up again with three documents while in the example document 3 would have changed to: <C>579</C>
By "virtually" combine, I meant that changes to the merged document would reflect directly into the original documents - although, I am already pretty convinced that it is not possible as I imagine it to work ;)