繁体   English   中英

使用变量中的其他节点对XSL应用模板节点进行排序(XSLT 1.0)

[英]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节点的整个排序节点集中检索位置?


TL; DR答案

  • <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.xmllist-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/>处理的节点。 因此,而不是current()但这不起作用,结果没有正确排序。 我的意思在XPath括号$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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM