【问题标题】:避免重置位置 xslt
【发布时间】:2022-01-15 23:49:23
【问题描述】:

对于每个组,我必须按具有相同编号的艺术家进行分组。在输出中,我必须显示每个组的位置(输出:1、2、3),但是在进入组的第二个循环时位置会重置,并且当前的输出是(错误输出:1,2 ,1)。

<xsl:for-each select="group"> <xsl:for-each-group select="artist" group-by="number"> <position> <xsl:value of select="position()"/> </position> <counter> <xsl:value of select="count(number)"/></counter> </xsl:for-each-group> </xsl:for-each>
or 

<xsl:for-each select="group"> <xsl:for-each-group select="artist" group-by="number"> <position> <xsl:value of select="position()"/> </position> <counter> <xsl:value of select="count(number)"/></counter> </xsl:for-each-group> </xsl:for-each>

<?xml version="1.0" encoding="UTF-8"?>

<group>
  <artist>
    <number>1</number>
  </artist>
  <artist>
    <number>1</number>
  </artist>
  <artist>
    <number>2</number>
  </artist>
  <artist>
    <number>2</number>
  </artist>
</group>
<group>
  <artist>
    <number>5</number>
  </artist>
  <artist>
    <number>5</number>
  </artist>
</group>

【问题讨论】:

  • 请编辑您的问题并显示 (1) 格式正确的输入和 (2) 预期输出。

标签: xml loops xslt xsd


【解决方案1】:

这是一个示例,展示了如何按顺序对所有子组进行编号,同时保持其所有父组的计数:

XML

<input>
    <group>
        <item>
            <category>a</category>
        </item>
        <item>
            <category>a</category>
        </item>
        <item>
            <category>a</category>
        </item>
        <item>
            <category>b</category>
        </item>
        <item>
            <category>b</category>
        </item>
    </group>
    <group>
        <item>
            <category>a</category>
        </item>
        <item>
            <category>a</category>
        </item>
    </group>
    <group>
        <item>
            <category>a</category>
        </item>
        <item>
            <category>a</category>
        </item>
        <item>
            <category>b</category>
        </item>
    </group>
</input>

XSLT 2.0

<xsl:stylesheet version="2.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="/input">
    <xsl:variable name="categories" select="distinct-values(group/item/concat(category, '|', generate-id(..)))" />
    <output>
        <xsl:for-each select="group"> 
            <group group-num="{position()}" count-categories="{count(distinct-values(item/category))}" count-items="{count(item)}">
                <xsl:for-each-group select="item" group-by="category">
                    <category category-num="{index-of($categories, concat(category, '|', generate-id(..)))}" count-items="{count(current-group())}">
                        <xsl:value-of select="category"/> 
                    </category>
                </xsl:for-each-group>
             </group>
        </xsl:for-each> 
    </output>
</xsl:template>

</xsl:stylesheet>

结果

<?xml version="1.0" encoding="UTF-8"?>
<output>
   <group group-num="1" count-categories="2" count-items="5">
      <category category-num="1" count-items="3">a</category>
      <category category-num="2" count-items="2">b</category>
   </group>
   <group group-num="2" count-categories="1" count-items="2">
      <category category-num="3" count-items="2">a</category>
   </group>
   <group group-num="3" count-categories="2" count-items="3">
      <category category-num="4" count-items="2">a</category>
      <category category-num="5" count-items="1">b</category>
   </group>
</output>

如果每个组都有自己不同的类别,那么这可以进一步简化。

【讨论】:

    【解决方案2】:

    听起来,根据想要的输出,您不需要并且想要外部for-each,而是直接希望将所有artists 与例如分组

    <xsl:for-each-group select="group/artist" group-by="number">
    

    对于您的示例数据,这将给出三个组,而内部 &lt;xsl:value of select="position()"/&gt; 将这样输出序列 1、2、3。

    使用 XSLT 2 或 3,您可以临时存储不同的组,例如在 XSLT 3 中作为一系列映射:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        xmlns:map="http://www.w3.org/2005/xpath-functions/map"
        expand-text="yes"
        exclude-result-prefixes="#all"
        version="3.0">
    
      <xsl:mode on-no-match="shallow-skip"/>
    
      <xsl:output method="xml" indent="yes" />
    
      <xsl:template match="root">
        <xsl:copy>
          <xsl:variable name="groups" as="map(*)*">
            <xsl:apply-templates/>
          </xsl:variable>
          <xsl:apply-templates select="$groups"/>
        </xsl:copy>
      </xsl:template>
      
      <xsl:template match="group">
        <xsl:for-each-group select="artist" group-by="number">
            <xsl:sequence select="map:entry(current-grouping-key(), current-group())"/>
        </xsl:for-each-group>
      </xsl:template>
      
      <xsl:template match=".[. instance of map(*)]">
        <group position="{position()}" number-count="{count(?*/number)}"/>
      </xsl:template>
      
    </xsl:stylesheet>
    

    https://xsltfiddle.liberty-development.net/6qjt5Re

    【讨论】:

    • 是的,没错,但实际上我需要外循环。你认为有办法保持两个循环吗? @马丁
    • @teall 请解释为什么你需要(或认为你需要)外部xsl: for-each
    • 对于相同的输入,我必须在 for-each-group 中应用其他功能。例如:我必须为当前发票组计算 个节点。如果我删除 for each ,它将计算所有发票组的 节点。 @michael.hor257k
    • 请不要在 cmets 中发布代码。编辑您的问题并在此处添加所有必要信息。
    • &lt;counter&gt; &lt;xsl:value of select="count(number)"/&gt;&lt;/counter&gt; 将使用您的方法和发布的方法输出 1,因为它计算每个组中第一个项目的 number 子元素,并且您的所有 artist 元素都有一个 @987654331仅限@孩子。至于更多方法,您使用哪个版本的 XSLT?不知何故,听起来好像您可能想将各种组存储在中间结果中。在 XSLT 3 中,您可以将变量与组映射序列或数组序列一起使用,在 XSLT 2 中,您可以使用包装器元素来存储组。
    猜你喜欢
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-03
    • 2012-05-14
    • 2018-11-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多