鉴于此源文件:
<?xml version="1.0" encoding="utf-8"?>
<config>
<group name="global">
<globals>
<item grp="db" prop="userid" value="foo"/>
<item grp="db" prop="passwd" value="bar"/>
<item grp="log" prop="level" value="debug"/>
<item grp="log" prop="filename" value="red.log"/>
</globals>
</group>
<group name="dev">
<globals>
<item grp="db" prop="server" value="dev_sql_1"/>
</globals>
<locals>
<item grp="db" prop="catalog" value="red_db_local"/>
<item grp="db" prop="passwd" value="dev_passwd"/>
<item grp="log" prop="level" value="info"/>
</locals>
</group>
<group name="qa">
<globals>
<item grp="db" prop="server" value="qa_sql_1"/>
<item grp="db" prop="catalog" value="qa_db"/> <!-- this is wonky, but may happen -->
</globals>
<locals>
<item grp="db" prop="catalog" value="red_db_local"/> <!-- this should beat 'qa_db' from ../globals/item[@grp='db' and prop='catalog'] -->
<item grp="db" prop="passwd" value="qa_passwd"/>
<item grp="log" prop="level" value="critical"/>
</locals>
</group>
<group name="prod">
<globals>
<item grp="db" prop="server" value="prod_sql_1"/>
</globals>
<locals>
<item grp="db" prop="catalog" value="prod_db_local"/>
<item grp="db" prop="passwd" value="prod_passwd"/>
<item grp="log" prop="level" value="critical"/>
</locals>
</group>
</config>
和一个可用环境之一的参数,我想最终得到一个合并和重复数据删除的节点集,保留最具体的值。所以,对于'prod':
<config>
<item grp="db" prop="userid" value="foo"/>
<item grp="log" prop="filename" value="red.log"/>
<item grp="db" prop="server" value="prod_sql_1"/>
<item grp="db" prop="catalog" value="prod_db_local"/>
<item grp="db" prop="passwd" value="prod_passwd"/>
<item grp="log" prop="level" value="critical"/>
</config>
我非常擅长在XSLT 1.0中使用键,我已经提出了适用于'prod'的样式表,但不适用于'dev'或'qa':
<?xml version="1.0" encoding="utf-8"?>
<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:param name="environment"/>
<!--
using | to create a union of top-level global items and and env-specific items
-->
<xsl:variable name="all-items"
select="/config/group[@name='global']/globals/item |
//group[@name=$environment]//item"/>
<xsl:key name="dupes" match="item" use="concat(@grp,'|',@prop)"/>
<xsl:template match="/config">
<xsl:copy>
<xsl:copy-of
select="$all-items[generate-id() = generate-id(key('dupes',
concat(@grp,'|',@prop))[last()])]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
这是我的目标:
<item.../>
节点合并到带有union |
@grp
和@prop
属性由于我是新手,我只能说我认为这段代码,
<xsl:copy-of select="$all-items[generate-id() = generate-id(key('dupes',
concat(@grp,'|',@prop))[last()])]"/>
从一组重复项目中选择last()
节点,但是当使用'dev'或'qa'运行时,我得到以下内容:
REG zacharyyoung$ xsltproc --stringparam environment dev config3.xsl config3.xml
<config>
<item grp="db" prop="userid" value="foo"/>
<item grp="log" prop="filename" value="red.log"/>
</config>
REG zacharyyoung$ xsltproc --stringparam environment qa config3.xsl config3.xml
<config>
<item grp="db" prop="userid" value="foo"/>
<item grp="log" prop="filename" value="red.log"/>
</config>
我已经检查了每个环境参数的中间变量all-items
,看起来至少有那么多正常工作。
如果我将<group name="qa"/>
移到底部,例如:
<config>
<group name="global">...</group>
<group name="dev">...</group>
<group name="prod">...</group>
<group name="qa">...</group>
<config>
然后用'qa'运行它:
REG zacharyyoung$ xsltproc --stringparam environment qa config3.xsl config3.xml
<config>
<item grp="db" prop="userid" value="foo"/>
<item grp="log" prop="filename" value="red.log"/>
<item grp="db" prop="server" value="qa_sql_1"/>
<item grp="db" prop="catalog" value="red_db_local"/>
<item grp="db" prop="passwd" value="qa_passwd"/>
<item grp="log" prop="level" value="critical"/>
</config>
那么,为什么<group name="...">...</group>
我的选择位置很重要?具体来说,为什么它只在最后一个位置工作,如何让它适用于任何位置?
编辑1
当我从$all-items
(对于任何环境)中隔离数据并将其放入自己的文件中时,XSL正常工作。以下示例是全局变量和'dev'的并集:
<config>
<item grp="db" prop="userid" value="foo"/>
<item grp="db" prop="passwd" value="bar"/>
<item grp="log" prop="level" value="debug"/>
<item grp="log" prop="filename" value="red.log"/>
<item grp="db" prop="server" value="dev_sql_1"/>
<item grp="db" prop="catalog" value="red_db_local"/>
<item grp="db" prop="passwd" value="dev_passwd"/>
<item grp="log" prop="level" value="info"/>
</config>
和这个XSL:
<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="dupes" match="item" use="concat(@grp,'|',@prop)"/>
<xsl:template match="/config">
<xsl:copy>
<xsl:copy-of
select="item[generate-id() = generate-id(key('dupes',
concat(@grp,'|',@prop))[last()])]"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
结果:
REG zacharyyoung$ xsltproc config4.xsl config4.xml
<config>
<item grp="db" prop="userid" value="foo"/>
<item grp="log" prop="filename" value="red.log"/>
<item grp="db" prop="server" value="dev_sql_1"/>
<item grp="db" prop="catalog" value="red_db_local"/>
<item grp="db" prop="passwd" value="dev_passwd"/>
<item grp="log" prop="level" value="info"/>
</config>
那么,现在它似乎是变量all-items
?
谢谢。
答案 0 :(得分:1)
我不确定分组为什么不起作用(我会尽快看一下),但你也可以在不使用密钥的情况下实现所需的输出。
这个XSLT 1.0样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="environment" select="'qa'"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group">
<xsl:if test="@name = $environment">
<xsl:apply-templates select="/config/group[@name='global']/globals/item[not(@prop = /config/group[@name='prod']/locals/item/@prop)]"/>
<xsl:apply-templates/>
</xsl:if>
</xsl:template>
<xsl:template match="globals|locals">
<xsl:apply-templates/>
</xsl:template>
</xsl:stylesheet>
应用于您的输入XML生成所需的输出:
<config>
<item grp="db" prop="userid" value="foo"/>
<item grp="log" prop="filename" value="red.log"/>
<item grp="db" prop="server" value="qa_sql_1"/>
<item grp="db" prop="catalog" value="red_db_local"/>
<item grp="db" prop="passwd" value="qa_passwd"/>
<item grp="log" prop="level" value="critical"/>
</config>
这也适用于&#34; prod&#34;和&#34; dev&#34;。
编辑:从谓词中删除变量。
答案 1 :(得分:0)
关闭DevNull's answer(回答上述问题)我做了以下修改(针对一些未说明的要求):
这是完整的样式表:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="environment" select="'qa'"/>
<xsl:template match="/config">
<xsl:copy>
<xsl:copy-of select="/config/group[@name='global']/globals/item[not(@prop = /config/group[@name=$environment]//item/@prop)]"/>
<xsl:copy-of select="/config/group[@name=$environment]/globals/item[not(@prop = /config/group[@name=$environment]/locals/item/@prop)]"/>
<xsl:copy-of select="/config/group[@name=$environment]/locals/item"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
我仍然希望在我原来的问题中找出键的错误。