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

如何为每个record节点创建独立的XSLT key查找?

如何为每个record节点实现独立的XSLT key查找?

我正在尝试用XSLT的key功能实现查找,但每个record节点需要独立的查找范围——用当前record下data/item的值,匹配同个record内names/person/id并返回对应的name。但key必须定义在顶层,当前写法会返回整个文档中所有匹配的条目,导致输出重复。

输入XML

<?xml version="1.0" encoding="UTF-8"?>
<file>
<record>
    <data>
        <item>2</item>
        <item>4</item>
        <item>6</item>
    </data>
    <names>
        <person><id>1</id><name>Anton</name></person>
        <person><id>2</id><name>Bruce</name></person>
        <person><id>3</id><name>Chris</name></person>
        <person><id>4</id><name>Dirk</name></person>
        <person><id>5</id><name>Erik</name></person>
        <person><id>6</id><name>Fred</name></person>
    </names>
</record>
<record>
    <data>
        <item>1</item>
        <item>2</item>
        <item>5</item>
    </data>
    <names>
        <person><id>1</id><name>Sue</name></person>
        <person><id>2</id><name>Jen</name></person>
        <person><id>3</id><name>Jill</name></person>
        <person><id>4</id><name>Jane</name></person>
        <person><id>5</id><name>Maria</name></person>
        <person><id>6</id><name>Mary</name></person>
    </names>
</record>
</file>

期望输出

<results>
   <result>
      <item>2</item>
      <name>Bruce</name>
   </result>
   <result>
      <item>4</item>
      <name>Dirk</name>
   </result>
   <result>
      <item>6</item>
      <name>Fred</name>
   </result>
</results>
<results>
   <result>
      <item>1</item>
      <name>Sue</name>
   </result>
   <result>
      <item>2</item>
      <name>Jen</name>
   </result>
   <result>
      <item>5</item>
      <name>Maria</name>
   </result>
</results>

当前使用的XSLT(错误写法)

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:key name="k1" match="file/record/names/person" use="id" />

<xsl:template match="file/record">
    <results>
        <xsl:for-each select="data/item">
            <result>
                <xsl:copy-of select="."/>
                <xsl:copy-of select="key('k1', .)/name"/>
            </result>           
        </xsl:for-each>
    </results>
</xsl:template>

</xsl:stylesheet>

错误输出

<results>
   <result>
      <item>2</item>
      <name>Bruce</name>
      <name>Jen</name>
   </result>
   <result>
      <item>4</item>
      <name>Dirk</name>
      <name>Jane</name>
   </result>
   <result>
      <item>6</item>
      <name>Fred</name>
      <name>Mary</name>
   </result>
</results>
<results>
   <result>
      <item>1</item>
      <name>Anton</name>
      <name>Sue</name>
   </result>
   <result>
      <item>2</item>
      <name>Bruce</name>
      <name>Jen</name>
   </result>
   <result>
      <item>5</item>
      <name>Erik</name>
      <name>Maria</name>
   </result>
</results>

解决方案

在XSLT 1.0中,可以通过复合键来限定查找范围——把每个record的唯一标识和id拼接成键值,确保只匹配当前record内的person节点:

修改后的XSLT

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<!-- 复合键:拼接record的唯一ID和person的id -->
<xsl:key name="k1" match="names/person" use="concat(generate-id(../../), '|', id)" />

<xsl:template match="file/record">
    <results>
        <xsl:for-each select="data/item">
            <result>
                <xsl:copy-of select="."/>
                <!-- 用当前record的唯一ID+item值作为键查找 -->
                <xsl:copy-of select="key('k1', concat(generate-id(../..), '|', .))/name"/>
            </result>           
        </xsl:for-each>
    </results>
</xsl:template>

</xsl:stylesheet>

原理说明

  • generate-id(../../)会为当前item所属的record生成一个唯一字符串,确保每个record的标识不重复;
  • 将这个唯一标识与id用分隔符(如|)拼接,形成复合键,每个person的键值仅在所属record内唯一;
  • 查找时用同样的规则拼接当前record的标识和item值,就能精准匹配到同个record内对应的person节点。

替代方案(无需key)

如果数据量不大,也可以直接用相对路径查找,省去key的定义:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

<xsl:template match="file/record">
    <results>
        <xsl:for-each select="data/item">
            <result>
                <xsl:copy-of select="."/>
                <!-- 直接查找同个record下匹配id的person -->
                <xsl:copy-of select="../names/person[id=current()]/name"/>
            </result>           
        </xsl:for-each>
    </results>
</xsl:template>

</xsl:stylesheet>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 17:54:52