2011-01-06 10 views
1

Wie kann ich doppelte Knoten basierend auf Werten mehrerer (mehr als 1) Attribute eliminieren? Auch die Attributnamen werden als Parameter an das Stylesheet übergeben. Jetzt ist mir die Münchnische Gruppierungsmethode bekannt, die ein <xsl:key> Element verwendet. Aber ich habe erfahren, dass XSLT 1.0 keine Parameter/Variablen in <xsl:key> erlaubt.Wie doppelte Knoten basierend auf Werten mehrerer Attribute zu beseitigen?

Gibt es eine andere Methode, doppelte Knoten zu entfernen? Es ist in Ordnung, wenn es nicht so effizient wie die Munechian Methode ist.

Update von 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

könnten Sie Beispiel XML und erforderliche Ausgabe zu Ihrer Frage hinzufügen – Treemonkey

Antwort

2

Mit dieser Transformation (einfach und keine Notwendigkeit, ein neues Stylesheet zu erzeugen):

<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> 

Der:

zum XML-Dokument Ihrer vorherigen Frage
<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> 

Bei der Anwendung gesucht, korrektes Ergebnis wird erzeugt:

<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> 
+0

+1. Habe hier viele Upvotes hinterlassen. – Flack

+0

@Dimitre: Das einzige Problem, das ich mit dieser Art des Erzeugens eines neuen Attributwerts sah, ist die Möglichkeit, ursprüngliche Attribute zu verpassen: Eine Schlüsselkollision könnte für eine 'Aufzeichnung' ohne' @ Operator2' und eine 'Aufzeichnung' ohne' @ Operator3' auftreten . –

+0

@Alejandro: Danke für eine weitere gute Beobachtung. Dies ist eine sofortige Lösung und ich werde es später am Nachmittag schaffen, wenn ich 10 Minuten Freizeit habe. –

1

Wenn Sie in den Attributnamen als Parameter übergeben wollen, dann ein Ansatz könnte ein zweistufiger Transformation sein, wo Im ersten Schritt werden alle XML-Eingaben und einfach die Attributnamen und die Elementnamen als Parameter verwendet, um ein zweites Stylesheet zu generieren, das die Duplikate eliminiert. Hier ist ein Beispiel erste Sheet:

<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> 

Es dauert vier Parameter:

  1. : den Namen des Elements enthält die Elemente, von denen Sie Duplikate beseitigen wollen
  2. element-name: der Name der Elemente, von denen Sie Dubletten entfernen möchten
  3. att-names: eine durch Komma getrennte Liste von Attributnamen
  4. sep: ein Trennzeichen, die nicht im Attributwert in dem Eingabe XML

Das Stylesheet erzeugt dann ein zweites Sheet, die Muench-Gruppierung gilt zu beseitigen Duplikate auftreten sollten. Zum Beispiel mit den Standardparametern im Stylesheet Saxon 6.5.5 generiert die folgende Sheet:

<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> 

die in ein XML-Dokument Dies kann wie

<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> 

und der Ausgang ist

<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 Für Stylesheet als Ausgabe. –

+0

+1. Markiert – Flack

+0

Ich möchte eigentlich auch den dritten Knoten von der Eingabe-XML, die in der produzierten Ausgabe eliminiert wurde. Wenn Sie sehen, dass der 3. Knoten nicht gelöscht werden soll, da es sich um einen eindeutigen Knoten handelt (kein anderer Knoten in der Eingabe ist genau wie dieser Knoten, basierend auf allen 3 Attributen). Lass es mich wissen, wenn das klickt. – JayRaj

3

anderer Ansatz für eine einzige Transformation in zwei Schritten angewandt werden, :

<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> 
ohne benannte Vorlage auch für @local-key Generation

<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> 

Hinweis: 10

Ausgang:

<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> 

bearbeiten Wenn Sie sicher sind positiv, die um Attribute ist die gleiche für alle Elemente, Sie dann könnte die Sortierung entfernen.

+0

+1 auch gute Lösung. – Flack

+0

+1 für mehr vorsichtig als ich und nicht offensichtlich Dinge zu überwachen. –

+0

@ Alejandro: Vielen Dank !! – JayRaj

Verwandte Themen