我需要将XML转换为XHTML。XML中有多个段落和嵌入式引文,例如
<para>SomeText</para>
<para><quote>SomeText</quote></para>
<para>SomeText</para>
我试过这个:
<xsl:choose>
<xsl:when test="//text/para">
<xsl:for-each select="//text">
<xsl:for-each select="//para">
<p><xsl:value-of select="text()"/></p>
</xsl:for-each>
</xsl:for-each>
</xsl:when>
<xsl:when test="//text/para[quote]">
<xsl:for-each select="//text">
<xsl:for-each select="//para/quote">
<p><q><xsl:value-of select="text()"/></q></p>
</xsl:for-each>
</xsl:for-each>
</xsl:when>
</xsl:choose>
但是,第二个条件只是被忽略了。
如@LarsH所示,请避免<xsl:for-each>
。使用模板匹配。
这个简单的转换:
<xsl:transform version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="para">
<p><xsl:apply-templates /></p>
</xsl:template>
<xsl:template match="quote">
<q><xsl:apply-templates /></q>
</xsl:template>
</xsl:transform>
将把这个转过来:
<text>
<para>SomeText</para>
<para><quote>SomeText</quote></para>
<para>SomeText</para>
</text>
到
<p>SomeText</p>
<p><q>SomeText</q></p>
<p>SomeText</p>
进一步阅读这里 SO:
- XSL 中的"调用模板"和"应用模板"之间有什么区别?
- 为什么 XSLT 默认输出所有文本?
- XSLT 应用模板的默认选择是什么?
问题是您正在使用忽略上下文(上下文文档除外)的 XPath 表达式,即以 //
开头的表达式。因此,如果文档中任何具有<quote>
子元素的 <para>
元素,则第一个条件将始终为 true,而第二个条件将永远不会达到。
实际上,您希望将for-each循环(或者可能更好的是,一组具有匹配模式和应用模板的模板)移动到选择/时间条件之外。事实上,一旦你有了正确的模板,你可能根本不需要选择/什么时候。
(从评论中移入一些信息)
XSLT 和 XPath 非常复杂,在尝试通过试错法获得某些工作之前,确实值得学习基础知识。这样您将节省大量时间。对于一般介绍,我会推荐
- XSLT 的工作原理
然后进行更高级的讨论 xsl:for-each
与 xsl:apply-templates
,请参阅
- Jeni Tennison 的博客文章匹配模板、命名模板还是每个模板?我的经验法则
- XSL 中的 for-each 和模板之间的差异?