我有一些必须转换为 xsl-fo 的 xml 文档(类似于 docbook)。一些文件包含诗歌,并且诗歌的行被写在单独的 p 标记中。经文由 br 标签分隔。有一些“页面”标签是不相关的,应该被忽略。
典型代码示例:
<h4>Headline</h4>
<p>1st line of 1st verse</p>
<p>2nd line of 1st verse</p>
<br/>
<p>1st line of 2nd verse</p>
<p>2nd line of 2nd verse</p>
<page n="100"/>
<p>3rd line of 2nd verse</p>
<h4>Other headline</h4>
对于 xsl-fo 输出,我想将一节经文的所有文本收集到一个 fo:block 中。目前,该机制适用于上述代码结构,但也有一些例外。这样做的实际方法是决定每个 p 标签: - 我是诗句的第一行吗?- 如果是:收集这节经文的所有文本并将其写入一个 fo:block,使用实际(第一个)p 标签的属性来设置块的格式 - 如果不是:内容被更早地处理,什么也不做。
第一行是紧接在 h4 或 br 标记之前的 ap 标记(或本身紧接在 br 标记之前的页面标记)。那个很容易开发。
对于给定的示例,收集经文的文本很容易:将所有以下兄弟姐妹分组,定义以 h4 或 br 标记结尾的组,然后我取第一组并使用所有 p 标记(忽略页面标记之间或结尾 h4 或br 标签)。
在代码中:
<xsl:for-each-group select="following-sibling::*" group-ending-with="br|h4">
<xsl:if test="position()=1">
<xsl:for-each select="current-group()[not(self::h4) and not(self::br) and not(self::page)]">
<xsl:apply-templates/>&crt;
</xsl:for-each>
</xsl:if>
</xsl:for-each-group>
现在来看一个类似的代码示例:
<h4>Headline</h4>
<p class="center">1</p>
<p>1st line of 1st verse</p>
<p>2nd line of 1st verse</p>
<br/>
<p class="center">2</p>
<p>1st line of 2nd verse</p>
<p>2nd line of 2nd verse</p>
<page n="100"/>
<p>3rd line of 2nd verse</p>
<h4>Other headline</h4>
现在居中的 p 就像以下经文的副标题。它不是真正的诗句,但就我的目的而言,如果它与真正的诗句文本分开就足够了。因此,获取当前经文的所有文本的稍微不同的规则是:将所有以下兄弟姐妹分组,定义组以 h4 或 br 标签或具有另一个类的 ap 标签结尾,然后是当前的 p 标签,然后我取第一组并使用所有 p 标签(忽略页面标签之间或结束 h4 或 br 标签)。
因此,我将当前 p 标签的类属性的值存储在一个名为 attributes 的变量中,并将组规则定义为:
<xsl:for-each-group select="following-sibling::*" group-ending-with="br|h4|p[normalize-space(@class) != $attributes]">
反过来,当试图确定 ap 标签是否是经文的第一行时,它不仅前面有一个 h4 或 br,而且还有另一个具有不同类属性值的 p 标签。
现在,这在我使用 Saxon-B9.1.0.6 的 Oxygen 测试环境中运行良好。但是必须使用 Saxon9.jar 在 java 中执行转换,并且在 xsl:for-each-group 的 group-ending-with 属性中使用变量会导致异常。
现在我有点卡住了。
能否以更好的方式定义分组条件?或者这可能根本不应该通过分组来完成,而是采用完全不同的方法?
源文件原样,标记可能不是最佳的,但它就是原样。这种转变并不新鲜,但后来适应了我们的需求。之前简单地避免了带有诗歌的源代码,但我想为此找到解决方案。
任何帮助将不胜感激。
此致,
克里斯蒂安·基尔霍夫