XSLT是否有重叠元素?

时间:2010-08-16 17:04:34

标签: xml xslt xpath

所以这篇文章的标题可能有点误导,但这是我能想到的最好的。我正在开发一个使用TEI编码文本的项目。我当前工作的一个要求是编写XSL转换以将XML编码的文本呈现为HTML。在大多数情况下,没问题。不过,我有点困在这个问题上:

    <l>There is <delSpan spanTo="A1"/>deleted text spanning</l>
    <l>multiple lines here.<anchor xml:id="A1"/> More text...</l>

或者,在其他情况下:

    <delSpan spanTo="A2"/>
    <l>Several deleted lines -- the delspan marker can appear </l>
    <l>outside of an l element.... </l>
    <anchor xml:id="A2"/>

(如果您不熟悉TEI:l =一行文字; delSpan =已删除文本的范围,包括多于一行,一页或更小的单位。)

目标是在delSpan(A1)及其对应的锚点(A1)之间显示文本 - “删除文本跨越/此处有多行” - 带有一些表示删除的格式(例如,text-decoration = “线通”)。现在,有一个“l”元素的模板可以处理大多数文本格式 - 或者至少调用其他模板来完成它。

但这些单身标签是异常的;所有其他格式化/标记都是使用实际包含要格式化的文本的标记来完成的。我是否正确地假设我需要在“l”模板中处理delSpan和锚元素?处理此问题并处理伪重叠元素的最优雅方法是什么?

很抱歉,如果这是一个noob问题,或者我没有提供足够的信息。我主要是一个很少有XSLT经验的C / C ++程序员,所以我很感激任何建议。

2 个答案:

答案 0 :(得分:2)

此样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="delSpan|anchor"/>
    <xsl:template match="text()[preceding::delSpan[1]/@spanTo=following::anchor[1]/@xml:id]">
        <span style="text-decoration:line-through;">
            <xsl:value-of select="."/>
        </span>
    </xsl:template>
</xsl:stylesheet>

输出:

<doc>
    <l>There is <span style="text-decoration:line-through;">deleted text spanning</span></l>
    <l><span style="text-decoration:line-through;">multiple lines here.</span> More text...</l>
</doc>

注意:使用前后轴及其在文档顺序中的含义。我们不会覆盖匹配l元素的任何previus模板。 <{1}}和delSpan也可能没有条纹。

答案 1 :(得分:1)

这里的主要问题是delSpan元素不是父元素,它的结束和结束“元素”是一个空元素(anchor用于关闭)。打开和关闭之间的链接是通过引用xml:id标记来完成的。

这个问题有多个解决方案,这里有一个从头到尾,假设您使用XSLT 1.0(使用XSLT 2.0更容易)。这个想法很简单:找到所有兄弟姐妹并应用它们,但前提是它们本身后面跟着一个兄弟anchor并使用正确的xml:id

<xsl:template match="delSpan">
   <xsl:variable select="@spanTo" name="spanTo" />
   <xsl:apply-templates select="following-sibling::*[following-sibling::anchor[@xml:id = $spanTo]" mode="deleted" />
</xsl:template>

<!--
     do this for all elements you need to treat inside delSpan
     if they have children, remember to use apply-templates with mode deleted
 -->
<xsl:template match="l" mode="deleted">
   <strike><xsl:value-of select="." /></strike>
</xsl:template>

我不是100%确定这是完全正确的。如果<delSpan>可以嵌套,则可能会出错。如果你很幸运,Dimitri Novatchev也会走过去看看。