2011-01-06 45 views
1

如何基於多個(多於1個)屬性值來消除重複節點?屬性名稱也作爲參數傳遞給樣式表。現在我知道使用<xsl:key>元素的Muenchian分組方法。但是我開始知道XSLT 1.0在<xsl:key>中不允許參數/變量。如何根據多個屬性的值來消除重複的節點?

是否有另一種方法來實現重複節點刪除?如果它不如Munechian方法那麼高效就沒問題。

從previus question更新:

XML:

<data id = "root"> 
    <record id="1" operator1='xxx' operator2='yyy' operator3='zzz'/> 
    <record id="2" operator1='abc' operator2='yyy' operator3='zzz'/> 
    <record id="3" operator1='abc' operator2='yyy' operator3='zzz'/> 
    <record id="4" operator1='xxx' operator2='yyy' operator3='zzz'/> 
    <record id="5" operator1='xxx' operator2='lkj' operator3='tyu'/> 
    <record id="6" operator1='xxx' operator2='yyy' operator3='zzz'/> 
    <record id="7" operator1='abc' operator2='yyy' operator3='zzz'/> 
    <record id="8" operator1='abc' operator2='yyy' operator3='zzz'/> 
    <record id="9" operator1='xxx' operator2='yyy' operator3='zzz'/> 
    <record id="10" operator1='rrr' operator2='yyy' operator3='zzz'/> 
</data> 
+0

您可以添加示例xml和所需的輸出到您的問題 – Treemonkey 2011-01-06 12:27:44

回答

2

使用這種轉變(簡單,不需要生成新的樣式表):

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

<xsl:param name="pAttribs"> 
<name>operator1</name> 
<name>operator2</name> 
<name>operator3</name> 
</xsl:param> 

<xsl:variable name="vAttribs" select= 
    "document('')/*/xsl:param[@name='pAttribs']"/> 

<xsl:key name="kRecByAtts" match="record" 
    use="@___g_key"/> 

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

<xsl:template match="/"> 
<xsl:variable name="vrtdPass1"> 
    <xsl:apply-templates/> 
</xsl:variable> 

<xsl:variable name="vPass1" select= 
    "ext:node-set($vrtdPass1)/*"/> 

<xsl:apply-templates select="$vPass1"/> 
</xsl:template> 

<xsl:template match="record[not(@___g_key)]"> 
<xsl:copy> 
    <xsl:copy-of select="@*"/> 

    <xsl:attribute name="___g_key"> 
    <xsl:for-each select="@*[name()=$vAttribs/name]"> 
     <xsl:sort select="name()"/> 

     <xsl:value-of select= 
      "concat('___Attrib___',name(),'___Value___',.,'+++')"/> 
    </xsl:for-each> 
    </xsl:attribute> 
</xsl:copy> 
</xsl:template> 

<xsl:template match= 
    "record[@___g_key] 
     [not(generate-id() 
      = 
       generate-id(key('kRecByAtts', @___g_key)[1]) 
      ) 
      ] 
    "/> 

    <xsl:template match="@___g_key"/> 
</xsl:stylesheet> 

當適用於您剛纔的問題的XML文檔:

<data id = "root"> 
    <record id="1" operator1='xxx' operator2='yyy' operator3='zzz'/> 
    <record id="2" operator1='abc' operator2='yyy' operator3='zzz'/> 
    <record id="3" operator1='abc' operator2='yyy' operator3='zzz'/> 
    <record id="4" operator1='xxx' operator2='yyy' operator3='zzz'/> 
    <record id="5" operator1='xxx' operator2='lkj' operator3='tyu'/> 
    <record id="6" operator1='xxx' operator2='yyy' operator3='zzz'/> 
    <record id="7" operator1='abc' operator2='yyy' operator3='zzz'/> 
    <record id="8" operator1='abc' operator2='yyy' operator3='zzz'/> 
    <record id="9" operator1='xxx' operator2='yyy' operator3='zzz'/> 
    <record id="10" operator1='rrr' operator2='yyy' operator3='zzz'/> 
</data> 

的想要,正確的結果產生

<data id="root"> 
    <record id="1" operator1="xxx" operator2="yyy" operator3="zzz"/> 
    <record id="2" operator1="abc" operator2="yyy" operator3="zzz"/> 
    <record id="5" operator1="xxx" operator2="lkj" operator3="tyu"/> 
    <record id="10" operator1="rrr" operator2="yyy" operator3="zzz"/> 
