2010-07-22 118 views
1

我想根據元素名稱(然後通過相同的屬性名稱)在標題下對XPath的結果進行分類。注意:XML數據可能不一致,並且某些具有相同名稱的元素可能具有不同的屬性,因此它們需要不同的標題。元素和屬性名稱的動態分組

我似乎無法寫出自己的文字問題,所以它可能是最好用一個例子..

XML:

<pets> 
    <dog name="Frank" cute="yes" color"brown" type="Lab"/> 
    <cat name="Fluffy" cute="yes" color="brown"/> 
    <cat name="Lucy" cute="no" color="brown"/> 
    <dog name="Spot" cute="no" color="brown"/> 
    <dog name="Rover" cute="yes" color="brown"/> 
    <dog name="Rupert" cute="yes" color="beige" type="Pug"/> 
    <cat name="Simba" cute="yes" color="grey"/> 
    <cat name="Princess" color="brown"/> 

</pets> 

的XPath:

//*[@color='brown'] 

輸出應該看起來像什麼樣(對於不同的元素具有不同的標題):

ElementName Color Cute  Name  Type 
Dog   Brown Yes  Frank Lab 


ElementName Color Cute  Name  
Dog   Brown No  Spot  
Dog   Brown Yes  Rover 


ElementName Color Cute  Name  
Cat   Brown Yes  Fluffy  
Cat   Brown No  Lucy 



ElementName Color Name  
Cat   Brown Princess 

的XSL我現在有(簡化!):

<xsl:apply-templates select="//*[@color='brown']" mode="result"> 
    <xsl:sort select="name()" order="ascending"/> 
</xsl:apply-templates> 


<xsl:template match="@*|node()" mode="result"> 
    <tr> 
     <th align="left">Element</th> 

     <xsl:for-each select="@*"> 
      <xsl:sort select="name()" order="ascending"/> 
      <th align="left"> 
       <xsl:value-of select="name()"/> 
      </th> 
     </xsl:for-each> 
    </tr> 

    <tr> 
     <td align="left"> 
      <xsl:value-of select="name()"/> 
     </td> 
     <xsl:for-each select="@*"> 
      <xsl:sort select="name()" order="ascending"/> 
      <td align="left"> 
       <xsl:value-of select="."/> 
      </td> 
     </xsl:for-each> 
    </tr> 
</xsl:template> 

這上面XSL對其進行排序正確的方式我想..但現在我需要某種形式的檢查,看看哪些元素具有相同的名稱,然後如果它們具有相同的名稱,它們是否具有相同的屬性。一旦我完成了這項檢查,我就可以將一般的「標題」放在具有匹配元素名稱和屬性的記錄集之上。

我想我可以使用xsl:選擇xsl:when並做一些測試。我想(正確的排序已經完成後):

If element name != previous element name 
    create headings 
Else if all attributes != all previous element's attributes 
    create headings 

我想我最大的問題是,是,我不知道如何檢查以前返回的數據集是什麼?有人可以告訴我如何做到這一點?

或者,如果我接近這個錯誤..讓我更好的解決方案?

希望一切都有道理!讓我知道你是否需要澄清!

在此先感謝您的耐心和迴應! :)

+0

很好的問題! (+1)。查看我的答案,瞭解一個通用高效的XSLT 1.0解決方案,該解決方案可以處理任何可能的元素和屬性組合。 :) – 2010-07-23 02:13:38

回答

1

這種轉變不會使關於具有上述結構的集的任何假設相同數量的屬性 - 完全沒有假設

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ext="http://exslt.org/common" 
exclude-result-prefixes="ext"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:key name="kAnimalByProperties" match="animal" 
    use="concat(@atype, .)"/> 

<xsl:variable name="vrtfNewDoc"> 
    <xsl:apply-templates select="/pets/*"> 
    <xsl:sort select="name()"/> 
    </xsl:apply-templates> 
</xsl:variable> 

