Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/xslt/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何使用XSLT1按标记折叠一组选定(相邻)标记?_Xslt_Fold - Fatal编程技术网

如何使用XSLT1按标记折叠一组选定(相邻)标记?

如何使用XSLT1按标记折叠一组选定(相邻)标记?,xslt,fold,Xslt,Fold,我有一组顺序节点,它们必须包含在新元素中。例如: <root> <c>cccc</c> <a gr="g1">aaaa</a> <b gr="g1">1111</b> <a gr="g2">bbbb</a> <b gr="g2">2222</b> </root> 因此,我有一个“分组标签”(@gr),但无法想象

我有一组顺序节点,它们必须包含在新元素中。例如:

  <root>
    <c>cccc</c>
    <a gr="g1">aaaa</a>    <b gr="g1">1111</b>
    <a gr="g2">bbbb</a>   <b gr="g2">2222</b>
  </root>
因此,我有一个“分组标签”(
@gr
),但无法想象如何生成正确的折叠标签


我正试图利用……的线索。。。但是我有一个“分组标签”,所以我知道我的解决方案不需要使用
key()
函数

我的非通用解决方案是:

   <xsl:template match="/">
       <root>
       <xsl:copy-of select="root/c"/>
       <fold><xsl:for-each select="//*[@gr='g1']">
             <xsl:copy-of select="."/>
       </xsl:for-each></fold>

       <fold><xsl:for-each select="//*[@gr='g2']">
             <xsl:copy-of select="."/>
       </xsl:for-each></fold>

       </root>
   </xsl:template>

我需要一个通用的解决方案(!),通过所有@gr循环并处理(标识)所有没有@gr的上下文。。。也许使用身份转换


另一个(未来的)问题是使用折叠递归地执行此操作。

在XSLT 1.0中,处理这类事情的标准技术称为Muenchian分组,其中包括使用一个键定义节点应如何分组,以及使用
generate id
仅提取每个组中的第一个节点作为整个组的代理的技巧

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:strip-space elements="*" />
  <xsl:output indent="yes" />
  <xsl:key name="elementsByGr" match="*[@gr]" use="@gr" />

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

  <!-- match the first element with each @gr value -->
  <xsl:template match="*[@gr][generate-id() =
         generate-id(key('elementsByGr', @gr)[1])]" priority="2">
    <fold>
      <xsl:for-each select="key('elementsByGr', @gr)">
        <xsl:call-template name="identity" />
      </xsl:for-each>
    </fold>
  </xsl:template>

  <!-- ignore subsequent ones in template matching, they're handled within
       the first element template -->
  <xsl:template match="*[@gr]" priority="1" />
</xsl:stylesheet>

请注意,如果您能够使用XSLT 2.0,那么对于每个组,整个过程将变成一个

<xsl:template match="root">
  <xsl:for-each-group select="*" group-adjacent="@gr">
    <xsl:choose>
      <!-- wrap each group in a fold -->
      <xsl:when test="@gr">
        <fold><xsl:copy-of select="current-group()" /></fold>
      </xsl:when>
      <!-- or just copy as-is for elements that don't have a @gr -->
      <xsl:otherwise>
        <xsl:copy-of select="current-group()" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:template>


每个组的
gr
值在
根中是否总是不同的,如果不是,那么如果你有
a1b1 a2b2 a3b3
那么应该给你三个
折叠元素(a1/b1,a2/b2,a3/b3)还是两个(a1/b1/a3/b3,a2/b2)?你可以使用“两个”假设,但在我真正的问题中,@gr是一个不重复的序列,也就是说,如果一个序列停止,它就不再出现了(下一组将是g3,g2之后不可能是g1)。好的,这个示例是完整的XML文档还是有几个不同的
元素需要单独“折叠”?我编辑了。。。并在问题标题中添加“邻居”。关于“褶皱的褶皱”现在不是问题,但我想我将来会遇到这个问题,还有。很好的解释和优雅的解决方案@PeterKrauss我还添加了一个可能的XSLT2.0解决方案,用于比较。是的,使用XSLT2非常简单直观。。。我讨厌XSLT1(!!),但PHP只提供XSLT1…PS:我将在下一期中向您介绍我的未来。
<root>
  <c>cccc</c>
  <fold>
    <a gr="g1">aaaa</a>
    <b gr="g1">1111</b>
  </fold>
  <fold>
    <a gr="g2">bbbb</a>
    <b gr="g2">2222</b>
  </fold>
</root>
<xsl:template match="root">
  <xsl:for-each-group select="*" group-adjacent="@gr">
    <xsl:choose>
      <!-- wrap each group in a fold -->
      <xsl:when test="@gr">
        <fold><xsl:copy-of select="current-group()" /></fold>
      </xsl:when>
      <!-- or just copy as-is for elements that don't have a @gr -->
      <xsl:otherwise>
        <xsl:copy-of select="current-group()" />
      </xsl:otherwise>
    </xsl:choose>
  </xsl:for-each-group>
</xsl:template>