2012-02-25 53 views
2

我有一個XML這樣的:輸出值XSLT/XPath 2.0中

<?xml version="1.0" encoding="UTF-8"?> 

<Section> 
    <Chapter> 
     <Cell colname="1"> 
      <Value>A</Value> 
     </Cell> 
     <Cell colname="2"> 
      <MyValue>AAA</MyValue> 
      <MyValue>BBB</MyValue> 
     </Cell> 
     <Cell colname="3"> 
      <MyCar>Honda</MyCar> 
     </Cell> 
    </Chapter> 
    <Chapter> 
     <Cell colname="1"> 
      <Value>C</Value> 
     </Cell> 
     <Cell colname="2"> 
      <MyValue>CCC</MyValue> 
     </Cell> 
     <Cell colname="3"> 
      <MyCar>Toyota</MyCar> 
     </Cell> 
    </Chapter> 
</Section> 

我喜歡有一個消息(以後將它們轉換代碼)像這樣輸出:

甲 AAA 本田 一個 BBB 本田 ç CCC 豐田

這是我的XSLT:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    exclude-result-prefixes="xs" 
    version="2.0"> 

    <xsl:output method="xml" version="1.0" encoding="iso-8859-1" indent="yes"/> 

    <xsl:template match="/"> 
     <xsl:apply-templates select="Section//Chapter"/> 
    </xsl:template> 

    <xsl:template match="Chapter"> 
     <xsl:for-each select="Cell[@colname='2']//MyValue"> 
      <xsl:message> 
       <xsl:value-of select="Cell[@colname='1']/Value"/> 
       <xsl:value-of select="."/> 
       <xsl:value-of select="Cell[@colname='3']/MyCar"/> 
      </xsl:message> 
     </xsl:for-each> 
    </xsl:template> 

    <xsl:template match="text()" /> 

</xsl:stylesheet> 

不幸的是,它不會輸出我想要它做的:(。

我意識到,每一個都會改變上下文,所以餘下的值不會做任何事情。

這是什麼解決方案?

TIA,

約翰

回答

3

此XSLT 2.0變換(等效XSLT 1.0轉化可以從該一個被機械地寫入)。

請注意:這是一個通用的解決方案,可以處理任意數量的孩子,不依賴於硬編碼名稱。

<xsl:stylesheet version="2.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:template match="Chapter"> 
    <xsl:apply-templates select="Cell[1]"/> 
</xsl:template> 

<xsl:template match="Cell"> 
    <xsl:param name="pText" as="xs:string*"/> 

    <xsl:apply-templates select="*[1]"> 
    <xsl:with-param name="pText" select="$pText"/> 
    </xsl:apply-templates> 
</xsl:template> 

<xsl:template match="Cell/*"> 
    <xsl:param name="pText" as="xs:string*"/> 

    <xsl:variable name="vText" as="xs:string*" 
    select="$pText, string(.)"/> 

    <xsl:sequence select= 
    "$vText 
     [not(current()/../following-sibling::Cell)]"/> 
    <xsl:apply-templates select="../following-sibling::Cell[1]"> 
    <xsl:with-param name="pText" select="$vText"/> 
    </xsl:apply-templates> 
    <xsl:apply-templates select="following-sibling::*"> 
    <xsl:with-param name="pText" select="$pText"/> 
    </xsl:apply-templates> 
</xsl:template> 
</xsl:stylesheet> 

時所提供的XML文檔應用:

<Section> 
    <Chapter> 
     <Cell colname="1"> 
      <Value>A</Value> 
     </Cell> 
     <Cell colname="2"> 
      <MyValue>AAA</MyValue> 
      <MyValue>BBB</MyValue> 
     </Cell> 
     <Cell colname="3"> 
      <MyCar>Honda</MyCar> 
     </Cell> 
    </Chapter> 
    <Chapter> 
     <Cell colname="1"> 
      <Value>C</Value> 
     </Cell> 
     <Cell colname="2"> 
      <MyValue>CCC</MyValue> 
     </Cell> 
     <Cell colname="3"> 
      <MyCar>Toyota</MyCar> 
     </Cell> 
    </Chapter> 
</Section> 

正好產生想要的,正確的結果

A AAA Honda A BBB Honda C CCC Toyota 

說明

  1. 這實際上是一個任務,用於生成屬於N個組的所有值的組合(Cell的孩子組成一個組),從每個組中取一個項目。

  2. 在K組的任何項目中,我們將此項目添加到組1,2,...,K-1的項目的當前組合。然後我們將這個新形成的組合傳遞給組K + 1。如果我們是最後一個組(N)中的一個項目,我們打印出(xsl:sequence)整個累積組合。

  3. 當控件返回時,其餘組的元​​素的所有組合(K + 1,K + 2,...,N)已被添加到我們當前組1,2, ...,K。所有這些組合都已經打印完畢。

  4. 我們傳遞給我們的相同組元素組合 - 現在我們將它傳遞給當前組(以下同胞)中的以下項目。

+0

Dimitre:謝謝你,比較你的解決方案與Lukasz的他們是如此的不同,因爲我還在學習你會介意解釋你的方法嗎?再次感謝!。 – JohnX 2012-02-26 00:10:00

+0

@JohnX:當然,我會在接下來的10分鐘內編輯我的答案。 – 2012-02-26 00:12:20

+0

@JohnX:已添加說明。 – 2012-02-26 00:25:42

1

我已經修改了你的做法一點,因爲我猜你真的不希望使用<xsl:message>診斷的操作。除此之外,我不產生在輸出XML和我不使用的for-each:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> 
    <xsl:output method="text" version="1.0" encoding="iso-8859-1" indent="yes"/> 
    <xsl:template match="/Section"> 
     <xsl:apply-templates select="Chapter"/> 
    </xsl:template> 
    <xsl:template match="Chapter"> 
     <xsl:apply-templates select="Cell/MyValue" /> 
    </xsl:template> 
    <xsl:template match="MyValue"> 
      <xsl:value-of select="../../Cell[@colname='1']/Value/text()"/> 
      <xsl:text> </xsl:text> 
      <xsl:value-of select="."/> 
      <xsl:text> </xsl:text> 
      <xsl:value-of select="../../Cell[@colname='3']/MyCar"/> 
      <xsl:text> </xsl:text> 
    </xsl:template> 
</xsl:stylesheet> 
+0

感謝Lukasz,感謝您的幫助。我想從你的解決方案看,我不得不經常使用apply-templates :)。 – JohnX 2012-02-26 00:03:07

+0

Lukasz,你可能有興趣看到更通用的解決方案...... :) – 2012-02-26 00:34:32