<xsl:template match="pets/*"> 
    <animal atype="{name()}"> 
    <xsl:copy-of select="@*"/> 
    <xsl:for-each select="@*"> 
     <xsl:sort select="name()"/> 
     <attrib>|<xsl:value-of select="name()"/>|</attrib> 
    </xsl:for-each> 
    </animal> 
</xsl:template> 

<xsl:template match="/"> 
    <xsl:for-each select="ext:node-set($vrtfNewDoc)"> 
    <xsl:for-each select= 
    "*[generate-id() 
     =generate-id(key('kAnimalByProperties', 
         concat(@atype, .) 
         )[1] 
        ) 
     ]"> 
     <table border="1"> 
      <tr> 
      <td>Element Name</td> 
      <xsl:for-each select="*"> 
       <td><xsl:value-of select="translate(.,'|','')"/></td> 
      </xsl:for-each> 
      </tr> 
      <xsl:for-each select= 
      "key('kAnimalByProperties', concat(@atype, .))"> 
      <xsl:variable name="vcurAnimal" select="."/> 
      <tr> 
       <td><xsl:value-of select="@atype"/></td> 
       <xsl:for-each select="*"> 
       <td> 
        <xsl:value-of select= 
        "$vcurAnimal/@*[name()=translate(current(),'|','')]"/> 
       </td> 
       </xsl:for-each> 
      </tr> 
      </xsl:for-each> 
     </table> 
     <p/> 
    </xsl:for-each> 
    </xsl:for-each> 
</xsl:template> 
</xsl:stylesheet> 

當所提供的XML文檔應用:

<pets> 
    <dog name="Frank" cute="yes" color="brown" type="Lab"/> 
    <cat name="Fluffy" cute="yes" color="brown"/> 
    <cat name="Lucy" cute="no" color="brown"/> 
    <dog name="Spot" cute="no" color="brown"/> 
    <dog name="Rover" cute="yes" color="brown"/> 
    <dog name="Rupert" cute="yes" color="beige" type="Pug"/> 
    <cat name="Simba" cute="yes" color="grey"/> 
    <cat name="Princess" color="brown"/> 
</pets> 

想要的,正確的結果產生

<table border="1"> 
    <tr> 
     <td>Element Name</td> 
     <td>color</td> 
     <td>cute</td> 
     <td>name</td> 
    </tr> 
    <tr> 
     <td>cat</td> 
     <td>brown</td> 
     <td>yes</td> 
     <td>Fluffy</td> 
    </tr> 
    <tr> 
     <td>cat</td> 
     <td>brown</td> 
     <td>no</td> 
     <td>Lucy</td> 
    </tr> 
    <tr> 
     <td>cat</td> 
     <td>grey</td> 
     <td>yes</td> 
     <td>Simba</td> 
    </tr> 
</table> 
<p/> 
<table border="1"> 
    <tr> 
     <td>Element Name</td> 
     <td>color</td> 
     <td>name</td> 
    </tr> 
    <tr> 
     <td>cat</td> 
     <td>brown</td> 
     <td>Princess</td> 
    </tr> 
</table> 
<p/> 
<table border="1"> 
    <tr> 
     <td>Element Name</td> 
     <td>color</td> 
     <td>cute</td> 
     <td>name</td> 
     <td>type</td> 
    </tr> 
    <tr> 
     <td>dog</td> 
     <td>brown</td> 
     <td>yes</td> 
     <td>Frank</td> 
     <td>Lab</td> 
    </tr> 
    <tr> 
     <td>dog</td> 
     <td>beige</td> 
     <td>yes</td> 
     <td>Rupert</td> 
     <td>Pug</td> 
    </tr> 
