如何匹配子级元素进行分组而不丢弃兄弟姐妹?

问题描述 投票:0回答:1

我只是没有到达这里。我想将相邻的w:p元素分组。否则,不应再更改文档。在第一个XSLT转换中,我进行了身份转换,其中我使用for-each-groupgroup-adjacent创建组。但兄弟元素(w:tblw:bdr)被删除 - 这是我不想要的。如何在不删除兄弟元素的情况下创建组?我已经尝试了几种方法:将wx:sub-section元素包含在另一层中,其中包括w:p元素和另一层 - 将它们与for-each-group的模板匹配中的兄弟元素分开。没有成功。有点帮助我的是用for-each-group的模板匹配搜索几个模式(然后在group-adjacent中)。但最后,文档的某些部分总是被丢弃。

我的源码XML(简化版)

<wx:sect>
   <w:p val='1'>...</w:p>
   <w:p val='1'>...</w:p>
   <wx:sub-section>
      <w:p val='1'>...</w:p>
      <w:p val='1'>...</w:p>
      <w:tbl>...<w:tbl>
      <w:bdr>...</w:bdr>
      <w:p val='2'>...</w:p>
      <w:p val='2'>...</w:p>
      <w:bdr>...</w:bdr>
      <w:p val='1'>...</w:p>
      <w:p val='1'>...</w:p>
      <w:p val='3'>...</w:p>
      <w:p val='3'>...</w:p>
         <wx:sub-section>
            same structure one step down
            <wx:sub-section>
               same structure one step down (and so forth up to 5 steps)
            </wx:sub-section>
         </wx:sub-section>
    </wx:sub-section>
</wx:sect>

我的样式表(xslt 2.0)

我知道使用//wx:sect/wx:sub-section我只使用第一层wx:sub-section(无论如何都要发布它,以获得更好的概述)。到目前为止,我使用//wx:sect/wx:sub-section[w:p and not(wx:sub-section)]捕获其他图层,但这不正确,因为它们也会掉线。另一种可能性是单独匹配各层(//wx:sect/wx:sub-section/wx:sub-section ......)。这似乎也不正确。

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

<xsl:template match="/wx:sect/wx:sub-section">
        <xsl:for-each-group select="w:p"
            group-adjacent="@w:val">
            <xsl:choose>
                <xsl:when test="current-grouping-key() = '1">
                    <div class="wrap1">
                        <xsl:copy-of select="current-group()"/>
                    </div>
                </xsl:when>
                <xsl:when test="current-grouping-key() = '2'">
                    <div class="wrap2">
                        <xsl:copy-of select="current-group()"/>
                    </div>
                </xsl:when>
                ...
                <xsl:otherwise>
                    <xsl:copy-of select="current-group()"/>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each-group>
    </xsl:template>

想要结果

<wx:sect>
   <wrapper1>
     <w:p val='1'>...</w:p>
     <w:p val='1'>...</w:p>
   </wrapper1>
   <wx:sub-section>
     <wrapper1>
        <w:p val='1'>...</w:p>
        <w:p val='1'>...</w:p>
     </wrapper1>
     <w:tbl>...<w:tbl>
     <w:bdr>...</w:bdr>
     <wrapper2>
        <w:p val='2'>...</w:p>
        <w:p val='2'>...</w:p>
     </wrapper2>
     <w:bdr>...</w:bdr>
     <wrapper1>
        <w:p val='1'>...</w:p>
        <w:p val='1'>...</w:p>
     </wrapper1>
     <wrapper3>
        <w:p val='3'>...</w:p>
        <w:p val='3'>...</w:p>
     </wrapper3>
        <wx:sub-section>
           same structure
           <wx:sub-section>
              same structure (up to 5 steps)
           </wx:sub-section>
        </wx:sub-section>
   </wx:sub-section>
</wx:sect>
xml xpath xslt-2.0 xslt-grouping
1个回答
1
投票

我能够提出的最短的方法是https://xsltfiddle.liberty-development.net/bFDb2Cz,它使用XSLT 3和复合分组键来测试w:p元素的邻接性以及它在一个分组中的@val值:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:w="http://example.com/w"
    exclude-result-prefixes="xs"
    version="3.0">

  <xsl:output indent="yes"/>

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

  <xsl:template match="*[w:p[@val]]">
      <xsl:copy>
          <xsl:for-each-group select="*" composite="yes" group-adjacent="boolean(self::w:p), @val">
              <xsl:choose>
                  <xsl:when test="current-grouping-key()[1]">
                      <div class="wrapper{current-grouping-key()[2]}">
                          <xsl:apply-templates select="current-group()"/>
                      </div>
                  </xsl:when>
                  <xsl:otherwise>
                      <xsl:apply-templates select="current-group()"/>
                  </xsl:otherwise>
              </xsl:choose>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

<xsl:mode on-no-match="shallow-copy"/>只是一个XSLT 3声明方式,表示你想使用身份转换。

如果你不能在XSLT 2中移动到XSLT 3,你需要嵌套两个xsl:for-each(首先检查group-adjacent="boolean(self::w:p)",然后在你内部获得一个真正的分组键,你使用xsl:for-each-group select="current-group()" group-adjacent="@val"或apply-templates用于其他元素)或者你需要一些结合这两个值,例如group-adjacent="concat((boolean(self::w:p), '|', @val))"虽然这有点难看然后在里面检查并提取两个不同的值。

XSLT 2位于http://xsltransform.hikmatu.com/gWcDMey/1并且嵌套分组

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:w="http://example.com/w"
    exclude-result-prefixes="xs"
    version="2.0">

  <xsl:output indent="yes"/>

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

  <xsl:template match="*[w:p[@val]]">
      <xsl:copy>
          <xsl:for-each-group select="*" group-adjacent="boolean(self::w:p)">
              <xsl:choose>
                  <xsl:when test="current-grouping-key()">
                      <xsl:for-each-group select="current-group()" group-adjacent="@val">
                          <div class="wrapper{current-grouping-key()}">
                              <xsl:apply-templates select="current-group()"/>
                          </div>                          
                      </xsl:for-each-group>
                  </xsl:when>
                  <xsl:otherwise>
                      <xsl:apply-templates select="current-group()"/>
                  </xsl:otherwise>
              </xsl:choose>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>
© www.soinside.com 2019 - 2024. All rights reserved.