2016-04-18 130 views
0

給出的以下XML文檔選擇元件組的第一元素:使用XSLT 1.0

<foo> 
    <bar> 
    <type>1</type> 
    <id>1</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>1</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>2</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>2</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
</foo> 

bar是列表元素,按類型和id邏輯上分組的XML元素。因此,示例文檔包含兩個有序列表(type = 1和id = 1,type = 1和id = 2),每個列表包含兩個元素。在真實文檔中,還有更多不同長度的列表(使用不同類型和ID)。

現在我需要用不同的值更新每個列表的第一個元素a1,下列文件中:

<foo> 
    <bar> 
    <type>1</type> 
    <id>1</id> 
    <a1>-100</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>1</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>2</id> 
    <a1>-100</a1> 
    <other_stuff/> 
    </bar> 
    <bar> 
    <type>1</type> 
    <id>2</id> 
    <a1>0</a1> 
    <other_stuff/> 
    </bar> 
</foo> 

在僞SQL這可能會是這樣的:

update bar set a1 = -100 where position() = 1 group by type, id 

這是可能的XSLT 1.0?我認爲可以歸結爲能夠編寫一個XPath表達式,其結果與我的僞SQL語句相同。

回答

2

使用Muenchian grouping每個組中確定的第一項和改變孩子,其餘與身份轉換複製:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="1.0"> 

    <xsl:param name="new-value" select="-100"/> 

    <xsl:key name="group" match="bar" use="concat(type, '|', id)"/> 

    <xsl:template match="@* | node()"> 
     <xsl:copy> 
      <xsl:apply-templates select="@* | node()"></xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="bar[generate-id() = generate-id(key('group', concat(type, '|', id))[1])]/a1"> 
     <xsl:copy> 
      <xsl:value-of select="$new-value"/> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

至於進一步的解釋,關鍵定義<xsl:key name="group" match="bar" use="concat(type, '|', id)"/>讓XSLT處理器指數barconcat(type, '|', id)上的元素,以便我們可以使用例如key('group', '1|1')找到所有bar元素的值爲concat(type, '|', id)

你只需要改變第一bar元素每組所以我們需要有一種方法來識別謂語的內部的第一項bar[...],我們需要找到一個表達的條件

bar[. is the first item in its group] 
模式

我們得到與key('group', concat(type, '|', id))模式裏面,所以我們要編寫一個條件

bar[. is the first item in key('group', concat(type, '|', id))] 

,我們可以用近字面上表達XSLT 2.0組10操作員和圖案

bar[. is key('group', concat(type, '|', id))[1]] 

隨着XSLT 1.0,我們可以使用產生-ID表達它,如在

bar[generate-id() = generate-id(key('group', concat(type, '|', id))[1])] 

,其選擇進行/那些bar元件的量,生成的ID等於匹配由key('group', concat(type, '|', id))計算的組中第一個([1])項目的生成ID。

+0

只是爲了我的理解:'xsl:key'使用子元素'type'和'd'的內容的字符串連接爲所有'bar'元素生成一個鍵。然後'generate-id(...)'函數調用會重新生成該鍵並檢查它是否與當前元素相匹配。這將爲每個類型(id對)創建一個列表,然後選擇其中的第一個。這或多或少是正確的? – Markus

+0

@Markus,我已經添加了關於使用方法的一些解釋,我已經採用了XSLT 2.0的一種方式,因爲那裏的表達更容易表達,更接近自然語言。 –