You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何正确使用XPath following-sibling轴解决TEI XML转换问题

问题:TEI XML中转时关联对应的XSLT修正

需要将TEI格式的<desc>元素转换为每个<placeName>对应的<event>元素,但当前实现存在两个问题:要么所有<note>都被附加到每个<event>中,要么完全无法获取到与<placeName>对应的<note>。

原TEI XML结构

<desc year="1879">
      <date from="1879-08-30" to="1879-08-30"/> 
            <placeName>New York</placeName> 
            <placeName>New Jersey</placeName>
            <note>visiting my grandma</note>
      <date from="1879-10-30" to="1879-11-01"/> 
            <placeName>Berlin</placeName> 
            <note>with my mother</note>
            <placeName>Hamburg</placeName>
</desc>

原XSLT代码(存在问题)

<xsl:template match="//tei:desc">
     <xsl:variable name="note-content">
                <xsl:for-each select="//tei:placeName">
                    <xsl:if test="following-sibling::tei:note[1]">
                        <xsl:element name="note" namespace="http://www.tei-c.org/ns/1.0">
                            <xsl:value-of select="following-sibling::tei:note[1]"/>
                        </xsl:element>
                    </xsl:if>
                </xsl:for-each>
            </xsl:variable>
<xsl:for-each-group select="*" group-starting-with="tei:date">
      <!-- other specifications -->

      <xsl:for-each select="current-group()[name()='placeName']">
               <xsl:element name="event" namespace="http://www.tei-c.org/ns/1.0">
                 <!-- other specifications -->

                   <xsl:element name="desc" namespace="http://www.tei-c.org/ns/1.0">
                   <xsl:element name="placeName" namespace="http://www.tei-c.org/ns/1.0">
                           <xsl:attribute name="ref"/>
                           <xsl:value-of select="."/>
                   </xsl:element>
                   </xsl:element>
                   <xsl:if test="$note-content !=''">
                       <xsl:element name="note" namespace="http://www.tei-c.org/ns/1.0">
                           <xsl:value-of select="$note-content"/>
                       </xsl:element>
                   </xsl:if>
               </xsl:element>
            </xsl:for-each>
        </xsl:for-each-group>
    </xsl:template>

解决方案:精准关联<placeName>与对应<note>

原代码的核心问题是提前全局收集了所有<note>内容,导致无法按分组和节点顺序匹配。正确的做法是在分组内动态判断每个<placeName>对应的<note>,利用following-sibling轴结合分组上下文实现精准匹配。

修改后的XSLT代码

<xsl:template match="tei:desc">
  <xsl:for-each-group select="*" group-starting-with="tei:date">
    <!-- 先获取当前date分组内的第一个note -->
    <xsl:variable name="current-group-note" select="current-group()[self::tei:note][1]"/>
    
    <xsl:for-each select="current-group()[self::tei:placeName]">
      <event xmlns="http://www.tei-c.org/ns/1.0">
        <!-- 保留原有的desc和placeName结构 -->
        <desc>
          <placeName ref="">
            <xsl:value-of select="."/>
          </placeName>
        </desc>
        
        <!-- 两个判断条件:要么是分组内最后一个placeName,要么后面紧跟的元素是note -->
        <xsl:if test="position() = last() or following-sibling::*[1][self::tei:note]">
          <note>
            <xsl:value-of select="$current-group-note"/>
          </note>
        </xsl:if>
      </event>
    </xsl:for-each>
  </xsl:for-each-group>
</xsl:template>

关键逻辑说明

  1. 分组内提取note:通过current-group()[self::tei:note][1]获取当前date分组下的第一个<note>,确保只处理当前时间段内的备注。
  2. 匹配对应placeName:
    • 如果当前<placeName>是分组内最后一个,则关联该分组的<note>(如原XML中的New Jersey、Hamburg);
    • 如果当前<placeName>后面直接紧跟<note>,则关联该<note>(如原XML中的Berlin)。
  3. 去掉全局note变量:避免提前收集所有note导致的错误关联,改为在分组内动态处理。

转换后预期结果

  • New York、New Jersey 对应的<event>都会附加note: visiting my grandma;
  • Berlin、Hamburg 对应的<event>都会附加note: with my mother。

内容的提问来源于stack exchange,提问作者Laura P

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 05:15:37