2016-04-12 8 views
1

Ausgangspunkt ist eine XML-Liste wieListe sortieren und Dubletten in XSLT eliminieren?

<attributes> 
     <para role="tocmain1"/> 
     <para role="tocmain1"/> 
     <other style="fix"/> 
     <other style="fix"/> 
     <para role="tocmain2"/> 
     <para role="tocmain2"/> 
     <para role="tocmain2"/> 
     <para role="tocmain3"/> 
     <para role="tocmain3"/> 
     <para language="de"/> 
     <para language="de"/> 
     <para role="tocmain3"/> 
</attributes> 

Ich mag würde das Vorkommen jedes Elements + Attribut + Wert Instanz nur ein Vorkommen zu reduzieren.

So:

<attributes> 
    <other style="fix"/> 
    <para language="de"/> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/>  
</attributes>` 

Bisher habe ich nur gelungen, in alphabetischer Reihenfolge die Liste zu bestellen. Alle meine Versuche, die Liste zu reduzieren, waren bisher vergeblich.

Das ist, was ich jetzt haben:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="2.0"> 
<xsl:template match="/"> 
    <attributes> 
     <xsl:for-each select="attributes/node()">    
      <xsl:sort select="name()" order="ascending"/>   
      <xsl:sort select="@*" order="ascending"/>     
      <xsl:choose> 
       <xsl:when test="name() = name(preceding::*[1]) and self::node()/@* = preceding::*/@*"/> 
       <xsl:otherwise> 
        <xsl:copy-of select="."/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:for-each> 
    </attributes> 
</xsl:template> 
</xsl:stylesheet> 

Antwort

0

Okay, auf Vorschlag von Daniel Haley habe ich eine Antwort gefunden, die für meine Frage funktioniert.

Ich bin jetzt mit zwei xsl nacheinander:

  1. XSL, die ohne Duplikate

    <xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
        <xsl:output indent="yes"/> 
        <xsl:strip-space elements="*"/>  
        <xsl:template match="@*|node()"> 
         <xsl:copy> 
          <xsl:apply-templates select="@*|node()"/> 
         </xsl:copy> 
        </xsl:template>  
        <xsl:template match="/*"> 
         <xsl:copy> 
          <xsl:apply-templates select="@*"/> 
          <xsl:for-each-group select="*" group-by="@*"> 
           <xsl:sort select="@*"/> 
           <xsl:apply-templates select="current-group()[1]"/> 
          </xsl:for-each-group> 
         </xsl:copy> 
        </xsl:template>  
    </xsl:stylesheet>
  2. XSL eine ungeordnete Liste gibt, die die Liste bestellt:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    version="2.0"> 
        <xsl:output indent="yes"/> 
        <xsl:strip-space elements="*"/> 
        <xsl:template match="/"> 
         <attributes> 
          <xsl:for-each select="attributes/node()">     
           <xsl:sort select="name()" order="ascending"/> 
           <xsl:sort select="name(@*)" order="ascending"/>     
           <xsl:sort select="@*" order="ascending"/>     
           <xsl:copy-of select="."/>     
          </xsl:for-each> 
         </attributes> 
        </xsl:template>   
    </xsl:stylesheet>
  3. Ergebnis wie gefordert:

    <attributes> 
        <other style="fix"/> 
        <para language="de"/> 
        <para role="tocmain1"/> 
        <para role="tocmain2"/> 
        <para role="tocmain3"/>  
    </attributes>

Vielen Dank für die ich die Antwort und sorry für irreführend Beispiel XML finden! Wenn jemand weiß, wie man die zwei Schritte in einem Skript kombiniert: Gern geschehen!

0

Ihre XSLT erzeugt Ihr Wunsch XML einige Formatierungsprobleme Modulo, die mit xsl:output und xsl:strip-space aufgelöst werden kann. Auch könnten Sie distinct-values() nutzen Sie den Code zu optimieren:

Ihr XML-Eingabedokument,

<attributes> 
    <para role="tocmain1"/> 
    <para role="tocmain1"/> 
    <para role="tocmain1"/> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
    <para role="tocmain3"/> 
    <para role="tocmain3"/> 
</attributes> 

auf diesen rationalisierte XSLT gegeben,

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

    <xsl:template match="/attributes"> 
    <attributes> 
     <xsl:for-each select="distinct-values(para/@role)"> 
     <xsl:sort select="." order="ascending"/> 
     <para role="{.}"/> 
     </xsl:for-each> 
    </attributes> 
    </xsl:template> 
</xsl:stylesheet> 

werden diese XML-Ausgabe produzieren Dokument,

<?xml version="1.0" encoding="UTF-8"?> 
<attributes> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
</attributes> 

wie angefordert.

1

Sie könnten auch xsl:for-each-group und xsl:apply-templates für den ersten Knoten in der Gruppe verwenden. Dies sollte es einfach machen, jede zusätzliche Transformation hinzuzufügen, die in der Zukunft erforderlich sein könnte.

XML Eingang (modifizierte korrekte Sortierung zu zeigen)

<attributes> 
    <para role="tocmain3"/> 
    <para role="tocmain2"/> 
    <para role="tocmain1"/> 
    <para role="tocmain3"/> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain1"/> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
</attributes> 

XSLT 2,0

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

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

    <xsl:template match="/*"> 
    <xsl:copy> 
     <xsl:apply-templates select="@*"/> 
     <xsl:for-each-group select="*" group-by="@role"> 
     <xsl:sort select="@role"/> 
     <xsl:apply-templates select="current-group()[1]"/> 
     </xsl:for-each-group> 
    </xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

XML Output

<attributes> 
    <para role="tocmain1"/> 
    <para role="tocmain2"/> 
    <para role="tocmain3"/> 
</attributes> 
+0

Ich hätte explizit erwähnen sollen, dass die Liste in Elementen, Attributen und Werten unterschiedlich ist. Ich habe meine Liste auf diese Weise bearbeitet. Alle deine Versuche, die @role verwenden, werden nicht funktionieren. Deshalb habe ich versucht, */@ * zu verwenden. Ich muss Duplikate auf der Grundlage des gleichen Elements + des gleichen Attributs + des gleichen Wertes löschen. – rena

Verwandte Themen