如何使用XSLT合并两个兄弟姐妹



我需要合并两个兄弟姐妹

<table>
    <tbody>
    <tr>
    <td> table data</td>
    </tr>
    </tbody>
    <tbody>
    <tr>
    <td> table data</td>
    </tr>
    </tbody>
    </table>

预期输出:

<table>
<tbody>
<tr>
<td> table data</td>
</tr>
<tr><td> table data</td>
</tr>
</tbody>
</table>

我的XSLT代码是:

<xsl:template match="/">
   <xsl:for-each-group select="*" group-adjacent="boolean(self::tbody)">
         <tbody>
    <xsl:value-of select="."/>
         </tbody>
         </xsl:for-each-group>
    </xsl:template>

没有给出正确的输出。你能建议

您当前的XSLT

有很多问题
  1. 您的模板与文档节点匹配,在您的情况下,该节点是table元素的父,而不是table元素本身。当您尝试将tbody元素分组时,您的模板应匹配table元素
  2. xsl:value-of仅返回节点的文本值。您应该在此处使用xsl:copy-of(或与身份模板结合使用xsl:apply-templates)。您还应该选择组中的所有项目,而不仅仅是当前项目。
  3. 您尚未考虑除tbody
  4. 以外的节点下发生的情况

所以,您的XSLT应该看起来像这样....

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
  <xsl:output method="html" indent="yes" />
  <xsl:strip-space elements="*" />
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="table">
    <table>
      <xsl:for-each-group select="*" group-adjacent="boolean(self::tbody)">
        <xsl:choose>
          <xsl:when test="current-grouping-key()">
            <tbody>
              <xsl:apply-templates select="current-group()/*"/>
            </tbody>
          </xsl:when>
          <xsl:otherwise>
            <xsl:apply-templates select="current-group()" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each-group>
    </table>
  </xsl:template>
</xsl:stylesheet>

注意,如果您使用的是XSLT 3.0,则可以用以下方式替换身份模板:

<xsl:mode on-no-match="shallow-copy"/>

另一方面,如果您实际上仅使用XSLT 1.0,则需要进行Muenchian分组。这意味着定义这样的键:

<xsl:key name="table" match="table/*" use="boolean(self::tbody)" />

然后,而不是使用xsl:for-each-group,而是这样做(尽管这将对所有tbody元素进行分组,而不仅仅是相邻的元素)

<xsl:for-each select="*[generate-id() = generate-id(key('table', boolean(self::tbody))[1])]">

尝试此XSLT

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="html" indent="yes" />
  <xsl:strip-space elements="*" />
  <xsl:key name="table" match="table/*" use="boolean(self::tbody)" />
  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="table">
    <table>
      <xsl:for-each select="*[generate-id() = generate-id(key('table', boolean(self::tbody))[1])]">
        <xsl:choose>
          <xsl:when test="self::tbody">
            <tbody>
              <xsl:apply-templates select="key('table', true())/*"/>
            </tbody>
          </xsl:when>
          <xsl:otherwise>
            <xsl:apply-templates select="key('table', false())" />
          </xsl:otherwise>
        </xsl:choose>
      </xsl:for-each>
    </table>
  </xsl:template>
</xsl:stylesheet>

当然,毕竟,在这种情况下,Michael.hor257k的答案要简单得多。(尽管如果您确实陷入XSLT 1.0,那么绝对值得阅读Muenchian分组。

您的示例可以简单地通过:

来处理

XSLT 1.0

<xsl:stylesheet version="1.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="/table">
    <xsl:copy>
        <tbody>
            <xsl:copy-of select="tbody/*"/>
        </tbody>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

最新更新