2017-07-06 30 views
0

我工作XSLT具有使用忽略重複邏輯(MySegment/*[not(.=preceding::*)]).XSLT:忽略重複相似的價值觀

輸入:

<MySegment> 
<Field1>ABCD</Field1> 
<FIeld2>1</Field2> 
</MySegment> 
<MySegment> 
<Field1>ABCD123</Field1> 
<FIeld2>1</Field2> 
</MySegment> 

這裏,我們有兩個不同的值,但是因爲ABCD123包含ABCD以及,它被視爲重複條目。任何人都可以建議。

這裏是我的XSLT看起來像:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 

<xsl:template match="/RecordsInp"> 


      <xsl:for-each select="ParentSegment"> 


<xsl:for-each select="./MySegment/*[not(.=preceding::*)]"> 

        <A> 
         <Field1><xsl:value-of select ="name(.)"/></Field1> 
         <Field2><xsl:value-of select="."/></Field2> 
        </A> 

       </xsl:for-each> 

</xsl:for-each> 

    </xsl:template> 

</xsl:stylesheet> 

我輸入的是:

<RecordsInp> 
<ParentSegment> 
<MySegment> 
<Field1>ABC</Field1> 
<Field2>A1</Field2> 
</MySegment> 

    <MySegment> 
    <Field1>ABC</Field1> 
    <Field2>A1</Field2> 
    </MySegment> 
    <MySegment> 
    <Field1>ABCDEF</Field1> 
    <Field2>ABC</Field2> 
    </MySegment> 
    </ParentSegment> 
    </RecordsInp> 

我所得到的是:

<?xml version="1.0" encoding="UTF-8"?> 
    <A> 
     <Field1>Field1</Field1> 
     <Field2>ABC</Field2> 
    </A><A> 
     <Field1>Field2</Field1> 
     <Field2>A1</Field2> 
    </A><A> 
     <Field1>Field1</Field1> 
     <Field2>ABCDEF</Field2> 
    </A> 

注意,我沒有得到字段2 = ABC在最後一次出現。由於字段2從來沒有在先前出現過ABC,我需要以下XML:

<?xml version="1.0" encoding="UTF-8"?> 
<A> 
    <Field1>Field1</Field1> 
    <Field2>ABC</Field2> 
</A><A> 
    <Field1>Field2</Field1> 
    <Field2>A1</Field2> 
</A><A> 
    <Field1>Field1</Field1> 
    <Field2>ABCDEF</Field2> 
</A> 
<A> 
    <Field1>Field2</Field1> 
    <Field2>ABC</Field2> 
</A> 
+2

*「因爲ABCD123也包含ABCD,它被視爲重複」* - 否,而不是您顯示的XPath。 – Tomalak

+0

你能否建議如何解決這個問題?我的目標是循環遍歷此段的所有字段,並將它們填充到標題中,而不會有任何重複。 – Tpi

+0

我們無法就如何糾正代碼提供建議,而無需清楚地解釋代碼應該執行的操作,並至少呈現演示錯誤行爲的特徵示例。再加上示例輸入以及預期和觀察輸出,我們將其稱爲[mcve],這是我們希望您在提出修復代碼的幫助中提供的問題。 –

回答

0

根據你的第二個輸入例如,原因你樣式表不拉<Field2>ABC</Field2>你期望的方式是因爲ABC存在如在一個值在前Field1

可以也考驗名反對謂詞當前(current())的名字,但也許你應該嘗試使用xsl:keyMuenchian grouping),而不是preceding::軸...

XML輸入

<RecordsInp> 
    <ParentSegment> 
     <MySegment> 
      <Field1>ABC</Field1> 
      <Field2>A1</Field2> 
     </MySegment> 
     <MySegment> 
      <Field1>ABC</Field1> 
      <Field2>A1</Field2> 
     </MySegment> 
     <MySegment> 
      <Field1>ABCDEF</Field1> 
      <Field2>ABC</Field2> 
     </MySegment> 
    </ParentSegment> 
</RecordsInp> 

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:key name="fields" match="MySegment/*" 
    use="concat(name(),'|',normalize-space())"/> 

    <xsl:template match="MySegment"> 
    <xsl:for-each 
     select="*[count(.|key('fields',concat(name(),'|',normalize-space()))[1])=1]"> 
     <A> 
     <Field1><xsl:value-of select="name()"/></Field1> 
     <Field2><xsl:value-of select="."/></Field2> 
     </A> 
    </xsl:for-each> 
    </xsl:template> 

</xsl:stylesheet> 

輸出

<A> 
    <Field1>Field1</Field1> 
    <Field2>ABC</Field2> 
</A> 
<A> 
    <Field1>Field2</Field1> 
    <Field2>A1</Field2> 
</A> 
<A> 
    <Field1>Field1</Field1> 
    <Field2>ABCDEF</Field2> 
</A> 
<A> 
    <Field1>Field2</Field1> 
    <Field2>ABC</Field2> 
</A> 
+0

當然,將Meunchian分組應用於這樣的問題的訣竅是構造明確的關鍵值。當你需要通過連接多個單獨的值來形成一個密鑰時,總會有一個風險,你會被你選擇的分隔符出現在數據中。顯然,這樣的樣式表和OP的示例數據不會發生這種情況,但重要的是要保持頭腦後面某處的可能性。 –

+0

@JohnBollinger - 非常真實。同樣值得注意的是,您可以使用任何字符串而不是單個字符分隔符。例如,我可以使用'〜StackOverflowIsAwesome〜'來代替'|'。 –

+0

它的工作..你是一個天才。 – Tpi

0

你的XPath表達式./MySegment/*[not(.=preceding::*)]選擇每個上下文節點的<MySegment>兒童的字符串值不匹配的在文檔順序在它們之前的任何元素的那些子元素。因此,由於前面的<Field1>ABC</Field1>元素,<Field2>ABC</Field2>未反映在結果中。

很明顯,這是比你打算的更廣泛的條件;據我所知,你只想與前面的具有相同名稱的元素進行比較。在純XPath中表達這一點有點棘手;樣式表重構將更容易處理。無論如何,無條件地使用xsl:for-each都暗示了這樣的重構。這裏有一個合理的方法去解決它:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:template match="/RecordsInp/ParentSegment/MySegment/*"> 
    <!-- bind the context node's name and value to variables: --> 
    <xsl:variable name="fname" select="name()"/> 
    <xsl:variable name="fvalue" select="string(.)"/> 

    <!-- here's the test you seem really to want: --> 
    <xsl:if test="not(preceding::*[name() = $fname and string() = $fvalue])"> 
     <A> 
     <Field1><xsl:value-of select ="$fname"/></Field1> 
     <Field2><xsl:value-of select="$fvalue"/></Field2> 
     </A> 
    </xsl:if> 
    </xsl:template> 

</xsl:stylesheet>