如何为每个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
相关产品推荐
相关产品推荐

