我有这个XML代码
<data>
<proteins>
<protein>
<accession>111</accession>
</protein>
</proteins>
<peptides>
<peptide>
<accession>111</accession>
<sequence>AAA</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>AAA</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>AAA</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>BBB</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>BBB</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>BBB</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>BBB</sequence>
</peptide>
</peptides>
</data>
和这个XSLT代码
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="byAccSeq" match="peptide"
use="concat(accession, '|', sequence)"/>
<xsl:template match="/">
<root><xsl:apply-templates select="/*/proteins/protein"/></root>
</xsl:template>
<xsl:template match="protein">
<xsl:apply-templates
select="../../peptides/peptide[accession=current()/accession]"/>
</xsl:template>
<xsl:template match="peptide[generate-id()=
generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="peptide"/>
</xsl:stylesheet>
输出是这个
<root>
<peptide>
<accession>111</accession>
<sequence>AAA</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>BBB</sequence>
</peptide>
</root>
现在,相同的XSLT代码但是几乎所有路径都变为绝对路径
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="byAccSeq" match="/data/peptides/peptide"
use="concat(accession, '|', sequence)"/>
<xsl:template match="/">
<root><xsl:apply-templates select="/data/proteins/protein"/></root>
</xsl:template>
<xsl:template match="/data/proteins/protein">
<xsl:apply-templates
select="/data/peptides/peptide[accession=current()/accession]"/>
</xsl:template>
<xsl:template match="/data/peptides/peptide[generate-id()=
generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="peptide"/>
</xsl:stylesheet>
不会改变任何东西。但是,如果最后一条路径也表示为绝对
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="byAccSeq" match="/data/peptides/peptide"
use="concat(accession, '|', sequence)"/>
<xsl:template match="/">
<root><xsl:apply-templates select="/data/proteins/protein"/></root>
</xsl:template>
<xsl:template match="/data/proteins/protein">
<xsl:apply-templates
select="/data/peptides/peptide[accession=current()/accession]"/>
</xsl:template>
<xsl:template match="/data/peptides/peptide[generate-id()=
generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="/data/peptides/peptide"/>
</xsl:stylesheet>
那么输出就是
<root></root>
我没想到这一点。
而且,(对于我而言)如果我之前写过模板匹配,这也是出乎意料的,输出仍然是希望的
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:key name="byAccSeq" match="/data/peptides/peptide"
use="concat(accession, '|', sequence)"/>
<xsl:template match="/">
<root><xsl:apply-templates select="/data/proteins/protein"/></root>
</xsl:template>
<xsl:template match="/data/proteins/protein">
<xsl:apply-templates
select="/data/peptides/peptide[accession=current()/accession]"/>
</xsl:template>
<xsl:template match="/data/peptides/peptide"/>
<xsl:template match="/data/peptides/peptide[generate-id()=
generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]">
<xsl:copy-of select="."/>
</xsl:template>
</xsl:stylesheet>
最后文件:http://www.xsltcake.com/slices/sgWUFu
我想了解其背后的逻辑。
最佳答案
正如@Michael所暗示的,问题是template conflict resolution之一。将匹配模式从peptide
更改为/data/peptides/peptide
会将模板的优先级提高到与用于处理/data/peptides/peptide[generate-id()= generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]
的模板相同的级别。文档中的某些节点可能会被这些匹配模式中的一个或两个选中,这会导致模板冲突。
从技术上讲,拥有多个匹配模板规则是一个错误,但是处理器通常通过应用文档中的最后一个匹配模板来恢复,这就是为什么更改模板顺序会产生不同结果的原因。
迈克尔很清楚,撒克逊人发出以下警告:
Recoverable error
XTRE0540: Ambiguous rule match for /data/peptides[1]/peptide[1]
Matches both "/data/peptides/peptide" on line 16 of file:///C:/sandbox/so.xsl
and "/data/peptides/peptide[generate-id()= generate-id(key('byAccSeq', concat(accession,
'|', sequence))[1])]" on line 13 of file:///C:/sandbox/so.xsl
Recoverable error
XTRE0540: Ambiguous rule match for /data/peptides[1]/peptide[4]
Matches both "/data/peptides/peptide" on line 16 of file:///C:/sandbox/so.xsl
and "/data/peptides/peptide[generate-id()= generate-id(key('byAccSeq', concat(accession,
'|', sequence))[1])]" on line 13 of file:///C:/sandbox/so.xsl