【问题标题】:XSLT Grouping elements inside two siblingsXSLT 对两个同级中的元素进行分组
【发布时间】:2012-06-21 20:11:23
【问题描述】:

我正在努力解决这个问题,我认为解释它的最简单方法就是在下面向您展示。我见过this,但它并不总是适用,因为我最后也有独立的项目,可以匹配。

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

我考虑过 xsl:for-each 和 xsl:if ,但问题是你不能保证有多少“组”和“非组”项目。

谢谢!

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>

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

到目前为止,我遇到的唯一问题(除了杂乱之外)是 What4 和 What5 出现在 Group 之外。

<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>

【问题讨论】:

  • 你试过什么?除了考虑 xsl:for-each 和 xsl:if 当然。请发布您迄今为止提出的 XSLT。
  • 给我一点,我需要将笔记本电脑切换到我的 XSLT 所在的位置,并将其从我真正的 XML 格式转换为我上面所做的模型。

标签: xslt


【解决方案1】:

我。 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>

二。 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>

当这个 XSLT 2.0 转换应用于同一个 XML 文档(如上)时,会产生同样正确的结果

【讨论】:

  • 谢谢迪米特!!完美,你很优秀。
  • 在 XSLT 1.0 版本上我只需要更改一件事 -- xsl:copy-of 不适用于这些项目,因为我需要删除一些元素(标记元素应该' t 出现在输出中)。
  • @JonathonHowey:不客气。继续问这些具有挑战性的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-10-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-05
  • 2012-11-24
相关资源
最近更新 更多