我是这个XSLT的新手,我无法弄清楚如何:
这是xml的片段,我从以下开始:
<Article>
<Bullettext>10,00 </Bullettext>
<Bullettext>8,00 </Bullettext>
</Article>
<Article>
<something>some text</something>
</Article>
<Article>
<Corpsdetexte>Bulgaria</Corpsdetexte>
<Bullettext>15,0 </Bullettext>
<Bullettext>10,0 </Bullettext>
</Article> `
Run Code Online (Sandbox Code Playgroud)
这就是我想要的输出:
<LIST>
<ITEM>12,00 </ITEM>
<ITEM>10,00 </ITEM>
<ITEM>8,00 </ITEM>
</LIST>
<P>
<something>some text</something>
</P>
<P>
<Corpsdetexte>Bulgaria</Corpsdetexte>
</P>
<LIST>
<ITEM>15,0 </ITEM>
<ITEM>10,0 </ITEM>
</LIST>
Run Code Online (Sandbox Code Playgroud)
有任何想法吗??
根据您对Rubens Farias的回答的评论(实际上,您应该编辑要包含的问题),似乎您需要一种通用方法将任何相邻BulletText
元素组转换为列表.这让我们得到两个问题:我们如何找到这样的群体,并找到它们,我们如何将它们转换为列表?
为了找到一个群体,我们需要寻找所有BulletText
其前一个兄弟元素是不是一个BulletText
元素.其中每一个都开始一个组,这些是我们要转换成列表的元素.所以我们要做的第一件事就是创建一个可以找到它们的XPath表达式:
BulletText[not(preceding-sibling::*[1][name()='BulletText'])]
Run Code Online (Sandbox Code Playgroud)
如果你看一下XPath表达式中的谓词,那就是我所说的我们需要做的事情:它匹配一个BulletText
元素,如果不是它的第一个前面的兄弟(preceding-sibling::*[1]
)的名字是BulletText
.请注意,如果该元素有没有前面的兄弟,这个表达式会匹配.
所以现在我们可以创建一个匹配这些start-of-group元素的模板.我们在这个模板中放了什么?我们将把这些元素转换为LIST
元素,因此模板开始看起来像:
<LIST>
...
</LIST>
Run Code Online (Sandbox Code Playgroud)
很容易.但是,我们如何找到将填充该列表的元素?我们有两种情况需要处理.
第一个很简单:如果以下所有兄弟BulletText
元素都是元素,我们希望使用此元素及其所有后续兄弟元素填充列表.
第二个更难.如果有一个不是BulletText
元素的跟随兄弟,我们希望我们的列表是当前元素的父元素的所有子元素,从当前元素开始并在stop元素之前结束.下面是我们需要使用count()
函数计算起始和结束索引的position()
函数,以及查找每个元素位置的函数.
完成的模板如下所示:
<xsl:template match="BulletText[not(preceding-sibling::*[1][name()='BulletText'])]">
<!-- find the element that we want to stop at -->
<xsl:variable name="stop" select="./following-sibling::*[name() != 'BulletText'][1]"/>
<LIST>
<xsl:choose>
<!-- first, the simple case: there's no element we have to stop at -->
<xsl:when test="not($stop)">
<xsl:apply-templates select="." mode="item"/>
<xsl:apply-templates select="./following-sibling::BulletText" mode="item"/>
</xsl:when>
<!-- transform all elements between the start and stop index into items -->
<xsl:otherwise>
<xsl:variable name="start_index" select="count(preceding-sibling::*) + 1"/>
<xsl:variable name="stop_index" select="count($stop/preceding-sibling::*)"/>
<xsl:apply-templates select="../*[position() >= $start_index
and position() <= $stop_index]"
mode="item"/>
</xsl:otherwise>
</xsl:choose>
</LIST>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)
您还需要两个其他模板.一个将BulletText
元素转换为项目 - 我们mode
在这里使用,以便我们可以将它应用于BulletText
元素而无需调用我们当前使用的模板:
<xsl:template match="BulletText" mode="item">
<ITEM>
<xsl:value-of select="."/>
</ITEM>
</xsl:template>
Run Code Online (Sandbox Code Playgroud)
然后你还需要一个模板来保持BulletText
我们的第一个模板不匹配的元素生成任何输出(因为如果我们使用身份变换,如果我们不这样做,它们就会被复制):
<xsl:template match='BulletText'/>
Run Code Online (Sandbox Code Playgroud)
由于XSLT的模板优先级规则的神奇之处BulletText
,两个模板匹配的任何元素都将被第一个转换,而这一个将捕获其余的元素.
只需将这三个模板添加到身份转换中,就可以了.