2011-04-20 91 views
2

我有以下輸入:排序的價值元素和刪除重複

<?xml version="1.0" encoding="utf-8"?> 
<NewTerms> 
    <newTerm>XPath</newTerm> 
    <newTerm>AutoValue</newTerm> 
    <newTerm>XPath</newTerm> 
    <newTerm>context</newTerm> 
    <newTerm>AutoValue</newTerm> 
    <newTerm>language files</newTerm> 
    <newTerm>AutoValue</newTerm> 
    <newTerm>.NET</newTerm> 
    <newTerm>XPath</newTerm> 
</NewTerms> 

我想對它進行排序,並將其與下面的完美功能:

<xsl:output method="xml" indent="yes" omit-xml-declaration="no"/> 

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

</xsl:stylesheet> 

的問題是我得到(很明顯)重複排序的輸出列表中具有相同值的元素(例如XPath,AutoValue)。我想要沒有重複值的排序列表。也就是說,我希望在已排序的XML輸出中只有一次每個值。

請有什麼建議?

回答

2

這個樣式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:key name="kNewTermByValue" match="newTerm" use="."/> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="NewTerms"> 
     <xsl:copy> 
      <xsl:apply-templates select="@*"/> 
      <xsl:apply-templates 
      select="newTerm[count(.|key('kNewTermByValue',.)[1])=1]"> 
       <xsl:sort/> 
      </xsl:apply-templates> 
     </xsl:copy> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<NewTerms xp_0:noNamespaceSchemaLocation="../XSD\CC-CustomDocuTags.xsd" xmlns:xp_0="http://www.w3.org/2001/XMLSchema-instance"> 
    <newTerm>.NET</newTerm> 
    <newTerm>AutoValue</newTerm> 
    <newTerm>context</newTerm> 
    <newTerm>EPF</newTerm> 
    <newTerm>language files</newTerm> 
    <newTerm>XPath</newTerm> 
</NewTerms> 

注意:不要將屬性和子項排列在一起,因爲在輸出子項後無法輸出屬性。

+0

+1 - 更好的答案。我認爲測試集合中第一個節點的count(。| key('keyName',。)[1])= 1'方法比比較ID更漂亮(即使我並不總是使用它)。 – 2011-04-21 01:36:41

+0

@lwburk:我也喜歡這個,因爲集合論。但只有當你確定兩個操作數都是單例時(沒有人是空的),它纔有效。 – 2011-04-21 02:16:11

+0

+1精彩,我從你們那裏學到很多東西。現在很慚愧,我的回答被接受了。有沒有一種方法可以重新考慮它(對於所有其他正在尋找這種解決方案來指出這一點的人)? – rekaszeru 2011-04-21 10:38:03

1

你應該篩選排序的選擇:

<xsl:template match="@*|node()[not(preceding::node()=.)]"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*|node()"> 
      <xsl:sort select="."/> 
     </xsl:apply-templates> 
    </xsl:copy> 
</xsl:template> 

,它會給你所需的輸出:

<?xml version="1.0"?> 
<NewTerms> 
    <newTerm>.NET</newTerm> 
    <newTerm>AutoValue</newTerm>AutoValueAutoValue 
    <newTerm>EPF</newTerm> 
    <newTerm>XPath</newTerm>XPathXPath 
    <newTerm>context</newTerm> 
    <newTerm>language files</newTerm> 
</NewTerms> 
+0

謝謝你!我試圖用key()函數來做...並且沒有到達任何地方。我認爲這主要是bcos,我沒有真正瞭解key()函數是如何工作和作出反應的。 – Jasmin 2011-04-20 09:49:34

+0

請注意,這會丟棄屬性。另外,我不介意檢查小輸入的同類兄弟。性能差異不會引人注目。但值得注意的是,使用密鑰是更習慣於使用XSLT的方式,可以在大型輸入中獲得嚴重的性能優勢。我認爲我的政策至少會在放棄密鑰時提及。 – 2011-04-21 01:33:45