我有一个XML文档如下:
<objects>
<object uid="0" />
<object uid="1" />
<object uid="2" />
</objects>
我可以使用以下查询选择多个元素:
doc.xpath("//object[@uid=2 or @uid=0 or @uid=1]")
但是这会按照它们在XML文档中声明的顺序返回元素(uid = 0,uid = 1,uid = 2),并且我希望结果与执行XPath查询的顺序相同(uid = 2,uid = 0,uid = 1)。
我不确定单独使用XPath是否可行,并且已经研究过XSLT排序,但我没有找到解释如何实现此目的的示例。
我在Ruby中使用Nokogiri库。
答案 0 :(得分:4)
XPath 1.0无法指定所选节点的顺序。
XPath 2.0允许sequence个具有任何特定订单的节点:
//object[@uid=2], //object[@uid=1]
评估一个序列,其中object
项@uid=2
所有object
个项目都在@uid=1
如果没有可用的XPath 2.0引擎,仍然可以使用XSLT以便以任何所需的顺序输出节点。
在此特定情况下以下XSLT指令的序列:
<xsl:copy-of select="//object[@uid=2]"/>
<xsl:copy-of select="//object[@uid=1]"/>
产生所需的输出:
<object uid="2" /><object uid="1" />
答案 1 :(得分:1)
我假设您使用的是XPath 1.0。 W3C规范说: XPath中的主要语法结构是表达式。表达式与生产Expr匹配。计算表达式以生成一个对象,该对象具有以下四种基本类型之一:
* node-set (an unordered collection of nodes without duplicates)
* boolean (true or false)
* number (a floating-point number)
* string (a sequence of UCS characters)
所以我认为你不能简单地使用XPath重新订购。 (规范的其余部分定义了文档顺序和反向文档顺序,因此如果后者执行您想要的操作,您可以使用适当的轴(例如在前面)获取它。
在XSLT中,您可以使用属性的name()来使用<xsl:sort>
。 XSLT FAQ非常好,你应该在那里找到答案。
答案 2 :(得分:0)
我认为在xpath中没有办法实现它,但是如果你想切换到XSLT,你可以使用xsl:sort标签:
<xsl:for-each select="//object[@uid=1 or @uid=2]">
<xsl:sort: select="@uid" data-type="number" />
{insert new logic here}
</xsl:for-each>
这里有更完整的信息: http://www.w3schools.com/xsl/el_sort.asp
答案 3 :(得分:0)
XSLT示例:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:param name="pSequence" select="'2 1'"/>
<xsl:template match="objects">
<xsl:for-each select="object[contains(concat(' ',$pSequence,' '),
concat(' ',@uid,' '))]">
<xsl:sort select="substring-before(concat(' ',$pSequence,' '),
concat(' ',@uid,' '))"/>
<xsl:copy-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
输出:
<object uid="2" /><object uid="1" />
答案 4 :(得分:0)
这就是我在Nokogiri的表现:
require 'nokogiri'
xml = '<objects><object uid="0" /><object uid="1" /><object uid="2" /></objects>'
doc = Nokogiri::XML(xml)
objects_by_uid = doc.search('//object[@uid="2" or @uid="1"]').sort_by { |n| n['uid'].to_i }.reverse
puts objects_by_uid
运行输出:
<object uid="2"/>
<object uid="1"/>
搜索的替代方法是:
objects_by_uid = doc.search('//object[@uid="2" or @uid="1"]').sort { |a,b| b['uid'].to_i <=> a['uid'].to_i }
如果您不喜欢将sort_by
与reverse
一起使用。
XPath对于定位和检索节点很有用,但是我们想要做的过滤通常在访问器中过于复杂,所以我让语言来做,无论是Ruby,Perl还是Python。我把过滤逻辑放在哪里是基于XML数据集的大小以及是否有很多不同的uid
值我想要抓取。有时候让XPath引擎完成繁重工作是有道理的,有时候让XPath更容易抓住所有object
节点并使用调用语言进行过滤。