0

我有一些必须转换为 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 属性中使用变量会导致异常。

现在我有点卡住了。

能否以更好的方式定义分组条件?或者这可能根本不应该通过分组来完成,而是采用完全不同的方法?

源文件原样,标记可能不是最佳的,但它就是原样。这种转变并不新鲜,但后来适应了我们的需求。之前简单地避免了带有诗歌的源代码,但我想为此找到解决方案。

任何帮助将不胜感激。

此致,

克里斯蒂安·基尔霍夫

4

1 回答 1

1

这个样式表:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="div[@class='poem']">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:for-each-group select="*" group-ending-with="br|h4">
                <div class="strophe">
                    <xsl:copy-of select="current-group()/self::p[not(@class)]"/>
                </div>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

使用此输入:

<div class="poem">
    <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>
</div>

输出:

<div class="poem">
    <div class="strophe">
        <p>1st line of 1st verse</p>
        <p>2nd line of 1st verse</p>
    </div>
    <div class="strophe">
        <p>1st line of 2nd verse</p>
        <p>2nd line of 2nd verse</p>
        <p>3rd line of 2nd verse</p>
    </div>
</div>

使用此输入:

<div class="poem">
    <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>
</div>

输出:

<div class="poem">
    <div class="strophe">
        <p>1st line of 1st verse</p>
        <p>2nd line of 1st verse</p>
    </div>
    <div class="strophe">
        <p>1st line of 2nd verse</p>
        <p>2nd line of 2nd verse</p>
        <p>3rd line of 2nd verse</p>
    </div>
</div>

所以,这个样式表:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="div[@class='poems']">
        <xsl:copy>
            <xsl:copy-of select="@*"/>
            <xsl:for-each-group select="*[preceding-sibling::h4]"
                                group-starting-with="h4">
                <div class="poem">
                    <xsl:for-each-group select="current-group()"
                                        group-ending-with="br">
                        <div class="strophe">
                            <xsl:copy-of select="current-group()
                                                  /self::p[not(@class)]"/>
                        </div>
                    </xsl:for-each-group>
                </div>
            </xsl:for-each-group>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

使用此输入:

<div class="poems">
    <h3>Poems</h3>
    <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>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>
</div>

输出:

<div class="poems">
    <div class="poem">
        <div class="strophe">
            <p>1st line of 1st verse</p>
            <p>2nd line of 1st verse</p>
        </div>
        <div class="strophe">
            <p>1st line of 2nd verse</p>
            <p>2nd line of 2nd verse</p>
            <p>3rd line of 2nd verse</p>
        </div>
    </div>
    <div class="poem">
        <div class="strophe">
            <p>1st line of 1st verse</p>
            <p>2nd line of 1st verse</p>
        </div>
        <div class="strophe">
            <p>1st line of 2nd verse</p>
            <p>2nd line of 2nd verse</p>
            <p>3rd line of 2nd verse</p>
        </div>
    </div>
</div>
于 2010-09-29T17:32:57.800 回答