tags:

views:

338

answers:

2

Hi! I'm parsing big XML file with XPathExpression selection for some nodes existing at various depth levels.

What is the easiest way to export selected nodes to separate XML file, preserving all direct-ancestors nodes (and their attributes)? C# is preferred.

Example source XML :

<a>
  <x>
  <b>
    <c/>
    <z/>
  </b>
  <c/>
</a>
<c/>
<d><e/></d>

Expected target XML for filtering againts "c" nodes

<a>
  <b>
    <c/>
  </b>
  <c/>
</a>
<c/>

EDIT: I'm using XPathExpression and XPathNodeIterator because there is additional logic for testing if given node should be inculded in result XML, XPathExpression alone is not enough. So basically I have array of matching XPathNavigator elements, which I want to save to XML with ancestor structure.

+2  A: 
string xml = @"<xml>
 <a>
  <x/>
  <b>
    <c/>
    <z/>
  </b>
  <c/>
</a>
<c/>
<d><e/></d></xml>";
    XmlDocument doc = new XmlDocument();
    doc.LoadXml(xml);
    XmlDocument results = new XmlDocument();
    XmlNode root = results.AppendChild(results.CreateElement("xml"));
    foreach (XmlNode node in doc.SelectNodes("/*/*[descendant-or-self::c]"))
    {
        root.AppendChild(results.ImportNode(node, true));
    }
    results.Save("out.xml");
Marc Gravell
I'm using XPathExpression and XPathNodeIterator because there is additional logic for testing if given node should be inculded in result XML, XPathExpression alone is not enough. So basically I have array of matching XPathNavigator elements, which I want to save to XML with ancestor structure.
tomash
@tomash - perhaps indicate (roughly) how you are using it currently?
Marc Gravell
If we enumarate "c" elements, there is a separate (completely external) business function which evaluates if given "c" XmlNode (or "c" XPathNavigator) is valid. If first "c" above is not valid, "b" should be also not added, but it is included with "descendant-or-self" switch...
tomash
OK, it's working for me, see additional info below
tomash
In that case, you could consider xslt with a custom external object (via XsltArgumentList) - not trivial, though
Marc Gravell
A: 

I've used solution based on Marc's above, with small modification: I'm not using "descendant-or-self" switch but for selected (and validated) nodes I'm using following traversal:

    private void appendToOut(XmlNode node, XmlNode parameter)
    {
        if (node.ParentNode != null && node.ParentNode.NodeType != XmlNodeType.Document)
        {
            appendToOut(node.ParentNode, node);
        }
        diffRoot.AppendChild(diffDoc.ImportNode(node, node==parameter));
    }
tomash