[英]Missing some child nodes after sorting with `<xsl:apply-templates>`
[英]Sorting in XSL apply-templates nodes using other nodes from a variable (XSLT 1.0)
如何使用$ bar中的相应节点顺序对$ foo中的<foo name="..."/>
节点进行排序?
部分解决方案(Mark Veenstra)
<xsl:for-each select="$list-resources"> <xsl:apply-templates select="$building-resources[@name = current()/@name]"> <xsl:with-param name="param" select="$some-value"/> </xsl:apply-templates> </xsl:for-each>
新问题(请参见问题末尾的编辑):
如何在每个$ building-resources节点的整个排序节点集中检索位置?
<xsl:sort/>
具有@data-type
属性,用于指定@select
节点中的数据类型。 默认值为“文本”。 由于我比较数字,因此必须设置 @data-type="number"
。 否则,当比较9和10时,文本比较将失败。
<xsl:sort select="count($bar[@name = current()/@name]/preceding-sibling::*)" data-type="number"/>
在<xsl:sort/>
, current()
指向当前已排序的节点(而不是<xsl:template/>
当前节点)
感谢michael.hor257k
码
<!-- Resource "instances" to order, using $list-resources --> <xsl:variable name="building-resources" select="document('building.xml')/building/resource"/> <result> <!-- Apply templates to the resource instances --> <xsl:apply-templates select="$building-resources"> <!-- Sort using the nodes order from the resources list --> <!-- Don't forget the @data-type: we're comparing NUMBERS not TEXTS --> <xsl:sort select="count($list-resources[@name = current()/@name]/preceding-sibling::*)" data-type="number"/> </xsl:apply-templates> </result> </xsl:template> <!-- Template to apply for each resource of $building-resources --> <xsl:template match="ressource"> <!-- position() refers to the node position in $building-resources because we used $building-resources as @select value of the apply-templates --> <output position="{position()}"> <xsl:value-of select="."/> </output> </xsl:template>
输入
列表resources.xml中
<resources> <resource name="wood"/> <resource name="stone"/> <resource name="gold"/> </resources>
建筑resources.xml中
<building> <resource name="stone"/> <resource name="gold"/> <resource name="stone"/> <resource name="wood"/> <resource name="wood"/> </building>
产量
<result> <output position="1">wood</output> <output position="2">wood</output> <output position="3">stone</output> <output position="4">stone</output> <output position="5">gold</output> </result>
排序
我有两个XML文档:
资源list-resources.xml
( list-resources.xml
,如“类”列表):
<resources> <resource name="wood"/> <resource name="stone"/> <resource name="gold"/> </resources>
以及建筑物内的资源( buildings.xml
,例如“对象”列表):
<building> <resource name="stone"/> <resource name="gold"/> <resource name="stone"/> <resource name="wood"/> <resource name="wood"/> </building>
我想订购<resource/>
节点从<building/>
所以它的匹配<resource/>
从订单<resources/>
这是所需的输出:
<result> <output position="1">wood</output> <output position="2">wood</output> <output position="3">stone</output> <output position="4">stone</output> <output position="5">gold</output> </result>
为此,我在XSL中有两个节点集:
<xsl:variable name="building-resources" select="building/resource"/> <xsl:variable name="list-resources" select="resources/resource"/>
我使用XSL apply-templates来处理$building-resources
节点:
<xsl:apply-templates select="$building-resources"> <xsl:with-param name="some-param" select="$variable-from-somewhere"/> </xsl:apply-templates>
假设应用的模板还可以。 我目前未排序的结果是:
<result> <output position="1">stone</output> <output position="2">gold</output> <output position="3">stone</output> <output position="4">wood</output> <output position="5">wood</output> </result>
现在,我添加了一个<xsl:sort/>
元素对$building-resources
节点进行排序,但是我不知道在其@select
放入什么...
<xsl:apply-templates select="$building-resources"> <xsl:sort select="what-to-put-here"/> <xsl:with-param name="some-param" select="$variable-from-somewhere"/> </xsl:apply-templates>
我尝试了以下XPath表达式:
count($list-ressources[@name = current()/@name]/preceding-sibling::*)
但是在此XPath内部, current()
指的是<xsl:apply-templates/>
所在的<xsl:template/>
处理的节点。因此,而不是但这不起作用,结果没有正确排序。 我的意思是在XPath括号current()
,$list-resources[]
“正在<xsl:sort/>
进程当前正在处理的节点” (编辑:这实际上是current()所做的!) 。 我该怎么做?
获取排序的位置
由于简化了代码,所以我忘了一些东西……Mark Veenstra的解决方案提出了一个问题。
在所应用的模板(生成<output/>
节点的模板)中,我使用position()
获取应用模板的节点的位置:
<xsl:template match="resource"> <xsl:variable name="position" select="position()"/> <output position="{$position}"> <xsl:value-of select="@name"/> </output> </xsl:template>
只要我仅执行“一个”应用模板,此方法就可以很好地工作(因此,此应用模板内的position()
将节点的位置保留在排序列表中)。 但是,如果我使用Mark的解决方案(请注意, <xsl:sort/>
中的current()
现在引用的是<xsl:for-each/>
的节点,也就是$ liste-resources中的节点):
<xsl:for-each select="$list-resources"> <xsl:apply-templates select="$building-resources[@name = current()/@name]"> <xsl:with-param name="param" select="$some-value"/> </xsl:apply-templates> </xsl:for-each>
然后,所应用的模板内部的position()
引用该节点在部分节点集中的位置($ building-resources [@name = current()/ @ name])。
如何解决?
我认为您应该尝试执行以下操作。 (另)
更改:
<xsl:apply-templates select="$building-resources">
<xsl:sort select="what-to-put-here"/>
<xsl:with-param name="some-param" select="$variable-from-somewhere"/>
</xsl:apply-templates>
至:
<xsl:for-each select="$list-resources/@name">
<xsl:variable name="curName" select="." />
<xsl:apply-templates select="$building-resources[@name = $curName]">
<xsl:with-param name="some-param" select="$variable-from-somewhere"/>
</xsl:apply-templates>
</xsl:for-each>
因此,在应用模板之前,请确保按其他节点集的顺序应用。 这就是为什么我for-each
添加了额外的for-each
原因。
关于排序问题,我建议:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<building>
<xsl:apply-templates select="building/resource">
<xsl:sort select="count(document('list-resources.xml')/resources/resource[@name = current()/@name]/preceding-sibling::resource)" data-type="number" order="ascending"/>
</xsl:apply-templates>
</building>
</xsl:template>
<xsl:template match="resource">
<resource position="{position()}">
<xsl:value-of select="@name"/>
</resource>
</xsl:template>
</xsl:stylesheet>
将其应用于您的输入示例后,将返回:
<?xml version="1.0" encoding="UTF-8"?>
<building>
<resource position="1">wood</resource>
<resource position="2">wood</resource>
<resource position="3">stone</resource>
<resource position="4">stone</resource>
<resource position="5">gold</resource>
</building>
我不确定另一个问题是什么。
我将使用XSL键和<xsl:sort>
,如下所示:
<xsl:key name="kResource" match="resources/resource" use="@name" />
<!-- regular identity template -->
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<!-- specialized identity template, adds a position attribute -->
<xsl:template match="*" mode="with-position">
<xsl:copy>
<xsl:attribute name="position"><xsl:value-of select="position()" /></xsl:attribute>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="building">
<result>
<xsl:apply-templates select="*" mode="with-position">
<xsl:sort select="count(key('kResource', @name)/preceding-sibling::*)" data-type="number" />
</xsl:apply-templates>
</result>
</xsl:template>
相关输出:
<result>
<resource position="1" name="wood" />
<resource position="2" name="wood" />
<resource position="3" name="stone" />
<resource position="4" name="stone" />
<resource position="5" name="gold" />
</result>
请注意,即使我添加了position
属性,我认为这也是一件不必要的事情。 XML元素在文档中具有自然的位置,无需过于具体。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.