如何使用XSL在排序后获得第一个孩子

时间:2018-05-02 16:40:41

标签: xslt xslt-2.0

我有一个带有estruture的XML:

<?xml version="1.0" encoding="utf-8" ?>
    <products>
      <product>
        <code>XXX</code>
        <name>XXXXXX</name>
        <variants>
          <variant>
            <code>XXXY</code>
            <stock>5</stock>
          </variant>
          <variant>
            <code>XXXZ</code>
            <stock>8</stock>
          </variant>
          <variant>
            <code>XXXW</code>
            <stock>7</stock>
          </variant>
        </variants>
      </product>
      <product>
        <code>ZZZ</code>
        <name>ZZZZZZ</name>
        <variants>
          <variant>
            <code>ZZZY</code>
            <stock>5</stock>
          </variant>
          <variant>
            <code>ZZZX</code>
            <stock>8</stock>
          </variant>
          <variant>
            <code>ZZZW</code>
            <stock>7</stock>
          </variant>
        </variants>
      </product>
    </products>

我需要按库存排序并获得第一个&#34;变种&#34;。 输出是这样的:

<variant>
  <code>XXXZ</code>
  <stock>8</stock>
</variant>

<variant>
  <code>ZZZX</code>
  <stock>8</stock>
</variant>

有可能吗? 我该如何解决这个问题?

2 个答案:

答案 0 :(得分:1)

您可以使用xsl:perform-sortvariant元素进行排序,然后按降序排序顺序输出或选择第一个:

  <xsl:template match="variants">
      <xsl:variable name="sorted-variants" as="element(variant)*">
          <xsl:perform-sort select="variant">
              <xsl:sort select="xs:integer(stock)" order="descending"/>
          </xsl:perform-sort>
      </xsl:variable>
      <xsl:copy-of select="$sorted-variants[1]"/>
  </xsl:template>

https://xsltfiddle.liberty-development.net/3NzcBsU

如果其他模板(例如身份转换)复制已处理的apply-templates,则可以使用variant进行同样的操作:

  <xsl:template match="variants">
      <xsl:variable name="sorted-variants" as="element(variant)*">
          <xsl:apply-templates select="variant">
              <xsl:sort select="xs:integer(stock)" order="descending"/>
          </xsl:apply-templates>
      </xsl:variable>
      <xsl:copy-of select="$sorted-variants[1]"/>
  </xsl:template>

https://xsltfiddle.liberty-development.net/3NzcBsU/1

使用for-each,您可以直接嵌套if test="position() = 1"

  <xsl:template match="variants">
      <xsl:for-each select="variant">
          <xsl:sort select="xs:integer(stock)" order="descending"/>
          <xsl:if test="position() = 1">
              <xsl:copy-of select="."/>
          </xsl:if>
      </xsl:for-each>
  </xsl:template>

https://xsltfiddle.liberty-development.net/3NzcBsU/2

答案 1 :(得分:1)

下面的代码可以解决这个问题:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:template match="/">
  <xsl:for-each select="products/product">   
    <xsl:for-each select="variants/variant">
      <xsl:sort order="descending" select="stock" data-type="number"/>
      <xsl:if test="position() = 1">
              <xsl:apply-templates select="."/>
      </xsl:if>
    </xsl:for-each>
  </xsl:for-each>
</xsl:template>

<xsl:template match="variant">
    <xsl:apply-templates select="code"/>  
    <xsl:apply-templates select="stock"/>
</xsl:template>

</xsl:stylesheet>

我们在这里做什么:

  • 从您的产品列表中获取产品;
  • 对于此产品,我们会获取并对变体列表进行排序;
  • 在这个变体列表中,我们得到第一个元素;
  • 我们将第一个变体(select =“。”)传递给您的外部模板;
  • 然后,您可以根据需要在模板中使用您的变体;