2010-11-03 50 views
0

我正在使用XSLT和XML。如何使用XSLT從兩個XML獲得所需的XML輸出

第一件事我要在兩個XML上工作。

首先XML:

<?xml version="1.0"?> 
<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0" ID="tcm:232-83752-2" Managed="10682"> 
    <tcm:Item ID="tcm:232-564598" Title="010 News Mapping"/> 
    <tcm:Item ID="tcm:232-564599" Title="020 CUGOs"/> 
    <tcm:Item ID="tcm:232-614307" Title="030 Reserved Urls"/> 
</tcm:ListItems> 

第二XML我們將使用上述ID即中醫得到它:232-564598等,下面是XML的ID中醫之一:232-564598和其他ID將具有相同類型的XML。

<tcm:Component ID="tcm:229-564598" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink"> 
    <tcm:Data> 
    <tcm:Content> 
     <MappingCollection xmlns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F"> 
     <VanityUrl> 
      <old>mbp</old> 
      <new>/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f</new> 
      <dateAdded>2010-05-03T14:45:00</dateAdded> 
      <comments> News mapping </comments> 
     </VanityUrl> 
     <VanityUrl> 
      <old>about/news</old> 
      <new>about/news/news.aspx</new> 
      <dateAdded>2010-05-03T14:45:00</dateAdded> 
      <comments> News mapping </comments> 
     </VanityUrl> 
     </MappingCollection> 
    </tcm:Content> 
    </tcm:Data> 
</tcm:Component> 

我試圖使用上面的兩種XML獲得格式的XML格式。

<?xml version="1.0" encoding="UTF-8"?> 
<mappings> 
    <!-- News mapping --> 
    <mapping old="mbp" new="/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f"/> 
    <mapping old="about/news" new="about/news/news.aspx"/> 
    <!-- CUGO's--> 
    <mapping old="/nhs" new="/cugo.aspx?promoCode=UKNHS01&amp;pub=/uk/english"/> 
    <mapping old="/hk/ukstudentfare" new="/cugo.aspx?promoCode=HKSTU10&amp;pub=/hk/Chinese"/> 
</mappings> 

這裏是我的XSLT,我試圖生成上述格式的XML,但它不適合我。請注意第一個XML是主XML將使用以下XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:em="http://www.espire.com/tridion/schemas" xmlns:tcmse="http://www.tridion.com/ContentManager/5.1/TcmScriptAssistant" exclude-result-prefixes="em xlink tcmse tcm"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-16" indent="yes"/> 
    <!-- root match--> 
    <xsl:template match="tcm:ListItems"> 
    <mappings> 
     <xsl:apply-templates select="tcm:Item"/> 
    </mappings> 
    </xsl:template> 
    <xsl:template match="tcm:Item"> 
     <xsl:variable name="doc" select="document(@ID)"/> 
    <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"> 
     <xsl:comment> 
     <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/> 
     </xsl:comment> 
    </xsl:if> 
    <xsl:for-each select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl"> 
     <xsl:element name="mapping"> 
      <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:old"> 
      <xsl:attribute name="old"> 
       <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:old"/> 
      </xsl:attribute> 
      </xsl:if> 
      <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:new"> 
      <xsl:attribute name="new"> 
       <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:new"/> 
      </xsl:attribute> 
      </xsl:if> 
      <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:dateAdded"> 
      <xsl:attribute name="dateAdded"> 
       <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:dateAdded"/> 
      </xsl:attribute> 
      </xsl:if> 
     </xsl:element> 
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 

在上面的XSLT我能夠獲得數據環也要去正確的,但它已經到來的數據是相同的轉化,我的意思是環路表現正確,但節點值相同

請推薦!

回答

2

該樣式表:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F" 
xmlns:tcm="http://www.tridion.com/ContentManager/5.0" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
exclude-result-prefixes="ns tcm msxsl"> 
    <xsl:strip-space elements="*"/> 
    <xsl:key name="kVanityByComment" match="ns:VanityUrl" use="ns:comments"/> 
    <xsl:template match="/"> 
     <xsl:variable name="vSourcesRTF"> 
      <xsl:copy-of select="document(tcm:ListItems/tcm:Item/@ID)"/> 
     </xsl:variable> 
     <mappings> 
      <xsl:apply-templates select="msxsl:node-set($vSourcesRTF)/node()"/> 
     </mappings> 
    </xsl:template> 
    <xsl:template match="ns:VanityUrl"/> 
    <xsl:template match="ns:VanityUrl[generate-id()= 
             generate-id(key('kVanityByComment', 
                 ns:comments)[1])]"> 
     <xsl:comment> 
      <xsl:value-of select="ns:comments"/> 
     </xsl:comment> 
     <xsl:apply-templates select="key('kVanityByComment', 
             ns:comments)" 
          mode="output"/> 
    </xsl:template> 
    <xsl:template match="ns:VanityUrl" mode="output"> 
     <mapping> 
      <xsl:apply-templates/> 
     </mapping> 
    </xsl:template> 
    <xsl:template match="ns:VanityUrl/ns:comments" priority="1"/> 
    <xsl:template match="ns:VanityUrl/*"> 
     <xsl:attribute name="{local-name()}"> 
      <xsl:value-of select="."/> 
     </xsl:attribute> 
    </xsl:template> 
