给定以下XML文档:
<dialog>
<speech speaker="Robert">
<line>"Once more into the breach", he said.</line>
I can't believe him. I just <emphasis>can't</emphasis> believe him!
</speech>
</dialog>
我想尝试捕获speech
中不在line
中的每一个元素,并将其封装在line
中,但我需要捕获任何其他元素(例如,上面示例中的emphasis
)。
我想达到的结果是:
<dialog>
<speech speaker="Robert">
<line>"Once more into the breach", he said.</line>
<line>I can't believe him. I just <emphasis>can't</emphasis> believe him!</line>
</speech>
</dialog>
我使用的是libxslt
和libxml
,所以我一直使用XSLT1.0。
XSLT1.0中实现这一点的一种方法是通过同级递归,如下例所示:
<xsl:stylesheet
version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml"/>
<xsl:template match="@* | node()" name="identity">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="speech">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="node()[1]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="speech/line">
<xsl:call-template name="identity"/>
<xsl:apply-templates select="following-sibling::node()[1]"/>
</xsl:template>
<xsl:template match="speech/node()[not(self::line)
and (not(preceding-sibling::node())
or
preceding-sibling::node()[1][self::line])]">
<xsl:if test="normalize-space() or following-sibling::node()[1][not(self::line)]">
<line>
<xsl:call-template name="identity"/>
<xsl:apply-templates select="following-sibling::node()[1][not(self::line)]"/>
</line>
</xsl:if>
<xsl:apply-templates select="following-sibling::line[1]"/>
</xsl:template>
<xsl:template match="speech/node()[not(self::line)
and preceding-sibling::node()[1][not(self::line)]]">
<xsl:call-template name="identity"/>
<xsl:apply-templates select="following-sibling::node()[1][not(self::line)]"/>
</xsl:template>
</xsl:stylesheet>
有了这个样式表,一个类似的输入示例
<dialog>
<speech speaker="Robert">
<line>"Once more into the breach", he said.</line>
I can't believe him. I just <emphasis>can't</emphasis> believe him!
</speech>
<speech speaker="Foo">This is a test.
<line>This line is wrapped and should be copied unchanged.</line>
<em>This</em> needs to be <it>wrapped</it>.
</speech>
<speech speaker="Bar"> <em>This</em> should be wrapped.
<line>This line is wrapped and should be copied unchanged.</line>
<it>Test</it>
</speech>
</dialog>
转化为
<dialog>
<speech speaker="Robert"><line>"Once more into the breach", he said.</line><line>
I can't believe him. I just <emphasis>can't</emphasis> believe him!
</line></speech>
<speech speaker="Foo"><line>This is a test.
</line><line>This line is wrapped and should be copied unchanged.</line><line>
<em>This</em> needs to be <it>wrapped</it>.
</line></speech>
<speech speaker="Bar"><line> <em>This</em> should be wrapped.
</line><line>This line is wrapped and should be copied unchanged.</line><line>
<it>Test</it>
</line></speech>
</dialog>