XSLT 相对或绝对路径、意外行为
我有这个 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
我想了解这背后的逻辑。
I have this XML code
<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>
and this XSLT code
<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>
The output is this one
<root>
<peptide>
<accession>111</accession>
<sequence>AAA</sequence>
</peptide>
<peptide>
<accession>111</accession>
<sequence>BBB</sequence>
</peptide>
</root>
Now, the same XSLT code but with almost all paths changed to absolute
<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>
does not change anything. However, if the last path is also expressed as absolute
<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>
then the ouput is simply
<root></root>
I did not expect this.
And, also unexpectedly (for me) if I write the template match before, the output is again the wished one
<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>
The last files: http://www.xsltcake.com/slices/sgWUFu
I would like to understand the logic behind this.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果每个匹配 match="x" 的节点也匹配 match="/a/b/c/x",则将前者更改为后者的唯一效果是更改规则的优先级;该规则被认为更具体,因此优先级更高,这可能会导致当节点匹配多个规则时触发该规则。
If every node that matches match="x" also matches match="/a/b/c/x", then the only effect of changing the former to the latter is to change the priority of the rule; the rule is considered to be more specific, therefore higher priority, which may cause it to be fired when a node matches more than one rule.
正如@Michael 提到的,这个问题是模板冲突解决之一。将匹配模式从
peptide
更改为/data/peptides/peptide
会将模板的优先级提高到与处理/data/peptides/ 的模板相同的级别肽[生成-id()=
。文档中的某些节点可以通过这两个匹配模式中的一个/两个来选择,这会导致模板冲突。生成 id(key('byAccSeq', concat(accession, '|', 序列))[1])]
从技术上讲,拥有多个匹配模板规则是一种错误,但处理器通常通过应用文档中的最后一个匹配模板来恢复,这就是为什么更改模板的顺序会产生不同的结果。
正如迈克尔所熟知的,撒克逊人发出了以下警告:
As @Michael alluded, the issue is one of template conflict resolution. Changing the match pattern from
peptide
to/data/peptides/peptide
raises the priority of the template to the same level as the template for handling/data/peptides/peptide[generate-id()=
. There are nodes in the document that could be selected by either/both of those match patterns, which results in a template conflict.generate-id(key('byAccSeq', concat(accession, '|', sequence))[1])]
It is technically an error to have more than one matching template rule, but processors generally recover by applying the last matching template in the document, which is why changing the order of the templates produced different results.
As Michael would well know, Saxon produces the following warning: