代码之家  ›  专栏  ›  技术社区  ›  Pjoern

如何匹配子级元素以进行分组而不删除同级元素?

  •  0
  • Pjoern  · 技术社区  · 6 年前

    我只是一点也不到。我想把相邻的 w:p 元素。否则,不应再更改文档。在第一个XSLT转换中,我执行一个标识转换,在该转换中,我使用 for-each-group group-adjacent . 但是兄弟元素( w:tbl w:bdr )被扔了-这是我不想要的。 如何在不删除兄弟元素的情况下创建组? 我已经尝试了几种方法:包括 wx:sub-section 具有另一层的元素,包括 w: 第页 每组 . 没有成功。帮助我的是用 (然后在 也一样)。但是,在最后,文档的某些部分总是被删除。

    我的源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:小节 //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>
    
    1 回复  |  直到 5 年前
        1
  •  1
  •   Martin Honnen    6 年前

    我能想到的最短的办法是 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" 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>