2012-01-16 38 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> 

我仍然希望找出原來問題中的按鍵有什麼問題。

相關問題