我有一个XML结构如下:
<document>
<text>Here is some text </text>
<bold>and this part is in bold</bold>
<text> and this part is not.</text>
<newline />
<bold>foo foo foo</bold>
<newline />
<newline />
<text>bar bar bar</text>
</document>
我想编写一个XSLT转换,它产生如下输出:
<document>
<line>Here is some text <b>and this part is in bold</b> and this part is not.</line>
<line><b>foo foo foo</b></line>
<blankline>
<line>bar bar bar</line>
</document>
我觉得这是一个问题,需要一个循环结构而不是文件/ *,直到跟随兄弟:name()=&#39; Newline&#39;,但我不能弄清楚如何构建它
这是我想尝试编写的算法:
<xsl:template match="document">
<xsl:apply-templates select="*[1]"/>
</xsl:template>
<xsl:template match="text | bold">
<line>
<xsl:if test="name() = 'text'>
<xsl:value-of select="." />
</xsl:if>
<xsl:if test="name() = 'bold'>
<b><xsl:value-of select="." /></b>
</xsl:if>
<!-- I want a loop which runs over all following 'text' or 'bold' elements, but stops before the next Newline is reached -->
<xsl:for-each select="preceding-sibling::*[self:newline]">
<xsl:if test="name() = 'text'>
<xsl:value-of select="." />
</xsl:if>
<xsl:if test="name() = 'bold'>
<b><xsl:value-of select="." /></b>
</xsl:if>
</xsl:for-each>
<!-- I then want to apply-templates on the next item (the newline) -->
<xsl:apply-templates select="following-sibling" />
</line>
</xsl:template>
<xsl:template match="newline">
<!-- i need to work out how to ignore single <newline> here but output <blankline> if more than one <newline /> is together. -->
<xsl:apply-templates select="following-sibling" />
</xsl:template>
答案 0 :(得分:1)
当您使用XSLT 2.0时,最好的办法是使用xsl:for-each-group
来解决您的问题。您需要对内容进行分组,以便每个组以newline
元素结尾。然后,您可以简单地处理每个组中的元素:
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0">
<xsl:template match="document">
<xsl:copy>
<xsl:for-each-group select="*" group-ending-with="newline">
<!-- context node is set to the first element in the group -->
<xsl:apply-templates select="." mode="create-line"/>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
<!-- ignore any newline element where the next element is also a newline -->
<xsl:template match="newline[following-sibling::*[1][self::newline]]"/>
<!-- output a blankline element for the second of a pair of newlines -->
<xsl:template match="newline[preceding-sibling::*[1][self::newline]]" mode="create-line">
<blankline/>
</xsl:template>
<!-- use a wildcard to match and wrap the groups -->
<xsl:template match="*" mode="create-line">
<line><xsl:apply-templates select="current-group()"/></line>
</xsl:template>
<xsl:template match="bold">
<b><xsl:apply-templates/></b>
</xsl:template>
</xsl:stylesheet>
我使用了一种模式来简化节点组的处理 - 你可以简单地使用text
元素的内置模板等等。
答案 1 :(得分:0)
我的理解是,您的总体目标可归纳为:
文本和粗体元素应该被转录,后者用标签注释。
这些转录组合在一起成为一个单独的行元素。源中的换行元素将这些组分开。
多个换行元素会导致空行元素的输出。
如果上述内容准确无误,那么您可以将输入分解为组,其中元素组与其他元素组分开。然后根据您提出的规则单独处理每个组:
<xsl:for-each-group select="//node()" group-adjacent="boolean(name(.)='newline')">
<xsl:choose>
<xsl:when test="current-grouping-key()='true'">
<xsl:if test="count(current-group()) gt 1">
<blankline/>
</xsl:if>
</xsl:when>
<xsl:otherwise>
<line>
<!--Process text and bold elements here.-->
</line>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
答案 2 :(得分:0)
如果您遇到XSLT 1.0,它会更棘手但可能:
<xsl:template match="document">
<document>
<xsl:apply-templates select="*[not(self::newline)][1]|newline/following-sibling::*[not(self::newline)][1]|newline/following-sibling::*[1][self::newline]" mode="first"/>
</document>
</xsl:template>
<xsl:template match="newline" mode="first">
<blankline />
</xsl:template>
<xsl:template match="*" mode="first">
<line>
<xsl:apply-templates select="self::*|following-sibling::*[generate-id(following-sibling::newline[1]) = generate-id(current()/following-sibling::newline[1])]" />
</line>
</xsl:template>
<xsl:template match="text">
<xsl:value-of select="." />
</xsl:template>
<xsl:template match="bold">
<b>
<xsl:value-of select="." />
</b>
</xsl:template>