XSLT在两个兄弟姐妹中分组元素

时间:2012-06-21 20:11:23

标签: xslt

我正在试图解决这个问题,我认为最简单的解释方法就是向下方展示。我见过this但它并不总是适用,因为我的最后一个项目也是匹配的。

看似棘手的部分是Whatever3 to Whatever6,然后是Whatever7和Whatever8,最后是Whatever9的新位置 - 他们需要分组并保持原始序列。 (忽略我的命名,没有办法使用xsl:sort)

我已经考虑过xsl:for-each和xsl:如果在里面,但问题是你不能保证有多少“组”与“非组”项目。

谢谢!

XML

<root>
   <item>
      <position>1</position>
      <label>Whatever1</label>
   </item>
   <item>
      <position>2</position>
      <label>Whatever2</label>
   </item>
   <item>
      <position>3</position>
      <label>Whatever3</label>
      <marker id="unique1">start_group</marker>
   </item>
   <item>
      <position>4</position>
      <label>Whatever4</label>
   </item>
   <item>
      <position>5</position>
      <label>Whatever5</label>
   </item>
   <item>
      <position>6</position>
      <label>Whatever6</label>
      <marker>last_in_group</marker>
   </item>
   <item>
      <position>7</position>
      <label>Whatever7</label>
      <marker id="unique2">start_group</marker>
   </item>
   <item>
      <position>8</position>
      <label>Whatever8</label>
      <marker>last_in_group</marker>
   </item>  
   <item>
      <position>9</position>
      <label>Whatever9</label>
   </item>
</root>

结果

<structure>
   <item>
      <position>1</position>
      <label>Whatever1</label>
    </item>
   <item>
      <position>2</position>
      <label>Whatever2</label>
    </item>
    <group position="3" id="unique1">
        <item>
          <position>1</position>
          <label>Whatever3</label>
        </item>
        <item>
          <position>2</position>
          <label>Whatever4</label>
        </item>
        <item>
          <position>3</position>
          <label>Whatever5</label>
        </item>
        <item>
          <position>4</position>
          <label>Whatever6</label>
        </item>
    </group>
    <group position="4" id="uniqueid2">
        <item>
          <position>1</position>
          <label>Whatever7</label>
        </item>
        <item>
          <position>2</position>
          <label>Whatever8</label>
        </item>
    </group>
    <item>
      <position>**5**</position>
      <label>Whatever9</label>
    </item>
</structure>

======================

这是我到目前为止所遇到的唯一问题(除了它是凌乱的)是Whatever4和Whatever5出现在集团之外。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

  <xsl:template match="root">
  <structure>
    <xsl:apply-templates select="item[not(marker)] | item[marker='start_group']"/>
  </structure>
 </xsl:template>

  <xsl:template match="item[marker='start_group']">
   <group>
    <xsl:variable name="currentPosition" select="number(position/text())"/>
    <xsl:variable name="lastGroup" select="count(following-sibling::*[local-name() = 'item' and marker='last_in_group'][1]/preceding-sibling::*) + 1"/>

    <xsl:attribute name="position">
        <xsl:value-of select="$currentPosition"/>
    </xsl:attribute>
    <xsl:attribute name="id">
        <xsl:value-of select="marker/@id"/>
    </xsl:attribute>

   <item>
    <position><xsl:value-of select="number(position/text()) - $currentPosition + 1"/></position>
    <label><xsl:value-of select="label/text()"/></label>
   </item>

   <!-- position() gets reset in for-loop, so need to adjust with outer position -->
   <xsl:for-each select="following-sibling::item[(position() + $currentPosition) &lt;= $lastGroup]">
         <item>
                <position><xsl:value-of select="number(position/text()) - $currentPosition + 1"/></position>
                <label><xsl:value-of select="label/text()"/></label>
         </item>
    </xsl:for-each>
   </group>
 </xsl:template>

  <xsl:template match="item[not(marker)]">
   <item>
    <position><xsl:value-of select="position/text()"/></position>
    <label><xsl:value-of select="label/text()"/></label>
   </item>
 </xsl:template>

