2009-06-02 65 views
1

如果這是一個非常簡單的問題,請道歉;我不使用XSLT,並且在網絡上找不到太多建議,因爲搜索結果有很多污染!XSLT;在文檔中查找最常見的元素值

我有以下形式的XML文檔。其主要目的是通過XSLT以幾種方式重新格式化,以便以多種不同格式顯示。

<desk> 
<drawer> 
    <contents>pencils</contents> 
    <quantity>2</quantity> 
</drawer> 
<drawer> 
    <contents>pens</contents> 
    <quantity>15</quantity> 
</drawer> 
<drawer> 
    <contents>pencils</contents> 
    <quantity>3</quantity> 
</drawer> 
<drawer> 
    <contents>rulers</contents> 
    <quantity>2</quantity> 
</drawer> 
</desk> 

我想從xml中提取兩條信息:i)平均數量; ii)xml中出現次數最多的內容(即「鉛筆」,因爲它出現的次數最多,所以出現的次數是兩次而不是「筆」)。這個想法是,這可以被傳送到一個非常簡單的shell腳本中。因此,我認爲獲取這些信息的最簡單方法是編寫幾個簡短的xsl樣式表,然後使用xsltproc來獲取數據。

第一條信息看起來很簡單。樣式表的核心將是這條線:

<xsl:value-of select="(sum(drawer/quantity)) div (count(drawer))" /> 

但我有點卡住了第二。

我想我可以通過每一個人內容的列表,使用這樣的循環:

<xsl:for-each select="drawer[not(contents = preceding-sibling::drawer/contents)]" /> 

,但我不太清楚如何再以數具有$ current_contents和元素的數量其內容元素的值。我也看不到通過結果進行排序的簡單方法,因此我可以獲得最常遇到的內容值的名稱。

我有一種感覺,這在XSLT 2.0中有各種分組選項,但不幸的是,xsltproc似乎並不支持這一點。任何幫助將受到感謝。

非常感謝,

雅各

回答

2

與在XSLT解決的問題非常多,我想在這裏你的答案是muenchian grouping。按照您感興趣的任何數據進行分組,針對每個對象可以使用xsl:sort,然後根據第一個結果進行任何您需要的操作。

未經檢驗的,頂級的頭,可能會待一個清潔器方式代碼:

<xsl:key name="average" match="desk/drawer/contents" use="text()"/> 

<xsl:template match="/"> 
    <xsl:for-each select="desk/drawer/contents[generate-id() = generate-id(key('average',text())[1])]">  
     <xsl:sort select="count(//desk/drawer/contents[text()=current()])" order="descending"/> 
     <xsl:if test="position()=1"> 
      Most common value: "<xsl:value-of select="current()"/>" (<xsl:value-of select="count(//desk/drawer/contents[text()=current()])"/>) 
     </xsl:if>  
    </xsl:for-each> 
</xsl:template> 
+0

謝謝;這很有幫助。我無法解決怎麼做,雖然是「無論你需要什麼」一點。通過「內容」對XML進行分組是否有一種簡單的方法來計算特定「內容」值在xml中出現的次數? – 2009-06-02 11:43:19

+0

對不起,請參閱更新 – annakata 2009-06-02 12:18:51

0

for-each排序是通過sort元素來完成。只需按數量進行排序(如果您只想要最頻繁的),則只需添加一個<xsl:if test="position()=1">標籤即可獲得循環中的第一個標籤。

<xsl:for-each select="drawer"> 
    <xsl:sort select="quantity" data-type="number" order="descending"/> 
    <xsl:if test="position()=1"> 
     Most frequent: <xsl:value-of select="contents"> with <xsl:value-of select="quantity"> items 
    </xsl:if> 
</xsl:for-each> 
+0

啊,對不起,應該更清楚地說明一下自己。這將產生結果「鉛筆」,因爲有17支鉛筆。我想要的是製作「鉛筆」,因爲「鉛筆」出現兩次,「筆」和「尺子」出現一次。 – 2009-06-02 11:36:37

0

它已經有一段時間,但我認爲這些方針的東西可能會奏效。

首先計數的所有內容

<xsl:variable name="tally"> 
    <xsl:for-each select="drawer"> 
    <contents count="{count(drawer[contents = current()/contents])}"><xsl:value-of select="contents"/></contents> 
    </xsl:for-each> 
</xsl:variable> 

注意重複的條目每次計數,$理貨將包含:

<contents count="2">pencils</contents> 
<contents count="1">pens</contents> 
<contents count="2">pencils</contents> 
<contents count="1">rulers</contents> 

然後用它來找到一個對其中不存在其他與更高的計數:

<xsl:variable name="mostfrequentcontents" select="$tally/contents[not($tally/contents/@count > @count)]" /> 

根據您的xslt處理器,您可能需要將$使用節點集函數對一個節點集進行計數。