我正在寻找一个可以转变的解决方案
<p>
<hi rend="bold">aa</hi>
<hi rend="bold">bb</hi>
<hi rend="bold">cc</hi>
Perhaps some text.
<hi rend="italic">dd</hi>
<hi rend="italic">ee</hi>
Some more text.
<hi rend="italic">ff</hi>
<hi rend="italic">gg</hi>
Foo.
</p>
到
<p>
<hi rend="bold">aabbcc</hi>
Perhaps some text.
<hi rend="italic">ddee</hi>
Perhaps some text.
<hi rend="italic">ffgg</hi>
Foo.
</p>
但我的解决方案应该_不硬编码元素和属性值的名称(斜体,粗体)。 XSLT应该真正连接具有相同名称和相同属性值的所有兄弟元素。其他一切都应保持不变。
我已经看过那些已经存在的解决方案,但它们似乎都没有满足我的所有要求。
如果有人为此提供了方便的XSLT样式表,我将非常感激。
答案 0 :(得分:6)
此XSLT 2.0样式表将使用公共rend属性合并相邻元素。
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[*/@rend]">
<xsl:copy>
<xsl:apply-templates select="@*" />
<xsl:for-each-group select="node()" group-adjacent="
if (self::*/@rend) then
concat( namespace-uri(), '|', local-name(), '|', @rend)
else
''">
<xsl:choose>
<xsl:when test="current-grouping-key()" >
<xsl:for-each select="current-group()[1]">
<xsl:copy>
<xsl:apply-templates select="@* | current-group()/node()" />
</xsl:copy>
</xsl:for-each>
</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:for-each-group select="node()" group-adjacent="
string-join(for $x in self::*/@rend return
concat( namespace-uri(), '|', local-name(), '|', @rend),'')">
使用您个人认为更具可读性的表格。
答案 1 :(得分:1)
该属性的名称(例如rend
)是否已知?在那种情况下,我认为你想要
<xsl:template match="p">
<xsl:copy>
<xsl:for-each-group select="*" group-adjacent="concat(node-name(.), '|', @rend)">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="@rend"/>
<xsl:apply-templates select="current-group()/node()"/>
</xsl:element>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
[编辑] 如果在元素之间可能存在包含内容的文本节点,正如您在输入的编辑中所示,那么您需要像示例一样嵌套到分组
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:template match="p">
<xsl:copy>
<xsl:for-each-group select="node() except text()[not(normalize-space())]" group-adjacent="boolean(self::*)">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<xsl:for-each-group select="current-group()" group-by="concat(node-name(.), '|', @rend)">
<xsl:element name="{name()}" namespace="{namespace-uri()}">
<xsl:copy-of select="@rend"/>
<xsl:apply-templates select="current-group()/node()"/>
</xsl:element>
</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>
答案 2 :(得分:1)
如果有偶然的访问者出现并想知道是否有针对此问题的XSLT 1.0解决方案,我提供以下内容。 请注意,我并没有试图减少肖恩和马丁的正确答案;我只是提供一些味道。
当这个XSLT 1.0解决方案:
时<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output omit-xml-declaration="no" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key
name="kFollowing"
match="hi"
use="concat(@rend, '+', generate-id(following-sibling::text()[1]))" />
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<p>
<xsl:apply-templates
select="
hi[generate-id() =
generate-id(
key('kFollowing',
concat(@rend, '+', generate-id(following-sibling::text()[1])))[1])]" />
</p>
</xsl:template>
<xsl:template match="hi">
<xsl:copy>
<xsl:apply-templates
select="@*|key('kFollowing',
concat(@rend, '+', generate-id(following-sibling::text()[1])))/text()" />
</xsl:copy>
<xsl:apply-templates select="following-sibling::text()[1]" />
</xsl:template>
</xsl:stylesheet>
...适用于OP的原始XML:
<p>
<hi rend="bold">aa</hi>
<hi rend="bold">bb</hi>
<hi rend="bold">cc</hi>
Perhaps some text.
<hi rend="italic">dd</hi>
<hi rend="italic">ee</hi>
Some more text.
<hi rend="italic">ff</hi>
<hi rend="italic">gg</hi>
Foo.
</p>
...产生了所需的结果:
<p>
<hi rend="bold">aabbcc</hi>
Perhaps some text.
<hi rend="italic">ddee</hi>
Perhaps some text.
<hi rend="italic">ffgg</hi>
Foo.
</p>