</table> 
<p/> 
<table border="1"> 
    <tr> 
     <td>Element Name</td> 
     <td>color</td> 
     <td>cute</td> 
     <td>name</td> 
    </tr> 
    <tr> 
     <td>dog</td> 
     <td>brown</td> 
     <td>no</td> 
     <td>Spot</td> 
    </tr> 
    <tr> 
     <td>dog</td> 
     <td>brown</td> 
     <td>yes</td> 
     <td>Rover</td> 
    </tr> 
</table> 
<p/> 
+0

@Dimitre:是的。這不會通過具有擴展功能的兩遍轉換進行任何假設。我認爲可以通過生成一個頭文件(按CVS解決方案按名稱對屬性進行分組)來覆蓋「讓我找到更好的解決方案」部分。另外,我認爲你的輸出標記更好!編輯我的。 – 2010-07-23 12:54:47

+0

@Alejandro:如果您使用CSV,那麼按順序獲取每個屬性名稱會很困難 - 以後當您需要時。 – 2010-07-23 13:01:55

+0

@Dimitre - 我需要看看爲什麼,但我只獲取標題和下面的值(僅顯示元素的名稱)。我將它複製並粘貼爲新文件。我將無法在一段時間內對它進行調查。儘管希望今天有一段時間。 :S – developer 2010-07-23 15:38:47

0

這個樣式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="ByName-AttNum" match="*/*[@color='brown']" use="concat(name(),'++',count(@*))"/> 
    <xsl:template match="/"> 
     <html> 
      <xsl:apply-templates/> 
     </html> 
    </xsl:template> 
    <xsl:template match="*/*[generate-id(.) = generate-id(key('ByName-AttNum',concat(name(),'++',count(@*)))[1])]"> 
     <table> 
      <tr> 
       <th>ElementName</th> 
       <xsl:apply-templates select="@*" mode="headers"> 
        <xsl:sort select="name()"/> 
       </xsl:apply-templates> 
      </tr> 
      <xsl:apply-templates select="key('ByName-AttNum',concat(name(),'++',count(@*)))" mode="list"/> 
     </table> 
    </xsl:template> 
    <xsl:template match="*" mode="list"> 
     <tr> 
      <td> 
       <xsl:value-of select="name()"/> 
      </td> 
      <xsl:apply-templates select="@*" mode="list"> 
       <xsl:sort select="name()"/> 
      </xsl:apply-templates> 
     </tr> 
    </xsl:template> 
    <xsl:template match="@*" mode="headers"> 
     <th> 
      <xsl:value-of select="name()"/> 
     </th> 
    </xsl:template> 
    <xsl:template match="@*" mode="list"> 
     <td> 
      <xsl:value-of select="."/> 
     </td> 
    </xsl:template> 
</xsl:stylesheet> 

結果:

<html> 
    <table> 
     <tr> 
      <th>ElementName</th> 
      <th>color</th> 
      <th>cute</th> 
      <th>name</th> 
      <th>type</th> 
     </tr> 
     <tr> 
      <td>dog</td> 
      <td>brown</td> 
      <td>yes</td> 
      <td>Frank</td> 
      <td>Lab</td> 
     </tr> 
    </table> 
    <table> 
     <tr> 
      <th>ElementName</th> 
      <th>color</th> 
      <th>cute</th> 
      <th>name</th> 
     </tr> 
     <tr> 
      <td>cat</td> 
      <td>brown</td> 
      <td>yes</td> 
      <td>Fluffy</td> 
     </tr> 
     <tr> 
      <td>cat</td> 
      <td>brown</td> 
      <td>no</td> 
      <td>Lucy</td> 
     </tr> 
    </table> 
    <table> 
     <tr> 
      <th>ElementName</th> 
      <th>color</th> 
      <th>cute</th> 
      <th>name</th> 
     </tr> 
     <tr> 
      <td>dog</td> 
      <td>brown</td> 
      <td>no</td> 
      <td>Spot</td> 
     </tr> 
     <tr> 
      <td>dog</td> 
      <td>brown</td> 
      <td>yes</td> 
      <td>Rover</td> 
     </tr> 
    </table> 
    <table> 
     <tr> 
      <th>ElementName</th> 
      <th>color</th> 
      <th>name</th> 
     </tr> 
     <tr> 
      <td>cat</td> 
      <td>brown</td> 
      <td>Princess</td> 
     </tr> 
    </table> 
