2012-07-29 63 views
2

XML/XSL/Xpath的新手,我已經在這些板上搜索了一個看似簡單的問題的答案,但也許我對XSL太陌生了,以便理解可能解決這個問題的一些答案。XSL問題:如何根據一組節點值選擇一組節點?

我想選擇一組搭配一組不同的文檔存儲在別處節點值的節點,使:

<body> 
    <partlist> 
     <part>head</part> 
     <part>spleen</part> 
     <part>toe</part> 
    </partlist> 
    <parts> 
     <head>this is a head</head> 
     <spleen>this is a spleen</spleen> 
     <toe>big toe</toe> 
     <toe>big toe</toe> 
    <parts> 
</body> 

所以,讓我們說,我想指望所有的「零件」 ,但我不知道「部分」節點名稱,我想要一個XPath expr來匹配一組節點,其名稱等於另一組節點的值...

我已經足夠新XSL既想象一個解決方案非常簡單,但經驗豐富,足以認識到期望從XSL獲得簡單的解決方案是一個肯定的錯誤路徑。

在我的基礎程序,無知,這是我曾嘗試:

<xsl:template match="/"> 
    <xsl:apply-templates select="partlist/part"> 
     <xsl:with-param name="parts" select="parts"/> 
    </xsl:apply-templates> 
</xsl:template> 
<xsl:template match="part"> 
    <xsl:param name="parts"/> 
    <xsl:value-of select="count($parts[.])"/>   
</xsl:template> 

但是,這是完全錯誤的。任何幫助深表感謝。

編輯:謝謝你的答案,但我認爲我沒有被理解 - 錯誤是我的,因爲我還沒有完全清楚......我需要的是一個單一的結果告訴我,如果有任何與引用集的節點值相匹配的節點...我認爲會更改查詢,因爲我沒有嘗試輸出計數列表,我試圖將集合與集合進行匹配以計算總數。 。但讓我XSL澄清,如果這樣的事情是可能的。這裏是我上面的代碼稍加修改,使我的意圖明顯:

<xsl:template match="/"> 
    <xsl:apply-templates select="partlist/part"> 
     <xsl:with-param name="parts" select="parts"/> 
    </xsl:apply-templates> 
</xsl:template> 
<xsl:template match="part"> 
    <xsl:param name="parts"/> 
    <xsl:if select="count($parts[.]) &gt; 0">1</xsl:if>   
</xsl:template> 
當應用到XML文檔例子

上述應該輸出:

1 

這是否有意義?

編輯:我還應該指定,我僅限於XSL 1.0

+0

我有不祥的預感,這個問題將是其中的一個「如果你瞭解XSL和XPath,你就不會問這樣的問題」,這基本上意味着它不能做完了。我得說,在程序和oop背景下,我很困惑,爲什麼有人會設計一種語言,答案是如此頻繁,「不能這樣做」。 – user1558945 2012-07-30 06:46:49

+1

對於XSLT,我從來沒有聽說過「它不能完成」。在某些情況下,這肯定不太明顯,但始終可以完成。 XSLT具有功能性背景,這就是爲什麼OOP /命令式背景的人看起來很奇怪。與過程相比,XSLT解決方案非常容易*的情況也很多*。幾乎所有涉及[身份模板](http://www.xmlplease.com/xsltidentity) – 2012-07-30 14:48:31

回答

1

可以使用local-name()函數來獲取一個節點的名稱,以便您可以針對給定的值進行比較。

例如,樣式表可以修改此:

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

    <xsl:template match="/"> 
    <xsl:apply-templates select="body/partlist/part"/> 
    </xsl:template> 

    <xsl:template match="part"> 
    <xsl:variable name="part" select="."/> 
    <xsl:value-of select="count(/body/parts/*[local-name() = $part])"/> 
    </xsl:template> 

</xsl:stylesheet> 

編輯補充:

您也可以比較值的集合,而不只是單一的值。從XPath 1.0 spec, section 3.4

如果一個要比較的對象是一個節點集合,而另一個是一個字符串, 則比較爲真,當且僅當存在中的一個節點的 節點集合,使得對節點的 字符串值和另一個字符串執行比較的結果爲true。

如果要算你有多少元素具有/body/parts其本地名稱下/body/partlist/part列出的部分相匹配,你可以用這個XPath表達式做到這一點:

count(/body/parts/*[local-name() = /body/partlist/part]) 

從問題中的最後一個轉型,添加了編輯之後,可以改寫,例如像這樣:

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

    <xsl:template match="body"> 
    <xsl:apply-templates select="partlist"> 
     <xsl:with-param name="parts" select="parts"/> 
    </xsl:apply-templates> 
    </xsl:template> 

    <xsl:template match="partlist"> 
    <xsl:param name="parts"/> 
    <xsl:if test="count($parts/*[local-name() = current()/part]) &gt; 0">1</xsl:if>   
    </xsl:template> 

</xsl:stylesheet> 
+0

謝謝,這很明顯,不幸的是我看到我的答案不是。我已經修改了它,所以希望它更有意義:它不是我想比較的單個值,它是一組值... – user1558945 2012-07-29 23:08:35

+0

@ user1558945,編輯瞭如何與一組值而不只是一個 – 2012-07-30 14:13:49

+0

輝煌,謝謝!我正要放棄。 – user1558945 2012-07-30 15:44:22

1

一本XSLT 1.0轉換

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

<xsl:template match="part"> 
    <xsl:value-of select="."/> 

    <xsl:value-of select= 
    "concat(': ', 
      count(/*/parts/*[name() = current()]), 
      '&#xA;')"/> 
</xsl:template> 
<xsl:template match="text()"/> 
</xsl:stylesheet> 

當所提供的XML文檔應用:

<body> 
    <partlist> 
     <part>head</part> 
     <part>spleen</part> 
     <part>toe</part> 
    </partlist> 
    <parts> 
     <head>this is a head</head> 
     <spleen>this is a spleen</spleen> 
     <toe>big toe</toe> 
     <toe>big toe</toe> 
    </parts> 
</body> 

產生想要的,正確的結果

head: 1 
spleen: 1 
toe: 2 

說明

正確使用模板和current()函數。


二,與單個的XPath 2.0表達式:

/*/partlist 
     /part 
      /concat(., 
        ': ', for $p in . 
         return count(/*/parts/*[name() eq $p]), 
        '&#xA;' 
       ) 

當此XPath 2.0表達式與相同的XML文檔(上圖),有用的,正確的結果產生評價:

head: 1 
spleen: 1 
toe: 2 

這裏是基於XSLT 2.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 method="text"/> 

<xsl:template match="/"> 
    <xsl:sequence select= 
    "/*/partlist 
     /part 
      /concat(., 
        ': ', for $p in . 
         return count(/*/parts/*[name() eq $p]), 
        '&#xA;' 
       ) 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

更新

的OP已經改變的問題,似乎他想:

我需要的是一個單一的結果告訴我,如果有 匹配的節點值的任何節點

0123: - 轉診集...

這同樣簡單的事情可以用一個XPath表達式獲得

該表達式評估爲true()準確時,有一些/*/parts/*name()/*/partlist/part元素的字符串值中的一個。

上述表達式可以用「原樣」在其中一個布爾期望(例如在任何謂詞任何地方,作爲xsl:ifxsl:when指令的test屬性的值,...,等等。

如果該值爲1而被通緝(ANF不true()),只需使用:

number(/*/parts/*[name() = /*/partlist/part]) 

這給了我們想要的結果1或0,因爲根據定義:

number(true()) = 1 

number(false()) = 0