我有一些这样的 XML:
<TEI>
<text>
<div type="scene" n="1">
<sp xml:id="sp1">
<speaker>Julius</speaker>
<l>Lorem ipsum dolor sit amet</l>
<ptr cRef="..." />
<stage>Aside</stage>
<ptr cRef="..." />
<l>consectetur adipisicing elit</l>
<stage>To Antony</stage>
<l>sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</l>
</sp>
<sp xml:id="sp2">
...
而且我需要将所有<stage>
元素提升一个级别以成为 s 的兄弟姐妹,将<sp>
s 分解,<sp>
以便元素与 s 中的<stage>
其他元素保持其前后关系<sp>
,例如
<TEI>
<text>
<div type="scene" n="1">
<sp by="#Julius">
<l>Lorem ipsum dolor sit amet</l>
<ptr cRef="..." />
</sp>
<stage>Aside</stage>
<sp by="#Julius">
<ptr cRef="..." />
<l>consectetur adipisicing elit</l>
</sp>
<stage>To Antony</stage>
<sp by="#Julius">
<l>sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</l>
</sp>
我一直在研究 XSLT 来做到这一点。它包括一个递归模板,该模板旨在使用<sp>
最多(但不包括)第一个子元素的所有子元素,<stage>
并将它们作为 new 的子元素在结果树中发出<sp>
。然后发出第一个<stage>
元素。然后递归第一个元素之后的所有<stage>
元素。最终,当子元素列表中没有<stage>
s 时,所有剩余的元素都会在结果树中的 new 中发出<sp>
。这是代码,包括调试<xsl:message>
s:
<xsl:template name="sp-with-stage">
<!-- call with speaker -->
<xsl:param name="speaker" />
<!-- call with an <sp> element -->
<xsl:param name="sp" />
<!-- $content parameter is optional, by default it's the children of the given $sp; this is the parameter whose value is different with each recursive call -->
<xsl:param name="content" select="$sp/*" />
<!-- find the first <stage> element amongst the $content node set -->
<xsl:variable name="stage" select="$content/following-sibling::stage[1]" />
<xsl:message>ID = <xsl:value-of select="$sp/@xml:id" /></xsl:message>
<xsl:message>speaker = "<xsl:value-of select="$speaker" />"</xsl:message>
<xsl:message>content length = <xsl:value-of select="count($content)" /></xsl:message>
<xsl:if test="$stage">
<xsl:message>nodes before $stage = <xsl:value-of select="count($stage/preceding-sibling::*)" /></xsl:message>
<xsl:message>nodes after $stage = <xsl:value-of select="count($stage/following-sibling::*)" /></xsl:message>
</xsl:if>
<xsl:if test="$stage">
<sp by="#{$speaker}">
<!-- process all the nodes in the $content node set before the current <stage> -->
<xsl:message>Processing <xsl:value-of select="count($stage/preceding-sibling::*)" /> nodes before "<xsl:value-of select="$stage/text()" />"</xsl:message>
<xsl:apply-templates select="$stage/preceding-sibling::*" />
</sp>
<xsl:apply-templates select="$stage" />
</xsl:if>
<xsl:choose>
<xsl:when test="$stage/following-sibling::stage">
<!-- if there's another <stage> element in the $content node set then call this template recursively -->
<xsl:message>Call recursively with <xsl:value-of select="count($stage/following-sibling::*)" /> following nodes</xsl:message>
<xsl:call-template name="sp-with-stage">
<xsl:with-param name="speaker"><xsl:value-of select="$speaker" /></xsl:with-param>
<xsl:with-param name="sp" select="$sp" />
<!-- the $content node set for this call is all the nodes after the current <stage> -->
<xsl:with-param name="content" select="$stage/following-sibling::*" />
</xsl:call-template>
</xsl:when>
<xsl:when test="$stage/following-sibling::*">
<!-- if there's no <stage> element in the $content node set, but there are still some elements, emit them in an <sp> element -->
<sp by="#{$speaker}">
<xsl:message>Processing <xsl:value-of select="count($stage/following-sibling::*)" /> trailing nodes</xsl:message>
<xsl:apply-templates select="$stage/following-sibling::*" />
</sp>
</xsl:when>
</xsl:choose>
</xsl:template>
然后像这样调用这个模板:
<xsl:template match="sp[stage]">
<xsl:call-template name="sp-with-stage">
<xsl:param name="speaker"><xsl:value-of select="speaker" /></xsl:param>
<xsl:param name="sp" select="." />
</xsl:call-template>
</xsl:template>
问题在于我的使用$stage/preceding-sibling::*
,我的意思是只处理当前$content
节点集中在当前节点之前的$stage
节点。实际发生的是,在每次递归调用中,所有在当前$stage
节点之前的节点<sp>
都被 this 选中$stage/preceding-sibling::*
。尽管递归调用$content
每次都获得正确的新节点集并且该$stage
节点是从该正确的$content
节点集中获取的,但这是事实。
为了澄清,在上面的示例 XML 的情况下,当<stage>To Antony</stage>
是$stage
节点并且$content
节点只包含:
<l>consectetur adipisicing elit</l>
<stage>To Antony</stage>
<l>sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</l>
该$stage/preceding-sibling::*
表达式仍然产生原来的所有子代.<sp>
<stage>To Antony</stage>
我想一定有一些preceding-sibling
我没有正确理解的东西。有什么建议么?或者甚至有什么完全不同的方式来实现转型的建议?