代码之家  ›  专栏  ›  技术社区  ›  ravthiru

对组中的所有单个组应用第二个分组

  •  0
  • ravthiru  · 技术社区  · 6 年前

    我曾经 for-each-group ,如果要基于键对项进行分组,然后如果它们不属于任何组,则应用第二个分组。

    <items>
        <item id="123" name="Java">
            <price></price>
            <description></description> 
        </item>
    
        <item id="123" name="Java and XML">
            <price></price>
            <description></description> 
        </item>
    
        <item id="234" name="python">
            <price></price>
            <description></description> 
        </item>
    
        <item id="456" name="scala">
            <price></price>
            <description></description> 
        </item>
    
        <item id="" name="python">
            <price></price>
            <description></description> 
        </item>
    
    
        <item id="768" name="scala">
            <price></price>
            <description></description> 
        </item>
    
        <item id="891" name="angular">
            <price></price>
            <description></description> 
        </item>
      </items>
    

    首先我要分组 id 如果组中有多个元素,那么我将组成一个组,否则我将应用另一个分组 name

    输出应该是这样的

    <items>
        <group>
            <item id="123" name="Java">
                <price></price>
                <description></description> 
            </item>
    
            <item id="123" name="Java and XML">
                <price></price>
                <description></description> 
            </item>
        </group>
        <group>
            <item id="234" name="python">
                <price></price>
                <description></description> 
            </item>
            <item id="" name="python">
                <price></price>
                <description></description> 
            </item>
        </group>
        <group>
            <item id="456" name="scala">
                <price></price>
                <description></description> 
            </item>
            <item id="768" name="scala">
                <price></price>
                <description></description> 
            </item>
        </group>
        <group>
            <item id="891" name="angular">
                <price></price>
                <description></description> 
            </item>
        </group>
    </items>
    

    如何对不在任何组中的应用分组?是 最适合这个。

    我试过这种方法

    <xsl:stylesheet version="2.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output omit-xml-declaration="yes" indent="yes"/>
        <xsl:strip-space elements="*"/>
    
        <xsl:variable name="nonMatched" as="element()*">
            <xsl:for-each-group select="./items/item" group-by="@id">           
                <xsl:if test="count(current-group())  lt 2">
                    <xsl:sequence select="current-group()"/>
                </xsl:if>
            </xsl:for-each-group>
        </xsl:variable>
    
        <xsl:template match="/">
        <items>
           <xsl:for-each-group select="/items/item" group-by="@id">
                <xsl:if test="count(current-group()) gt 1">
                    <group>
                    <xsl:copy-of select="current-group()"/>
                    </group>
                </xsl:if> 
            </xsl:for-each-group>
    
        <xsl:for-each-group select="$nonMatched" group-by="@name">
            <group>
            <xsl:copy-of select="current-group()"/>
            </group>
        </xsl:for-each-group>
        </items>
        </xsl:template>
    
    1 回复  |  直到 6 年前
        1
  •  1
  •   Martin Honnen    6 年前

    一种方法是通过不同的模板推送项目,在这些模板中使用键来标识组和组的条件,然后为每个组中的第一个项目组成组,并为每个组中的其他项目使用空模板;请注意,下面的方法利用了order强加的优先级 https://www.w3.org/TR/xslt-30/#conflict 因此,下面使用的模板顺序很重要,尽管您也可以使用 priority 把你的规则强加于 @id 基于分组,然后 @name 基于分组,然后对任何项目进行分组(即。 match="item" )其他分组条件不包括:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="#all"
        version="3.0">
    
      <xsl:mode on-no-match="shallow-copy"/>
    
      <xsl:output method="xml" indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:key name="id" match="item[normalize-space(@id)]" use="@id"/>
      <xsl:key name="name" match="item" use="@name"/>
    
      <xsl:template match="item">
          <group>
              <xsl:copy-of select="."/>
          </group>
      </xsl:template>
    
      <xsl:template match="item[key('name', @name)[2] and . is key('name', @name)[1]]">
          <group>
              <xsl:copy-of select="key('name', @name)"/>
          </group>
      </xsl:template>
    
      <xsl:template match="item[key('name', @name)[2] and not(. is key('name', @name)[1])]"/>
    
      <xsl:template match="item[key('id', @id)[2] and . is key('id', @id)[1]]">
          <group>
              <xsl:copy-of select="key('id', @id)"/>
          </group>
      </xsl:template>
    
      <xsl:template match="item[key('id', @id)[2] and not(. is key('id', @id)[1])]"/> 
    
    </xsl:stylesheet>
    

    在线 https://xsltfiddle.liberty-development.net/bdxtqt xsl:mode

    <xsl:template match="@* | node()">
      <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
    </xsl:template>
    

    让它与XSLT2处理器一起工作。唯一要注意的是,如果存在多个匹配项,XSLT 2处理器可能会报告错误,而不是使用最后一个匹配模板,我不记得哪个XSLT 2处理器会这样做,但正如前面所说,显式使用优先级可以解决这个问题。

    你发布的方法也应该有效:

      <xsl:template match="items">
        <xsl:copy>
            <xsl:variable name="nonMatched" as="element()*">
                <xsl:for-each-group select="item" group-by="@id">           
                    <xsl:sequence
                      select="if (not(current-group()[2]))
                              then .
                              else ()"/>
                </xsl:for-each-group>
            </xsl:variable>
            <xsl:for-each-group select="item except $nonMatched" group-by="@id">
                <group>
                    <xsl:apply-templates select="current-group()"/>
                </group>
            </xsl:for-each-group>
            <xsl:for-each-group select="$nonMatched" group-by="@name">
                <group>
                    <xsl:apply-templates select="current-group()"/>
                </group>
            </xsl:for-each-group>
        </xsl:copy>
      </xsl:template>
    

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