大家好我正在使用XPATH和XML.SelectNodes()从XML文件中提取圆顶数据,我希望这些数据按照一定的顺序,XML文件是这样的:
<?xml version='1.0' encoding='UTF-8'?>
<ConvenioAladi>
<Operaciones>
<Operacion Prioridad='Alta' />
<Operacion Prioridad='Media' />
<Operacion Prioridad='Alta' />
<Operacion Prioridad='Baja' />
<Operacion Prioridad='Baja' />
<Operacion Prioridad='Media' />
</Operaciones>
</ConvenioAladi>
希望获得这样的XML:
<?xml version='1.0' encoding='UTF-8'?>
<ConvenioAladi>
<Operaciones>
<Operacion Prioridad='Alta' />
<Operacion Prioridad='Alta' />
<Operacion Prioridad='Media' />
<Operacion Prioridad='Media' />
<Operacion Prioridad='Baja' />
<Operacion Prioridad='Baja' />
</Operaciones>
</ConvenioAladi>
我可以通过提供XPATH来随时获得Prioridad属性之一:
'/ ConvenioAladi / Operaciones / Operacion [@ Prioridad =' 阿尔塔 ']',
但如果我尝试这样的话: '/ ConvenioAladi / Operaciones / Operacion [@ Prioridad ='Alta'或@ Prioridad ='Media'或@ Prioridad ='Baja']'
或者: '/ ConvenioAladi / Operaciones / Operacion [@ Prioridad ='Alta'] | / ConvenioAladi / Operaciones / Operacion [@ Prioridad ='Media'] | / ConvenioAladi / Operaciones / Operacion [@ Prioridad ='Baja']'
我总是得到原始的XML,无论如何实现我之前提到过的东西?感谢
答案 0 :(得分:2)
您使用的版本中的XPath按顺序匹配节点,您无法更改。
有几种方法可以实现它:
一种简单的方法是执行XSL Transform
一旦你学习了XSLT,就可以很容易地做到这一点。如:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0">
<xsl:template match="Operaciones">
<xsl:copy>
<xsl:apply-templates select="Operacion">
<xsl:sort select="index-of(('Alta','Media','Baja'), @Prioridad)"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
然后您可以轻松查询所有Operaciones
。如果您使用XSLT路由,则意味着您可以升级查询而无需重新编译软件。这可能是您希望利用的解决方案。
更新:Mathias指出我们并不是在寻找字母排序。我将保留以下解决方案以供参考,但现在我建议您使用上面正确的XSLT解决方案。
第二种方式更具编程性,它利用了微软自己的功能:
假设doc
是XmlDocument
,您可以执行以下操作将其转换为XPathDocument
:
XPathDocument xpathDoc = new XPathDocument(new XmlNodeReader(doc));
执行此操作后,您可以运行以下查询:
XPathNavigator nav = xpathDoc.CreateNavigator();
XPathExpression expression = XPathExpression.Compile(@"//Operacion");
expression.AddSort(@"@Prioridad", XmlSortOrder.Ascending, XmlCaseOrder.None, "", XmlDataType.Text);
XPathNodeIterator iterator = nav.Select(expression);
foreach (XPathNavigator operation in iterator) {
Console.WriteLine("Found priority '{0}'",operation.GetAttribute("Prioridad",""));
}
第三种方式,使用Linq(你可能想在这里查看语法):
XDocument xDoc = XDocument.Load(new XmlNodeReader(doc));
var operations = xDoc.Descendants("Operacion").OrderBy(s=>(string)s.Attribute("Prioridad"));
foreach(var operation in operations) {
Console.WriteLine("hey -> {0}", operation);
}
我建议您通过Linq进行,但如果您要转换数据,那么每次都要使用XSLT。
答案 1 :(得分:0)
如前所述,这里有一些选择。为了具体起见,这里有一个完整的XSLT(1.0)解决方案,到目前为止只是暗示过:
<?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="*">
<xsl:variable name="n" select="name (.)"/>
<xsl:element name="{$n}">
<xsl:for-each select="@*">
<xsl:copy-of select="."/>
</xsl:for-each>
<xsl:apply-templates select="*"/>
</xsl:element>
</xsl:template>
<xsl:template match="/">
<xsl:apply-templates select="ConvenioAladi"/>
</xsl:template>
<xsl:template match="Operaciones">
<xsl:apply-templates select="Operacion[@Prioridad = "Alta"]"/>
<xsl:apply-templates select="Operacion[@Prioridad = "Media"]"/>
<xsl:apply-templates select="Operacion[@Prioridad = "Baja"]"/>
</xsl:template>
</xsl:stylesheet>
您可以将此样式表应用于XML,并按Operacion
,Alta
,Media
的顺序对Baja
个节点进行排序。它相当天真地进行:它只查找具有Operacion
属性值Alta
的任何Prioridad
,并且(基本上)将其复制到输出。然后是Media
,然后是Baja
。即使没有Operacion
个节点的Baja
属性具有值Prioridad
(并且其他两个值类似),它也会起作用。样式表确实隐含地假设这三个是Prioridad
属性的唯一可能值(如果有这样的节点,它们会被静默忽略),所以如果你有Operacion
个节点可能有其他节点Prioridad
属性的值,需要调整样式表。