我正在尝试使用XPath过滤XML文件。我正在使用的XPath肯定是过滤我想要的数据,但我只是不确定如何整体过滤文件。
以下是示例XML文件:
<fields>
<field name='F'>
<field name='0'><value>F.0 stuff</value></field>
<field name='1'><value>F.1 stuff</value></field>
<field name='2'><value>F.2 stuff</value></field>
</field>
<field name='B'>
<field name='0'><value>B.0 stuff</value></field>
<field name='1'><value>B.1 stuff</value></field>
<field name='2'><value>B.2 stuff</value></field>
<field name='3'><value>B.3 stuff</value></field>
</field>
</fields>
这是所需的输出:
<fields>
<field name='F'>
<field name='1'><value>F.1 stuff</value></field>
<field name='2'><value>F.2 stuff</value></field>
</field>
<field name='B'>
<field name='3'><value>B.3 stuff</value></field>
</field>
</fields>
解决方案不一定必须由XPath解决,但由于这是一个.NET应用程序,.NET API将不胜感激!以下代码可以剪切并粘贴到LINQPad中,无需编辑即可查看我正在尝试执行的操作。
var doc = XDocument.Parse(@"
<fields>
<field name='F'>
<field name='0'><value>F.0 stuff</value></field>
<field name='1'><value>F.1 stuff</value></field>
<field name='2'><value>F.2 stuff</value></field>
</field>
<field name='B'>
<field name='0'><value>B.0 stuff</value></field>
<field name='1'><value>B.1 stuff</value></field>
<field name='2'><value>B.2 stuff</value></field>
<field name='3'><value>B.3 stuff</value></field>
</field>
</fields>");
doc.Dump("Original XML");
var xpath = "//fields/field[@name='F']/field[@name='1' or @name='2'] | //fields/field[@name='B']/field[@name='3']";
doc.XPathSelectElements(xpath).Dump("XPath Combined");
var desired = XDocument.Parse(@"
<fields>
<field name='F'>
<field name='1'><value>F.1 stuff</value></field>
<field name='2'><value>F.2 stuff</value></field>
</field>
<field name='B'>
<field name='3'><value>B.3 stuff</value></field>
</field>
</fields>");
desired.Dump("Desired Filtered XML");
编辑:我完全错过了XML Transforms - 感谢您的解决方案!这是您可以粘贴到LINQPad中的解决方案,看它是否正常工作:
var filterString = @"@name=""F""]/field[@name=""0""] | field[@name=""B""]/field[not(@name=""3"")";
var xslFmt = @"
<xsl:stylesheet version='1.0'
xmlns:xsl='http://www.w3.org/1999/XSL/Transform'>
<xsl:output omit-xml-declaration='yes' indent='yes'/>
<xsl:template match='node()|@*'>
<xsl:copy>
<xsl:apply-templates select='node()|@*'/>
</xsl:copy>
</xsl:template>
<xsl:template match=
'field[{0}]
'/>
</xsl:stylesheet>";
var xslMarkup = string.Format(xslFmt, filterString);
var xmlTree = XDocument.Parse(@"
<fields>
<field name='F'>
<field name='0'><value>F.0 stuff</value></field>
<field name='1'><value>F.1 stuff</value></field>
<field name='2'><value>F.2 stuff</value></field>
</field>
<field name='B'>
<field name='0'><value>B.0 stuff</value></field>
<field name='1'><value>B.1 stuff</value></field>
<field name='2'><value>B.2 stuff</value></field>
<field name='3'><value>B.3 stuff</value></field>
</field>
</fields>");
xmlTree.Dump("Original XML");
// Code from MSDN: http://msdn.microsoft.com/en-us/library/bb675186.aspx
var newTree = new XDocument();
using (var writer = newTree.CreateWriter()) {
// Load the style sheet.
var xslt = new XslCompiledTransform();
xslt.Load(XmlReader.Create(new StringReader(xslMarkup)));
// Execute the transform and output the results to a writer.
xslt.Transform(xmlTree.CreateReader(), writer);
}
newTree.Dump("Transformed XML");
答案 0 :(得分:2)
XPath是一种查询语言,不能用于生成修改后的XML文档。
专为此类转换而设计的技术称为 XSLT 。
您可以使用 XDocument.CreateNavigator() 方法,然后使用 XslCompiledTransform.Transform() 方法中的一个重载来执行转换。
XSLT转换本身很简单:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"field[@name='F']/field[@name='0']
|
field[@name='B']/field[not(@name='3')]
"/>
</xsl:stylesheet>
应用于提供的XML文档时,会生成所需的正确结果:
<fields>
<field name="F">
<field name="1">
<value>F.1 stuff</value>
</field>
<field name="2">
<value>F.2 stuff</value>
</field>
</field>
<field name="B">
<field name="3">
<value>B.3 stuff</value>
</field>
</field>
</fields>