如何在不删除兄弟姐妹的情况下匹配子级元素进行分组?
How to match sub-level elements for grouping without dropping siblings?
我在这里一事无成。我想对相邻的 w:p
元素进行分组。否则不应进一步更改文档。在第一个 XSLT 转换中,我进行了身份转换,在其中我创建了具有 for-each-group
和 group-adjacent
的组。但是兄弟元素(w:tbl
、w: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
的第一层(post 无论如何,为了更好的概述)。到目前为止,我使用 //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>
我能想到的最短方法是 https://xsltfiddle.liberty-development.net/bFDb2Cz,它使用 XSLT 3 和复合分组键来测试 w:p
元素及其 [=13= 的邻接关系] 一组中的值:
<?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>
我在这里一事无成。我想对相邻的 w:p
元素进行分组。否则不应进一步更改文档。在第一个 XSLT 转换中,我进行了身份转换,在其中我创建了具有 for-each-group
和 group-adjacent
的组。但是兄弟元素(w:tbl
、w: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
的第一层(post 无论如何,为了更好的概述)。到目前为止,我使用 //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>
我能想到的最短方法是 https://xsltfiddle.liberty-development.net/bFDb2Cz,它使用 XSLT 3 和复合分组键来测试 w:p
元素及其 [=13= 的邻接关系] 一组中的值:
<?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>