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

基于XSLT的节点交叉评估:为TOKEN节点添加指定属性

搞定SECONDARY句子TOKEN的FURTHER_FROM_PRIMARY属性添加问题

嘿,我来帮你解决这个XML转换的需求!核心目标是:在同一个<PARAGRAPH>节点下,给那些BEGIN属性值比同组其他所有<SENTENCE type="SECONDARY">里的<TOKEN>都大的节点,加上FURTHER_FROM_PRIMARY="YES"属性对吧?下面是完整的解决方案,包括思路、代码和解释:

核心思路拆解

  1. 锁定上下文:只在当前<PARAGRAPH>范围内比较,不能跨段落乱比,不然结果肯定出错。
  2. 数值化比较:BEGIN属性是字符串格式的数字,必须转成数值再对比,不然会出现"100"比"99"小的字符串排序坑。
  3. 精准判断:对每个目标TOKEN,检查它的BEGIN是不是同组里的最大值——是就加属性,不是就原样保留节点结构。

完整XSLT实现

<?xml version="1.0" encoding="UTF-8"?>
<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>

    <!-- 针对PARAGRAPH下SECONDARY句子中TOKEN的特殊处理逻辑 -->
    <xsl:template match="PARAGRAPH/SENTENCE[@type='SECONDARY']/TOKEN">
        <!-- 将当前TOKEN的BEGIN转为数值,避免字符串排序错误 -->
        <xsl:variable name="currentBegin" select="number(@BEGIN)"/>
        <!-- 收集当前PARAGRAPH下所有SECONDARY句子中TOKEN的BEGIN数值 -->
        <xsl:variable name="allSecondaryTokenBegins" select="number(../../SENTENCE[@type='SECONDARY']/TOKEN/@BEGIN)"/>
        
        <xsl:copy>
            <!-- 复制原有的所有属性 -->
            <xsl:apply-templates select="@*"/>
            <!-- 判断条件:当前BEGIN是同组最大值,且同组有多个TOKEN(避免单个TOKEN误加属性) -->
            <xsl:if test="$currentBegin > max($allSecondaryTokenBegins) and count($allSecondaryTokenBegins) > 1">
                <xsl:attribute name="FURTHER_FROM_PRIMARY">YES</xsl:attribute>
            </xsl:if>
            <!-- 复制TOKEN的子节点(如果存在) -->
            <xsl:apply-templates select="node()"/>
        </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

关键部分解释

  • 默认模板:确保所有未被特殊模板匹配的节点和属性都被原样复制,完美保留XML原有结构。
  • 变量currentBegin:把当前TOKEN的BEGIN属性转成数值,这是避免字符串排序错误的关键。
  • 变量allSecondaryTokenBegins:严格限定在当前<PARAGRAPH>下收集所有SECONDARY句子的TOKEN的BEGIN值,保证比较范围正确。
  • 条件判断:
    • $currentBegin > max($allSecondaryTokenBegins):检查当前TOKEN的BEGIN是否是同组中的最大值。
    • count($allSecondaryTokenBegins) > 1:避免当只有一个SECONDARY TOKEN时误加属性(如果你的需求允许单个TOKEN也添加属性,可以直接去掉这个条件)。

测试示例(输入→输出)

输入XML片段

<PARAGRAPH>
    <SENTENCE type="PRIMARY">
        <TOKEN BEGIN="50" END="55">Hello</TOKEN>
    </SENTENCE>
    <SENTENCE type="SECONDARY">
        <TOKEN BEGIN="100" END="105">word1</TOKEN>
        <TOKEN BEGIN="200" END="206">word2</TOKEN>
        <TOKEN BEGIN="150" END="153">word3</TOKEN>
    </SENTENCE>
    <SENTENCE type="SECONDARY">
        <TOKEN BEGIN="250" END="254">word4</TOKEN>
    </SENTENCE>
</PARAGRAPH>

转换后输出XML片段

<PARAGRAPH>
    <SENTENCE type="PRIMARY">
        <TOKEN BEGIN="50" END="55">Hello</TOKEN>
    </SENTENCE>
    <SENTENCE type="SECONDARY">
        <TOKEN BEGIN="100" END="105">word1</TOKEN>
        <TOKEN BEGIN="200" END="206" FURTHER_FROM_PRIMARY="YES">word2</TOKEN>
        <TOKEN BEGIN="150" END="153">word3</TOKEN>
    </SENTENCE>
    <SENTENCE type="SECONDARY">
        <TOKEN BEGIN="250" END="254">word4</TOKEN>
    </SENTENCE>
</PARAGRAPH>

可以看到,BEGIN="200"的TOKEN被正确添加了目标属性,而单个SECONDARY TOKEN的word4没有添加(符合我们的条件判断逻辑)。

常见错误排查

如果你之前的代码没生效,大概率是这几个原因:

  • 没有限定PARAGRAPH上下文:比如直接取所有SECONDARY的TOKEN,导致跨段落比较,结果完全错误。
  • 用了字符串比较:直接对比@BEGIN而不是转成number(@BEGIN),出现数值排序错误(比如"100" < "99")。
  • 没处理边界情况:比如单个SECONDARY TOKEN的场景,导致不必要的属性添加。

内容的提问来源于stack exchange,提问作者wild card

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:45:33