2012-01-16 66 views
1

鉴于这种源文件:这种合并和重复数据删除方法有什么问题?

<?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> 

和参数是可用的环境,我想有一个合并和重复数据删除节点集结束了,保持最具体的值之一。所以,对于“刺”:

<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中使用的键,我想出了这个样式表,对于“刺”的作品,而不是“开发”或' 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> 

这是我的目标的方法:

  1. 合并所有相关<item.../>节点到节点集合与工会|
  2. 这组节点集由@grp@prop属性
  3. 保留的最后一个节点在任何所产生的群体(重复数据删除)

由于我是新来的钥匙,我只能说,我认为这段代码,

<xsl:copy-of select="$all-items[generate-id() = generate-id(key('dupes', 
              concat(@grp,'|',@prop))[last()])]"/> 

是选择last()节点进行重复的项目的节点集,但与“开发”或“质量保证”跑,我得到如下:

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正常工作。下面的例子是全局的工会和 '开发':

<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

谢谢。

回答

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> 

这也适用于 “刺” 和 “开发”。

编辑:从谓词中删除变量。

+0

我无法在组匹配谓词中使用'$ environment'运行样式表:'XPath错误:未定义变量 编译错误:文件config4.xsl第13行元素模板 未能编译谓词'匹配= “组[@名称= $环境]”'。这确实符合所提供的来源。谢谢。 – 2012-01-16 22:26:12

+0

@Zachary年轻 - 嗯......我用萨克森-H和Xalan测试过,没什么问题。我会看看xsltproc。 – 2012-01-16 22:28:52

+0

@ZacharyYoung - 撒克逊6.5.5也失败了。我更新了样式表以使用xsl:if代替谓词中的变量。 – 2012-01-16 22:32:32

0

都会响起DevNull's answer(其中回答所陈述的问题)我做了如下修改(对于一些不成文的规定):

  1. 新增环境全局混合,以防被输入了重复的值有
  2. 删除恒等变换,因为它似乎不适合我的需要

下面是完整的样式表:

<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> 

我仍然希望找出原来问题中的按键有什么问题。