我的XML如下所示,我想使用XSLT 2.0将其转换为所提到的预期xml格式。 child1
和child2
只是样本,在实际的XML中,可能有几个具有不同名称的节点。我是XSL的初学者
<?xml version="1.0" encoding="utf-8" ?>
<properties xmlns="http://www.sss.org">
My Parent level text 1 <b> i am bold</b> not bold
<child1>
text1 of first child
<child1val attribute1="testval">36-37</child1val>
text2 of child <sub> subscript</sub>
</child1>
<child2>
text1 of first child2
<child2val attribute1="testval">444</child2val>
<child2val>555</child2val>
text2 of child2
</child2>
My Parent level text3 in <b> i am bold</b>
</properties>
预期结果:
<properties xmlns="http://www.sss.org">
<text>
My Parent level text 1 <b> i am bold</b> not bold
</text>
<child1>
<text> text1 of first child </text>
<child1val attribute1="testval">36-37</child1val>
<text> text2 of child <i> i m italic</i></text>
</child1>
<child2>
<text> text1 of second child2</text>
<child2val attribute1="testval">444</child2val>
<child2val>555</child2val>
<text> text2 of child2</text>
</child2>
My Parent level text3 in <b> i am bold</b>
答案 0 :(得分:2)
缩进XML的方式无助于您提出问题的方式。例如,请考虑这个简化的XML样本。
<properties>
My Parent level text 1 <b> i am bold</b> not bold
<child1>
text1 of first child
</child1>
</properties>
它的布局方式似乎意味着属性元素有两个子元素。但事实并非如此,它有四个孩子。更明确的缩进就像这样
<properties>
My Parent level text 1
<b> i am bold</b>
not bold
<child1>
text1 of first child
</child1>
</properties>
看起来 text 元素只需要包围前三个子元素,而不是 child1 元素。目前尚不清楚为什么 b 会在 text 元素中包围,但 child1 却没有,但我猜是因为 b 和 i (以及 sub ?)是'html'元素,但 child1 不是。
做出这个假设,您可以使用XSLT 2.0中的 xsl:for-each-group 命令以及 group-adjacent 属性来解决此问题。您正在对相邻节点进行分组(如果它们是文本节点),或 b 或 i 或 sub ,则命令将如下所示
<xsl:for-each-group select="node()"
group-adjacent="boolean(self::b|self::i|self::sub|self::text())">
在此范围内,您可以检查 current-grouping-key()功能,以确定是否需要使用 text 元素
<xsl:choose>
<xsl:when test="current-grouping-key()">
<text>
<xsl:apply-templates select="current-group()" />
</text>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()" />
</xsl:otherwise>
</xsl:choose>
此代码本身可能只需要为具有其他元素作为子元素的元素运行,而不是针对仅具有单个文本节点作为子元素的元素运行。这意味着它将存在于此匹配的模板中
<xsl:template match="*[*]">
其他节点将与XSLT identity template匹配并复制。
试试这个XSLT
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xpath-default-namespace="http://www.sss.org" xmlns="http://www.sss.org">
<xsl:output method="xml" indent="yes" />
<xsl:strip-space elements="*" />
<xsl:template match="*[*]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:for-each-group select="node()" group-adjacent="boolean(self::b|self::i|self::sub|self::text())">
<xsl:choose>
<xsl:when test="current-grouping-key()">
<text>
<xsl:apply-templates select="current-group()" />
</text>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="current-group()" />
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
(注意这里使用命名空间,因为XML中的所有元素都在命名空间中)。
这应输出以下内容
<properties xmlns="http://www.sss.org">
<text>
My Parent level text 1 <b> i am bold</b> not bold
</text>
<child1>
<text>
text1 of first child
</text>
<child1val attribute1="testval">36-37</child1val>
<text>
text2 of child <sub> subscript</sub>
</text>
</child1>
<child2>
<text>
text1 of first child2
</text>
<child2val attribute1="testval">444</child2val>
<child2val>555</child2val>
<text>
text2 of child2
</text>
</child2>
<text>
My Parent level text3 in <b> i am bold</b>
</text>
</properties>