</html> 

注意:這是假設具有相同數量的屬性的所有元素都具有相同的屬性的名稱(就像在你輸入樣本)。

編輯:更好的輸出標記。

編輯2:另一種解決方案:與所有更多鈔票屬性(如CSV圖案)和順序元件由屬性一個報頭數和名稱。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="attrByName" match="pets/*/@*" use="name()"/> 
    <xsl:variable name="attr" select="/pets/*/@*[count(.|key('attrByName',name())[1])=1]"/> 
    <xsl:template match="pets"> 
     <html> 
      <table> 
       <tr> 
        <th>ElementName</th> 
        <xsl:apply-templates select="$attr" mode="headers"> 
         <xsl:sort select="name()"/> 
        </xsl:apply-templates> 
       </tr> 
       <xsl:apply-templates select="*[@color='brown']"> 
        <xsl:sort select="count(@*)" order="descending"/> 
        <xsl:sort select="name()"/> 
       </xsl:apply-templates> 
      </table> 
     </html> 
    </xsl:template> 
    <xsl:template match="pets/*"> 
     <tr> 
      <td> 
       <xsl:value-of select="name()"/> 
      </td> 
      <xsl:apply-templates select="$attr" mode="list"> 
       <xsl:sort select="name()"/> 
       <xsl:with-param name="node" select="."/> 
      </xsl:apply-templates> 
     </tr> 
    </xsl:template> 
    <xsl:template match="@*" mode="headers"> 
     <th> 
      <xsl:value-of select="name()"/> 
     </th> 
    </xsl:template> 
    <xsl:template match="@*" mode="list"> 
     <xsl:param name="node"/> 
     <td> 
      <xsl:value-of select="$node/@*[name()=name(current())]"/> 
     </td> 
    </xsl:template> 
</xsl:stylesheet> 

結果:

<html> 
    <table> 
     <tr> 
      <th>ElementName</th> 
      <th>color</th> 
      <th>cute</th> 
      <th>name</th> 
      <th>type</th> 
     </tr> 
     <tr> 
      <td>dog</td> 
      <td>brown</td> 
      <td>yes</td> 
      <td>Frank</td> 
      <td>Lab</td> 
     </tr> 
     <tr> 
      <td>cat</td> 
      <td>brown</td> 
      <td>yes</td> 
      <td>Fluffy</td> 
      <td></td> 
     </tr> 
     <tr> 
      <td>cat</td> 
      <td>brown</td> 
      <td>no</td> 
      <td>Lucy</td> 
      <td></td> 
     </tr> 
     <tr> 
      <td>dog</td> 
      <td>brown</td> 
      <td>no</td> 
      <td>Spot</td> 
      <td></td> 
     </tr> 
     <tr> 
      <td>dog</td> 
      <td>brown</td> 
      <td>yes</td> 
      <td>Rover</td> 
      <td></td> 
     </tr> 
     <tr> 
      <td>cat</td> 
      <td>brown</td> 
      <td></td> 
      <td>Princess</td> 
      <td></td> 
     </tr> 
    </table> 
</html> 

注意:此貫穿樹兩次,但沒有擴展。對於所需的輸出完全匹配沒有擴展需要模仿關鍵機制是這樣的:通過樹中添加新鍵(元素的名稱加屬性的名字)來設置了一個param再通過鍵在樹篩選節點的每個鍵運行運行,然後(可能是一個小的優化,爲非匹配元素保留一個節點集合...)。最壞的情況下(與distinc鍵的每個節點)將通過槽的節點:N(關鍵建築)+(N + 1)* N/2

+0

看到沒有任何假設的解決方案:) – 2010-07-23 02:22:06