Reputation: 55770
I'm trying to filter an Xml document so into a subset of itself using XPath.
I have used XPath get an XmlNodeList, but I need to transform this into an XML document.
Is there a way to either transform an XMLNodeList into an XmlDocument or to produce an XmlDocument by filtering another XmlDocument directly?
Upvotes: 2
Views: 3672
Reputation: 96830
This is a pretty typical reason to use XSLT, which is an efficient and powerful tool for transforming one XML document into another (or into HTML, or text).
Here's a minimal program to perform an XSLT transform and send the results to the console:
using System;
using System.Xml;
using System.Xml.Xsl;
namespace XsltTest
{
class Program
{
static void Main(string[] args)
{
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load("test.xslt");
XmlWriter xw = XmlWriter.Create(Console.Out);
xslt.Transform("input.xml", xw);
xw.Flush();
xw.Close();
Console.ReadKey();
}
}
}
Here's the actual XSLT, which is saved in test.xslt
in the program directory. It's pretty simple: given an input document whose top-level element is named input
, it creates an output
element and copied over every child element whose value
attribute is set to true
.
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:template match="/input">
<output>
<xsl:apply-templates select="*[@value='true']"/>
</output>
</xsl:template>
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
And here's input.xml
:
<?xml version="1.0" encoding="utf-8" ?>
<input>
<element value="true">
<p>This will get copied to the output.</p>
<p>Note that the use of the identity transform means that all of this content
gets copied to the output simply because templates were applied to the
<em>element</em> element.
</p>
</element>
<element value="false">
<p>This, on the other hand, won't get copied to the output.</p>
</element>
</input>
Upvotes: 1
Reputation: 1063338
With XmlDocument, you will need to import those nodes into a second document;
XmlDocument doc = new XmlDocument();
XmlElement root = (XmlElement)doc.AppendChild(doc.CreateElement("root"));
XmlNodeList list = // your query
foreach (XmlElement child in list)
{
root.AppendChild(doc.ImportNode(child, true));
}
Upvotes: 4
Reputation: 55770
I've actualy just thought of a way to do this but it doesn't seem very elegant.
use a StringBuilder to combine the OuterXml of each of the XmlNodes in the XmlNodeList...
As I said it's inelegant but I think it might work. I'd appreciate any other suggestion...
Upvotes: 0