</data> 
1

如果你想在屬性名作爲參數來傳遞,然後一個辦法可以是兩個步驟的變換,其中第一步接受任何XML輸入,並簡單地將屬性名稱和元素名稱作爲參數生成第二個樣式表,然後消除重複項。 下面是一個例子第一樣式表:

<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:exsl="http://exslt.org/common" 
    xmlns:axsl="http://www.w3.org/1999/XSL/TransformAlias" 
    exclude-result-prefixes="axsl exsl" 
    version="1.0"> 

    <xsl:param name="parent-name" select="'items'"/> 
    <xsl:param name="element-name" select="'item'"/> 
    <xsl:param name="att-names" select="'att1,att2'"/> 
    <xsl:param name="sep" select="'|'"/> 

    <xsl:namespace-alias stylesheet-prefix="axsl" result-prefix="xsl"/> 

    <xsl:output method="xml" indent="yes"/> 

    <xsl:variable name="key-value"> 
    <xsl:text>concat(</xsl:text> 
    <xsl:call-template name="define-values"> 
     <xsl:with-param name="att-names" select="$att-names"/> 
    </xsl:call-template> 
    <xsl:text>)</xsl:text> 
    </xsl:variable> 

    <xsl:template name="define-values"> 
    <xsl:param name="att-names"/> 
    <xsl:choose> 
     <xsl:when test="contains($att-names, ',')"> 
     <xsl:value-of select="concat('@', substring-before($att-names, ','), ',&quot;', $sep, '&quot;,')"/> 
     <xsl:call-template name="define-values"> 
      <xsl:with-param name="att-names" select="substring-after($att-names, ',')"/> 
     </xsl:call-template> 
     </xsl:when> 
     <xsl:otherwise> 
     <xsl:value-of select="concat('@', $att-names)"/> 
     </xsl:otherwise> 
    </xsl:choose> 
    </xsl:template> 

    <xsl:template match="/"> 
    <axsl:stylesheet version="1.0"> 
     <axsl:output indent="yes"/> 
     <axsl:key name="k1" match="{$parent-name}/{$element-name}" use="{$key-value}"/> 
     <axsl:template match="@* | node()"> 
     <axsl:copy> 
      <axsl:apply-templates select="@* | node()"/> 
     </axsl:copy> 
     </axsl:template> 
     <axsl:template match="{$parent-name}"> 
     <axsl:copy> 
      <axsl:apply-templates select="@*"/> 
      <axsl:apply-templates select="{$element-name}[generate-id() = generate-id(key('k1', {$key-value})[1])]"/> 
     </axsl:copy> 
     </axsl:template> 
    </axsl:stylesheet> 
    </xsl:template> 

</xsl:stylesheet> 

它需要四個參數:

  1. :含有的要消除重複
  2. element-name那些元件的元件的名稱:名稱您想要消除重複項的那些元素
  3. att-names:以逗號分隔的屬性名稱列表
  4. sep:不應該在輸入XML

樣式表中的屬性值發生分隔符接着產生適用Muenchian分組的消除重複的第二樣式表。例如使用樣式表Saxon 6.5中給出的默認參數。5生成以下樣式表:

<axsl:stylesheet xmlns:axsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <axsl:output indent="yes"/> 
    <axsl:key name="k1" match="items/item" use="concat(@att1,&#34;|&#34;,@att2)"/> 
    <axsl:template match="@* | node()"> 
     <axsl:copy> 
     <axsl:apply-templates select="@* | node()"/> 
     </axsl:copy> 
    </axsl:template> 
    <axsl:template match="items"> 
     <axsl:copy> 
     <axsl:apply-templates select="@*"/> 
     <axsl:apply-templates select="item[generate-id() = generate-id(key('k1', concat(@att1,&#34;|&#34;,@att2))[1])]"/> 
     </axsl:copy> 
    </axsl:template> 
</axsl:stylesheet> 

這可以在被施加到一個XML文檔等

<items> 
    <item att1="a" att2="1" att3="A"/> 
    <item att1="b" att2="1" att3="A"/> 
    <item att1="a" att2="1" att3="B"/> 
    <item att1="c" att2="2" att3="A"/> 
    <item att1="d" att2="3" att3="C"/> 
</items> 

並且輸出是

