具有重叠元素的XSLT?

3

所以,这篇文章的标题可能有点误导人,但这是我能想到的最好的标题。我正在处理一个使用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="line-through")。现在,有一个“l”元素的模板,它处理大多数文本格式化,或者至少调用其他模板来完成它。
但这些单例标记是一个反常现象;所有其他格式/标记都是通过实际包含它们所需格式化的文本的标记来完成的。我是否正确地认为我需要在“l”模板中处理delSpan和anchor元素?最优雅的方法是如何解决这个问题并处理伪重叠元素?如果我没有提供足够的信息或者这是一个初学者的问题,对不起。我主要是C/C++程序员,很少有XSLT经验,所以我感谢任何建议。
2个回答

3
这个样式表:
<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元素的模板。 delSpananchor 也可能不被剥离。


谢谢!这很简单、优雅,现在对我来说非常清晰明了。我正在享受 XSLT 的速成课程。 - Andrew Forrester
@Andrew Forrester:不客气!随时问我。 - user357812

1

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

有多种解决此问题的方法,以下是我脑海中的一种,假设您使用XSLT 1.0(使用XSLT 2.0更容易)。这个想法很简单:找到所有兄弟姐妹并应用它们,但仅当它们自己后面跟着具有正确xml:id的兄弟姐妹anchor时才应用:

<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也会过来看一眼。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接