如何使用 XPATH 添加节点 [英] How to appens nodes using XPATH
问题描述
大家好,我正在使用 XPATH 和 XML.SelectNodes() 从 XML 文件中提取圆顶数据,我希望这些数据按特定顺序排列,XML 文件是这样的:
Hi everyone I'm using XPATH with XML.SelectNodes() to extract dome data from an XML file, I wish this data to be in certain order, the XML file is like this:
<?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:
And wish to obtain an XML like this:
<?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 随时获得一个优先级属性:
I'm capable of obtaining one of the Prioridad attributes at any moment by giving the XPATH:
'/ConvenioAladi/Operaciones/Operacion[@Prioridad='Alta']',
但是如果我尝试这样的事情:'/ConvenioAladi/Operaciones/Operacion[@Prioridad='Alta' 或 @Prioridad='Media' 或 @Prioridad='Baja' ]'
but if I try something like this: '/ConvenioAladi/Operaciones/Operacion[@Prioridad='Alta' or @Prioridad='Media' or @Prioridad='Baja' ]'
或者:'/ConvenioAladi/Operaciones/Operacion[@Prioridad='Alta'] |/ConvenioAladi/Operaciones/Operacion[@Prioridad='媒体'] |/ConvenioAladi/Operaciones/Operacion[@Prioridad='Baja']'
我总是能得到原始的 XML,有没有办法实现我之前提到的?.谢谢
I always get the original XML back, is there anyway of achieving what I mentioned before?. Thanks
推荐答案
您使用的版本中的 XPath 按顺序匹配节点,您无法更改.
XPath in the version you are using matches nodes in order, which you cannot change.
有几种方法可以实现:
一种简单的方法是执行 XSL 转换
One simple way is to perform an XSL Transform
一旦你学会了 XSLT,做这种事情就变得很容易了.如:
Once you learn XSLT, it becomes really easy to do this sort of thing. Such as:
<?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 路由,这意味着您可以升级您的查询而无需重新编译您的软件.这可能是您希望使用的解决方案.
And then you can query all your Operaciones
easily. If you do it the XSLT route, it means that you can upgrade your queries without having to recompile your software. It is probably the solution you wish to utilise.
更新:Mathias 指出我们不是在寻找按字母顺序排序.我将保留下面的解决方案以供参考,但现在我建议选择上面正确的 XSLT 解决方案.
第二种方式更加程序化,它利用了微软自己的特性:
The second way is more programatic, which utilises Microsoft's own features:
假设 doc
是一个 XmlDocument
,您可以执行以下操作将其转换为 XPathDocument
:
Assuming doc
is an XmlDocument
, you can do the following to turn it into an XPathDocument
:
XPathDocument xpathDoc = new XPathDocument(new XmlNodeReader(doc));
完成后,您可以运行以下查询:
Once you do that, you can run the following query:
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(您可能想在此处检查语法):
Linq
Third way, using Linq (you might want to check the syntax here):
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.
I suggest you do it via Linq, but if you are transforming data, then go for XSLT every time.
这篇关于如何使用 XPATH 添加节点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!