XSLT相对或绝对路径,意外行为

时间:2011-12-13 18:28:41

标签: xslt path relative absolute

我有这个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

我想了解这背后的逻辑。

2 个答案:

答案 0 :(得分:4)

如果匹配match =“x”的每个节点也匹配match =“/ a / b / c / x”,则将前者更改为后者的唯一效果是更改规则的优先级;该规则被认为更具体,因此具有更高的优先级,这可能导致在节点匹配多个规则时触发该规则。

答案 1 :(得分:3)

正如@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