</xsl:stylesheet> 

利用該輸入:

<tcm:ListItems xmlns:tcm="http://www.tridion.com/ContentManager/5.0" ID="tcm:232-83752-2" Managed="10682"> 
    <tcm:Item ID="229-564598" Title="010 News Mapping"/> 
    <tcm:Item ID="229-564598" Title="020 CUGOs"/> 
    <tcm:Item ID="229-564598" Title="030 Reserved Urls"/> 
</tcm:ListItems> 

並與229-564598 URI該外部源:

<tcm:Component ID="tcm:229-564598" IsEditable="false" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink"> 
    <tcm:Data> 
    <tcm:Content> 
     <MappingCollection xmlns="uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F"> 
     <VanityUrl> 
      <old>mbp</old> 
      <new>/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f</new> 
      <dateAdded>2010-05-03T14:45:00</dateAdded> 
      <comments> News mapping </comments> 
     </VanityUrl> 
     <VanityUrl> 
      <old>about/news</old> 
      <new>about/news/news.aspx</new> 
      <dateAdded>2010-05-03T14:45:00</dateAdded> 
      <comments> News mapping </comments> 
     </VanityUrl> 
     </MappingCollection> 
    </tcm:Content> 
    </tcm:Data> 
</tcm:Component> 

輸出:

<mappings> 
    <!-- News mapping --> 
    <mapping old="mbp" 
      new="/SessionHandler.aspx?pageurl=/BP.aspx&amp;pub=/english&amp;section=IBE&amp;j=f" 
      dateAdded="2010-05-03T14:45:00"></mapping> 
    <mapping old="about/news" 
      new="about/news/news.aspx" 
      dateAdded="2010-05-03T14:45:00"></mapping> 
</mappings> 

編輯:多個輸入源。

+0

許多感謝亞歷杭德羅,它獨立完美地與第二個XML的工作,你可以看看我添加的代碼,並建議如何將它與您的XSLT合併。 – 2010-11-03 14:00:52

+1

@MKS:第一個XML提到的所有文檔都只是一種類型(即所有'VanityUrl'都有'comments ='新聞映射'')? – 2010-11-03 15:00:37

+0

謝謝,但對不起,我不明白你的觀點,你能否詳細說明一下,是的格式將是相同的,但可以有許多評論,如「新映射」,「Cugos」等。如果你看到第一個XML每個節點的文檔將被加載的屬性ID xml進來然後上面xslt代碼將被執行 – 2010-11-03 16:03:01

1

是的,您所做的更改確實很關鍵。 :-)

什麼for-each循環確實是選擇每個<em:VanityUrl>元件匹配您的XPath表達式,使該元素有什麼上下文節點內的for-each(稱爲模板即使它不是一個<xsl:template>) ,然後用新的上下文節點實例化該內部模板。

當您繼續在for-each循環中使用「$ doc/...」時,您拋棄了上下文節點,因此for-each不起作用(除了重複n次)。

<xsl:if test="$doc/...">報表正在評估是否有整個文檔中,而不是上下文元素<em:VanityUrl>而根據該節點

<xsl:value-of>聲明注重僅在所選節點集的第一個節點,所以你總是從第一<em:VanityUrl>所獲得的價值,不管上下文節點。

當你開始選擇和測試相對於上下文節點:

<xsl:if test="em:old"> 

一切都變得更好。 :-)

你問了寶貴的意見。由於文體原因,您可能需要用<xsl:apply-templates>替換您的<xsl:if>測試。 (一件事你會讓@Dimitre Novatchev高興。:-)因此

<xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"> 
    <xsl:comment> 
    <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/> 
    </xsl:comment> 
</xsl:if> 

成爲

<xsl:apply-templates select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments" /> 

,然後你需要爲這些單獨的模板:

<xsl:template match="em:comments"> 
    <xsl:comment> 
    <xsl:value-of select="."/> 
    </xsl:comment> 
</xsl:template> 

有幾個優點這樣做。最重要的是,您不必複製那麼長的XPath表達式,如果需要修改表達式,那麼這種表達式很容易出錯。如果沒有em:comment元素,apply-templates將不會執行任何操作,所以不會發表評論。

它還將您的樣式表模塊化,以便您可以修改em:comments的呈現方式,與可能出現的任何位置分開。在簡單的XML文檔中,em:comments只能在一個地方發生,這可能無關緊要,但它是充分利用XSLT強大功能的風格。另外請注意,如果有多個em:comments,這個修改後的版本會輸出多個註釋,而您的版本不會。同樣,你可能沒有輸入的倍數,所以它可能沒有關係。

