这种转变:
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:ext="http://exslt.org/common">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kSameNameAdj" match="*"
use="concat(generate-id(..),
'+',
generate-id(preceding-sibling::*[not(name()=name(current()))][1])
)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/">
<xsl:variable name="vrtfPass1">
<xsl:apply-templates select="node()"/>
</xsl:variable>
<xsl:apply-templates select="ext:node-set($vrtfPass1)" mode="compress"/>
</xsl:template>
<xsl:template name="explode" match=
"*[contains(name(),'_')
and not(substring(name(),1,1)='_')
and not(substring(name(), string-length(name()))='_')
]">
<xsl:param name="pName" select="name()"/>
<xsl:param name="pText" select="text()"/>
<xsl:choose>
<xsl:when test="not($pName)">
<xsl:value-of select="$pText"/>
</xsl:when>
<xsl:otherwise>
<xsl:element name="{substring-before(concat($pName, '_'), '_')}">
<xsl:call-template name="explode">
<xsl:with-param name="pName" select="substring-after($pName, '_')"/>
<xsl:with-param name="pText" select="$pText"/>
</xsl:call-template>
</xsl:element>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="/" name="fold" mode="compress">
<xsl:param name="pDoc" select="/"/>
<xsl:choose>
<xsl:when test="not($pDoc//*[name()=name(following-sibling::*[1])])">
<xsl:copy-of select="$pDoc"/>
</xsl:when>
<xsl:otherwise>
<xsl:variable name="vrtfThisPass">
<xsl:apply-templates select="$pDoc/*" mode="compress"/>
</xsl:variable>
<xsl:call-template name="fold">
<xsl:with-param name="pDoc" select="ext:node-set($vrtfThisPass)"/>
</xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
<xsl:template match="node()|@*" mode="compress">
<xsl:copy>
<xsl:apply-templates select="@*|node()[1]" mode="compress"/>
</xsl:copy>
<xsl:apply-templates select="following-sibling::node()[1]" mode="compress"/>
</xsl:template>
<xsl:template match="*[name()=name(following-sibling::*[1])]" mode="compress">
<xsl:element name="{name()}">
<xsl:apply-templates mode="compress" select=
"key('kSameNameAdj',
concat(generate-id(..),
'+',generate-id(preceding-sibling::*)
)
)/node()"/>
</xsl:element>
<xsl:apply-templates mode="compress" select=
"key('kSameNameAdj',
concat(generate-id(..),
'+',generate-id(preceding-sibling::*)
)
)
[last()]/following-sibling::node()[1]
"/>
</xsl:template>
</xsl:stylesheet>
当应用于以下 XML 文档时(提供的文档,扩展为更具挑战性):
<root>
<x>This is:</x>
<a_b_c>hello</a_b_c>
<a_b_c_d>my</a_b_c_d>
<a_b_c1>wonderful</a_b_c1>
<a_b_c>world</a_b_c>
<a_b>!</a_b>
<y>The End</y>
</root>
产生想要的正确结果:
<root>
<x>This is:</x>
<a>
<b>
<c>hello<d>my</d>
</c>
<c1>wonderful</c1>
<c>world</c>!</b>
</a>
<y>The End</y>
</root>
说明:
.1。这是一个多遍变换。第一遍将 XML 文档转换为:
<root>
<x>This is:</x>
<a>
<b>
<c>hello</c>
</b>
</a>
<a>
<b>
<c>
<d>my</d>
</c>
</b>
</a>
<a>
<b>
<c1>wonderful</c1>
</b>
</a>
<a>
<b>
<c>world</c>
</b>
</a>
<a>
<b>!</b>
</a>
<y>The End</y>
</root>
.2. 随后的传递,每个将具有相同名称的任何相邻元素组压缩为具有该名称的单个元素- 然后递归处理结果,直到不再有任何一组超过一个具有相同名称的相邻兄弟元素。
.3. 第一遍使用恒等规则。
.4. 接下来的遍使用“压缩”模式下的精细标识模板。