<items> 
    <item att1="a" att2="1" att3="A"/> 
    <item att1="b" att2="1" att3="A"/> 
    <item att1="c" att2="2" att3="A"/> 
    <item att1="d" att2="3" att3="C"/> 
</items> 
+0

+1樣式表作爲輸出。 – 2011-01-06 14:11:54

+0

+1。書籤。 – Flack 2011-01-06 17:12:13

+0

我實際上也希望輸入xml中的第三個節點在生成的輸出中被淘汰。如果您看到第三個節點不應該被刪除,因爲它是唯一節點(輸入中沒有其他節點與基於所有3個屬性的此節點完全相同)。讓我知道如果點擊。 – JayRaj 2011-01-12 07:40:58

3

在兩個步驟的單一變換的其它方法:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
exclude-result-prefixes="msxsl"> 
    <xsl:key name="kItemByLocal" match="record[@local-key]" use="@local-key"/> 
    <xsl:param name="pAttNames" select="'operator1 operator2 operator3'"/> 
    <xsl:template match="/"> 
     <xsl:variable name="vFirstRTF"> 
      <xsl:apply-templates/> 
     </xsl:variable> 
     <xsl:apply-templates select="msxsl:node-set($vFirstRTF)/node()"/> 
    </xsl:template> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="record[not(@local-key)]"> 
     <xsl:copy> 
      <xsl:attribute name="local-key"> 
       <xsl:call-template name="local-key"/> 
      </xsl:attribute> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="record[@local-key] 
           [count(.|key('kItemByLocal',@local-key)[1]) 
           != 1]|@local-key"/> 
    <xsl:template name="local-key"> 
     <xsl:param name="pAttributes" select="concat($pAttNames,' ')"/> 
     <xsl:if test="normalize-space($pAttributes)"> 
      <xsl:variable name="vName" 
          select="substring-before($pAttributes,' ')"/> 
      <xsl:variable name="vAttribute" select="@*[name()=$vName]"/> 
      <xsl:value-of select="concat($vName,'+',$vAttribute,'+')"/> 
      <xsl:call-template name="local-key"> 
       <xsl:with-param name="pAttributes" 
           select="substring-after($pAttributes,' ')"/> 
      </xsl:call-template> 
     </xsl:if> 
    </xsl:template> 
</xsl:stylesheet> 

輸出:

<data id="root"> 
    <record id="1" operator1="xxx" operator2="yyy" operator3="zzz"></record> 
    <record id="2" operator1="abc" operator2="yyy" operator3="zzz"></record> 
    <record id="5" operator1="xxx" operator2="lkj" operator3="tyu"></record> 
    <record id="10" operator1="rrr" operator2="yyy" operator3="zzz"></record> 
</data> 

編輯:還沒有命名模板@local-key

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
exclude-result-prefixes="msxsl"> 
    <xsl:key name="kItemByLocal" match="record[@local-key]" use="@local-key"/> 
    <xsl:param name="pAttNames" select="'operator1 operator2 operator3'"/> 
    <xsl:template match="/"> 
     <xsl:variable name="vFirstRTF"> 
      <xsl:apply-templates/> 
     </xsl:variable> 
     <xsl:apply-templates select="msxsl:node-set($vFirstRTF)/node()"/> 
    </xsl:template> 
    <xsl:template match="node()|@*"> 
     <xsl:copy> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="record[not(@local-key)]"> 
     <xsl:variable name="vAttNames" 
         select="concat(' ',$pAttNames,' ')"/> 
     <xsl:copy> 
      <xsl:attribute name="local-key"> 
       <xsl:for-each select="@*[contains(
              $vAttNames, 
              concat(' ',name(),' ') 
               )]"> 
        <xsl:sort select="substring-before(
              $vAttNames, 
              concat(' ',name(),' ') 
                )"/> 
        <xsl:value-of select="concat(name(),'++',.,'++')"/> 
       </xsl:for-each> 
      </xsl:attribute> 
      <xsl:apply-templates select="node()|@*"/> 
     </xsl:copy> 
    </xsl:template> 
    <xsl:template match="record[@local-key] 
           [count(.|key('kItemByLocal',@local-key)[1]) 
           != 1]|@local-key"/> 
</xsl:stylesheet> 

注意:如果你是積極肯定的屬性順序對於所有元素是相同的,那麼你可以刪除排序。

相關問題