</xsl:stylesheet>

1 个答案:

答案 0 :(得分:3)

<强>予。 XSLT 1.0解决方案:

此转化

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
 <xsl:strip-space elements="*"/>

 <xsl:key name="kFollowing"
  match="item[not(marker[. = 'start_group'])
            and
              preceding-sibling::*[marker][1]/marker = 'start_group'
             ]"
  use="generate-id(preceding-sibling::*
                    [marker[. = 'start_group']]
                     [1])"/>

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

 <xsl:template match="item[marker[. = 'start_group']]">
   <group position="{1 +count(preceding-sibling::*[. = 'start_group'])}"
   id="{marker/@id}">
     <xsl:copy-of select=".|key('kFollowing', generate-id())"/>
   </group>
 </xsl:template>

 <xsl:template match=
  "item[not(marker[. = 'start_group'])
      and
       preceding-sibling::*[marker][1]/marker = 'start_group'
       ]"/>
</xsl:stylesheet>

应用于提供的XML文档时:

<root>
    <item>
        <position>1</position>
        <label>Whatever1</label>
    </item>
    <item>
        <position>2</position>
        <label>Whatever2</label>
    </item>
    <item>
        <position>3</position>
        <label>Whatever3</label>
        <marker id="unique1">start_group</marker>
    </item>
    <item>
        <position>4</position>
        <label>Whatever4</label>
    </item>
    <item>
        <position>5</position>
        <label>Whatever5</label>
    </item>
    <item>
        <position>6</position>
        <label>Whatever6</label>
        <marker>last_in_group</marker>
    </item>
    <item>
        <position>7</position>
        <label>Whatever7</label>
        <marker id="unique2">start_group</marker>
    </item>
    <item>
        <position>8</position>
        <label>Whatever8</label>
        <marker>last_in_group</marker>
    </item>
    <item>
        <position>9</position>
        <label>Whatever9</label>
    </item>
</root>

会产生想要的正确结果:

<root>
   <item>
      <position>1</position>
      <label>Whatever1</label>
   </item>
   <item>
      <position>2</position>
      <label>Whatever2</label>
   </item>
   <group position="1" id="unique1">
      <item>
         <position>3</position>
         <label>Whatever3</label>
         <marker id="unique1">start_group</marker>
      </item>
      <item>
         <position>4</position>
         <label>Whatever4</label>
      </item>
      <item>
         <position>5</position>
         <label>Whatever5</label>
      </item>
      <item>
         <position>6</position>
         <label>Whatever6</label>
         <marker>last_in_group</marker>
      </item>
   </group>
   <group position="1" id="unique2">
      <item>
         <position>7</position>
         <label>Whatever7</label>
         <marker id="unique2">start_group</marker>
      </item>
      <item>
         <position>8</position>
         <label>Whatever8</label>
         <marker>last_in_group</marker>
      </item>
   </group>
   <item>
      <position>9</position>
      <label>Whatever9</label>
   </item>
</root>

<强> II。 XSLT 2.0解决方案:

<xsl:stylesheet version="2.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
 xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

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

 <xsl:template match="/*">
  <root>
   <xsl:for-each-group select="item" group-starting-with=
   "*[marker eq 'start_group'
    or
      not(marker)
    and
      preceding-sibling::*[marker][1]/marker eq 'last_in_group'
     ]
   ">
     <xsl:choose>
       <xsl:when test="current-group()[1]/marker">
               <group position=
               "{1 +count(current-group()[1]
                            /preceding-sibling::*
                                  [marker = 'start_group'])}"
               id="{marker/@id}">
                 <xsl:apply-templates select="current-group()"/>
               </group>
       </xsl:when>
       <xsl:otherwise>
        <xsl:apply-templates select="current-group()"/>
       </xsl:otherwise>
     </xsl:choose>
   </xsl:for-each-group>
  </root>
 </xsl:template>
</xsl:stylesheet>

当在同一个XML文档(上面)上应用此XSLT 2.0转换时,会生成相同的正确结果