2016-03-03 21 views
1

這是我謙虛的XML文件:哦不,不是再次出現「XSLT 1.0查找重複」任務。但我真正的意思是

<choice> 
    <question> 
     <text>one</text> 
     <answer> 
      <text>2</text> 
     </answer> 
     <answer> 
      <text>2</text> 
     </answer> 
    </question> 
    <question> 
     <text>two</text> 
     <answer> 
      <text>d</text> 
     </answer> 
    </question> 
    <question> 
     <text>three</text> 
     <answer> 
      <text>1</text> 
     </answer> 
     <answer> 
      <text>2</text> 
     </answer> 
    </question> 
</choice> 

而這正是我試圖找出是否有在「問題」一式兩份文本:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    version="1.0"> 
    <xsl:template match="/choice"> 
     <xsl:variable name="ok" select="count(question/text)=count(question/text[not(.=following::text)])"/> 
     <xsl:copy-of select="$ok"/> 
     <xsl:if test="not($ok)"> 
      <xsl:message terminate="yes"> 
       Error: Duplicate Question 
      </xsl:message> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

工作正常 - 但如何我是否會發現答案部分是否有重複(本例中的問題 - 重複「2」)?

抱歉打擾,但我真的被困在這裏...

+1

這可能會幫助:http://stackoverflow.com/questions/10216035/how-to-check-duplicate-element-values-using-xslt – kjhughes

+1

請出示的情況下,預期的輸出1)有重複和2)如果沒有重複的話。謝謝。 –

+0

@MathiasMüller:我只對一個布爾變量感興趣,如果存在重複項,那麼它包含「false」,如果沒有,則包含「true」。在這個例子中,我只是在檢測到有重複的情況後才放棄不正當行爲。我對重複數量和價值都不感興趣。 –

回答

0

我一個question擴展你的測試案例,從而產生以下XML

<choice> 
    <question> 
     <text>one</text> 
     <answer> 
      <text>2</text> 
     </answer> 
     <answer> 
      <text>2</text> 
     </answer> 
    </question> 
    <question> 
     <text>two</text> 
     <answer> 
      <text>d</text> 
     </answer> 
    </question> 
    <question> 
     <text>three</text> 
     <answer> 
      <text>1</text> 
     </answer> 
     <answer> 
      <text>2</text> 
     </answer> 
    </question> 
    <question> 
     <text>three</text> 
     <answer> 
      <text>1</text> 
     </answer> 
     <answer> 
      <text>d</text> 
     </answer> 
    </question> 
</choice> 

以下XSLT隔離所有重複。 <for-each>是必要的保持preceding-sibling S的跟蹤(我不得不半隻用於輸出的位置編號(這是沒有必要的功能)):

<xsl:template match="/choice/question"> 
    <xsl:variable name="quesPos" select="position() div 2" /> 
    <xsl:for-each select="answer"> 
     <xsl:variable name="txt" select="text/text()" /> 
     <xsl:variable name="answPos" select="position()" /> 
     <xsl:for-each select="../preceding-sibling::*/answer"> 
     <xsl:if test="text/text() = $txt"> 
      <dup> 
      <xsl:value-of select="concat('question[',$quesPos,']/answer[',$answPos,'] = ',$txt,' is a duplicate')" /> 
      </dup><xsl:text>&#10;</xsl:text> 
     </xsl:if> 
     </xsl:for-each> 
    </xsl:for-each> 
    </xsl:template> 

的此模板的結果是

<?xml version="1.0"?> 
<dup>question[3]/answer[2] = 2 is a duplicate</dup> 
<dup>question[3]/answer[2] = 2 is a duplicate</dup> 
<dup>question[4]/answer[1] = 1 is a duplicate</dup> 
<dup>question[4]/answer[2] = d is a duplicate</dup> 

替換內部的部分<xsl:if>讓您可以選擇做任何你喜歡的事情。

所以只是爲原始的XSLT隔離重複刪除除了txtxsl:if內的所有變量。


第二種方法 - 這可能會更快 - 使用xsl:key索引(但不position()信息 - 如果你需要它,移動謂詞出for-each的)。這被稱爲Muenchian Grouping

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema" version="1.0"> 
    <xsl:key name="answers" match="answer" use="text/text()"/> 

    <xsl:template match="/choice"> 
    <xsl:for-each select="question/answer[not(generate-id() = generate-id(key('answers',text/text())[1]))]"> 
     <dup> 
     <xsl:value-of select="concat(name(),'[',generate-id(),'] = ',text/text(),' is a duplicate')" /> 
     </dup><xsl:text>&#10;</xsl:text>  
    </xsl:for-each> 
    </xsl:template> 
</xsl:stylesheet> 
+0

嵌套for-each方法工作正常,即使大數據集的性能可能不是最好的。如果有一個解決方案通過在嵌套結構中查找重複內容來結合兩個方面,本來就不錯。但是,在XSLT 2.0下可能還有更好的選擇。 –

+0

@Denis Giffeler:我添加了另一個更快的解決方案。 – zx485

+0

接受的答案 - 代表所有那些尋找重複的失落靈魂:謝謝! –

相關問題