類似地,對於輸出屬性:

<xsl:if test="em:old"> 
     <xsl:attribute name="old"> 
     <xsl:value-of select="em:old"/> 
     </xsl:attribute> 
    </xsl:if> 

可以成爲

<xsl:apply-templates select="em:old[1]" /> 

與單獨的模板

<xsl:template match="em:old"> 
    <xsl:attribute name="old"> 
    <xsl:value-of select="."/> 
    </xsl:attribute> 
</xsl:template> 

注意[1],這避免了試圖輸出多個old="..."屬性如果輸入的是相同的元素: VanityUrl有多個em:舊元素。那會導致你的樣式表產生一個錯誤。但也許你想要在這種情況下引發錯誤。如果是這樣,你可能已經驗證了你的輸入XML。

事實上,你可以概括的應用模板和模板這裏適用於所有三種屬性:

<xsl:apply-templates select="em:old[1] | em:new[1] | em:dateAdded[1]" /> 

同樣,如果這些元素不存在,什麼也不會爲他們做(不會產生空屬性)。模板:

<xsl:template match="em:old | em:new | em:dateAdded"> 
    <xsl:attribute name="{local-name()}"> 
    <xsl:value-of select="."/> 
    </xsl:attribute> 
</xsl:template> 

local-name()爲我們提供了元素的名稱,沒有命名空間前綴。

更新:

另一種方式來處理,這將是使用模式:

<xsl:apply-templates select="em:old[1] | em:new[1] | em:dateAdded[1]" 
     mode="make-attribute" /> 

<xsl:template match="em:*" mode="make-attribute"> 
    <xsl:attribute name="{local-name()}"> 
    <xsl:value-of select="."/> 
    </xsl:attribute> 
</xsl:template> 

然後你的化妝屬性模板可以從任何地方使用,匹配模式不必須進行更新以匹配您可能想要創建屬性的所有可能元素。

我唯一會說的是,上面的命名空間的使用是令人困惑的...它不應該按原樣工作。例如。你的樣式表使用此命名空間URI像VanityURL元素:

"http://www.espire.com/tridion/schemas" 

,但第二個輸入文檔使用此命名空間URI這些元素:

"uuid:922EEC29-2DE3-4BA1-A46A-A300CB8FA85F" 

不要緊的命名空間前綴是不同的( 「em:」與默認值),但名稱空間URI必須匹配。我猜VanityURL的名稱空間URI必須已經更改,否則您的樣式表將不起作用...

HTH!

+0

謝謝你,一切都很好,但註釋重複的每一個元素,但我一直在尋找有一個前同輩的每個元素,請建議 – 2010-11-03 12:29:41

+0

@MKS,請澄清。您爲每個輸入em:comment元素獲取多個輸出註釋?或者你反覆收到相同的評論?請編輯您的問題(或答案)以顯示更新的代碼和更新的輸出。 – LarsH 2010-11-03 16:18:56

+0

@MKS,我也不明白你的意思是「我正在尋找每個元素的前一個兄弟姐妹」 - 哪種類型的元素(名稱)?在輸入或輸出?請給出您當前輸出與期望輸出的樣本。 – LarsH 2010-11-03 16:20:59

1

你也可以試試這個!您寶貴的意見

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:tcm="http://www.tridion.com/ContentManager/5.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:em="http://www.espire.com/tridion/schemas" xmlns:tcmse="http://www.tridion.com/ContentManager/5.1/TcmScriptAssistant" exclude-result-prefixes="em xlink tcmse tcm"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-16" indent="yes"/>  
    <!-- root match--> 
    <xsl:template match="tcm:ListItems"> 
    <mappings> 
     <xsl:apply-templates select="tcm:Item"/> 
    </mappings> 
    </xsl:template> 
    <xsl:template match="tcm:Item"> 
    <xsl:variable name="doc" select="document(@ID)"/> 
    <xsl:if test="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"> 
     <xsl:comment> 
     <xsl:value-of select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl/em:comments"/> 
     </xsl:comment> 
    </xsl:if> 
    <xsl:for-each select="$doc/tcm:Component/tcm:Data/tcm:Content/em:MappingCollection/em:VanityUrl"> 
     <xsl:element name="mapping"> 
     <xsl:if test="em:old"> 
      <xsl:attribute name="old"> 
      <xsl:value-of select="em:old"/> 
      </xsl:attribute> 
     </xsl:if> 
     <xsl:if test="em:new"> 
      <xsl:attribute name="new"> 
      <xsl:value-of select="em:new"/> 
      </xsl:attribute> 
     </xsl:if> 
     <xsl:if test="em:dateAdded"> 
      <xsl:attribute name="dateAdded"> 
      <xsl:value-of select="em:dateAdded"/> 
      </xsl:attribute> 
     </xsl:if> 
     </xsl:element> 
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet>