doppelte Daten anhand der gleichen @Id zählen

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • doppelte Daten anhand der gleichen @Id zählen

    Hallo zusammen,
    ich hoffe sehr, das mir geholfen werden kann, da ich momentan einfach nicht weiter komme. folgendes Problem:
    Ich habediesen xml-Code (nur beispielhaft):

    Quellcode

    1. <root>
    2. <node Id="52930571" Titel="TestBaum" Class="TextFolder" FrStatus="" Prod_Gruppe="" Prod_art="" Produkt="" Pfad="/Informationen/Spielwiese/Spiel/TestBaum">
    3. <node Id="52931339" Titel="Eb1" Class="TextFolder" FrStatus="" Prod_Gruppe="" Prod_art="" Produkt="" Pfad="/Informationen/Spielwiese/Spiel/TestBaum/Eb1">
    4. <node Id="52932107" Titel="Eb2" Class="TextFolder" FrStatus="" Prod_Gruppe="" Prod_art="" Produkt="" Pfad="/Informationen/Spielwiese/Spiel/TestBaum/Eb1/Eb2">
    5. <node Id="52932875" Titel="Eb3" Class="TextFolder" Pfad="/Informationen/Spielwiese/Spiel/TestBaum/Eb1/Eb2/Eb3">
    6. <node Id="52936715" Titel="Eb3_Knoten" Class="Knoten" Pfad="/Informationen/Spielwiese/Spiel/TestBaum/Eb1/Eb2/Eb3/Eb3_Knoten">
    7. <node Id="52946059" Titel="Eb3_Unterknoten" Class="Unterknoten" Pfad="/Informationen/Spielwiese/Spiel/TestBaum/Eb1/Eb2/Eb3/Eb3_Knoten/Eb3_Unterknoten"/>
    8. </node>
    9. </node>
    10. <node Id="52935179" Titel="Eb2_Knoten" Class="Knoten" Pfad="/Informationen/Spielwiese/Spiel/TestBaum/Eb1/Eb2/Eb2_Knoten">
    11. <node Id="52942347" Titel="Eb2_Unterknoten" Class="Unterknoten" Pfad="/Informationen/Spielwiese/Spiel/TestBaum/Eb1/Eb2/Eb2_Knoten/Eb2_Unterknoten"/>
    12. </node>
    13. </node>
    14. <node Id="52933643" Titel="Eb1_Knoten" Class="Knoten" Pfad="/Informationen/Spielwiese/Spiel/TestBaum/Eb1/Eb1_Knoten">
    15. <node Id="52938763" Titel="Eb1_Unterknoten" Class="Unterknoten" Pfad="/Informationen/Spielwiese/Spiel/TestBaum/Eb1/Eb1_Knoten/Eb1_Unterknoten"/>
    16. <node Id="52942347" Titel="Eb2_Unterknoten" Class="Unterknoten" Pfad="/Informationen/Spielwiese/Spiel/TestBaum/Eb1/Eb2/Eb2_Knoten/Eb2_Unterknoten"/>
    17. </node>
    18. </node>
    19. </node>
    20. </root>
    Alles anzeigen


    Darin gibt es einen redundanten Datensatz (Id=52942347, Titel=Eb2_Unterknoten). Ich möchte nur diese node mit einer Angabe wie oft sie vorkommt ausgegeben haben. Ich habe es folgendermaßen versucht:

    Quellcode

    1. <xsl:template match="/">
    2. <xsl:value-of select="count(//node[@Class='Knoten' or @Class='Unterknoten'])"/>
    3. <xsl:element name="br"/>
    4. <xsl:apply-templates select="//node[@Class='Knoten' or @Class='Unterknoten']"/>
    5. </xsl:template>
    6. <xsl:template match="node">
    7. <xsl:variable name="current.Id">
    8. <xsl:value-of select="@Id"/>
    9. </xsl:variable>
    10. <xsl:choose>
    11. <xsl:when test="//node[@Id = $current.Id]"> <!-- funktionier nicht! Hier liegt wohl das Problem -->
    12. <xsl:text>JUHU: </xsl:text>
    13. <xsl:value-of select="@Titel"/><xsl:text> Id: </xsl:text>
    14. <xsl:value-of select="@Id"/>
    15. <xsl:element name="br"/>
    16. </xsl:when>
    17. <xsl:otherwise>
    18. <xsl:text>Node ohne Reuse: </xsl:text>
    19. <xsl:value-of select="@Titel"/><xsl:text> Id: </xsl:text>
    20. <xsl:value-of select="@Id"/>
    21. <xsl:element name="br"/>
    22. </xsl:otherwise>
    23. </xsl:choose>
    24. </xsl:template>
    Alles anzeigen


    Momentan werden alle Knoten ausgegeben, da ja auch "self" verglichen wird und somit die Bedingung @Id = $current.Id für alle zutrifft. Muss ich wirklich auch noch die Verschachtelungsebene mit in die Bedingung bauen und wenn ja wie geht das?
    Ich hoffe es ist halbwegs klar was mein Problem ist und hoffe auf eure Hilfe!
    Danke und Grüße
    Helix
  • da sich die Elemente auf unterschiedlicher Hierarchie befinden ist das Vorhaben gar nicht so einfach.
    Schau dir mal dieses Buch an: books.google.de/books?id=wdzVe…num=1&ct=result#PPA165,M1

    gefunden via [google]xslt doppelte elemente rekursiv[/google]

    Du würdest also einmalig eine Liste aller IDs erstellen und diese dann irgendwie abfragen..
    // sorry, muss grad los, schaue später nochmal rein, habe aber auch schon länger nicht mehr mit XSLT gearbeitet.
  • Hi,
    danke für die antwort, habe es inzwischen selbst herausgefunden, hänge aber schon am nächsten Problem...
    Aber zunächst mal die Lösung:

    Quellcode

    1. <xsl:template match="/">
    2. <xsl:value-of select="count(//node[@Class='Knoten' or @Class='Unterknoten'])"/>
    3. <xsl:apply-templates select="//node[@Class='Knoten' or @Class='Unterknoten']"/>
    4. </xsl:template>
    5. <xsl:template match="node">
    6. <xsl:variable name="current.Id">
    7. <xsl:value-of select="@Id"/>
    8. </xsl:variable>
    9. <xsl:if test="count(//node[@Id = $current.Id])&gt;1">
    10. <xsl:text>JUHU: </xsl:text>
    11. <xsl:value-of select="@Titel"/><xsl:text> Id: </xsl:text>
    12. <xsl:value-of select="@Id"/>
    13. <xsl:element name="br"/>
    14. </xsl:if>
    15. </xsl:template>
    Alles anzeigen


    ich bekomme jetzt das Ergebniss:

    Quellcode

    1. 7<br/>
    2. JUHU: Eb2_Unterknoten Id: 52942347<br/>
    3. JUHU: Eb2_Unterknoten Id: 52942347<br/>


    Mein neues Problem ist jetzt, wie kann ich mir das Ergebnis nur einmal anzeigen lassen und wie kann ich die Häufigkeit dazu noch ausgeben lassen? Ich habe nur Xslt 1.1 groupby oder sowas fällt daher leider aus...
    Also etwas so soll es sein:

    Quellcode

    1. 7<br/>
    2. JUHU: Eb2_Unterknoten Id: 52942347 Häufigkeit: 2<br/>

    Ich hab ein bischen was über die Muensche Methode gelesen, aber muss ich mir das wirklich so kompliziert reinfahren? Versteh das noch nicht so ganz und dachte dass es in meinem Fall eigentlich auch einfacher gehen müsste.

    Danke
  • ach, der xpath war doch so einfach... count(//node[@Id = $current.Id]) &gt; 1

    Jetzt weiß das Element aber nur, dass es sich selbst mehrmals gibt.
    Die Anzahl auszulesen ist kein Problem: <xsl:value-of select="count(//node[@Id = $current.Id])"/> - am besten du speicherst den Wert in einer Variablen.

    Aber um eben einen Speicher zu haben mit IDs die schon abgearbeitet wurden musst du Rekursion anwenden, wie sie in dem Link oben beschrieben ist.

    Dazu musst du deine Logik auf call-template umstellen.
    Jeder Knoten ruft den nächsten in der Liste auf.
    Als Parameter wird die IDs durchgereicht die schon als Duplikat ausgegeben wurden.
    Weil man Variablen nicht überschreiben kann, musst du dazu eine neue Variable definieren.

    Versuch mal ob dir der Buchlink nicht vielleicht doch weiterhilft. Ich denke er löst genau dein Problem.
  • Alles klar, vielen Dank! Habe es nach dem Buch gemacht...
    also folgender Maßen:

    Quellcode

    1. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    2. <xsl:template match="/">
    3. <xsl:value-of select="count(//node[@Class='Unterknoten' or @Class='Knoten'])"/> <!-- Zahl Module -->
    4. <xsl:element name="br"/>
    5. <xsl:variable name="liste-reused-ids"> <!-- gibt eine bereinigte Liste aller mehrfach verwendeten Module aus -->
    6. <xsl:for-each select="//node[@Class='Unterknoten' or @Class='Knoten')]">
    7. <xsl:sort select="@Id"/>
    8. <xsl:variable name="current.Id">
    9. <xsl:value-of select="@Id"/>
    10. </xsl:variable>
    11. <xsl:if test="count(//node[@Id = $current.Id])&gt;1"> <!-- mehr als einmal vorkommend -->
    12. <xsl:value-of select="@Id"/>
    13. <xsl:text> </xsl:text>
    14. </xsl:if>
    15. </xsl:for-each>
    16. </xsl:variable>
    17. <xsl:variable name="haefigkeit">
    18. <xsl:for-each select="//node[@Class='Unterknoten' or @Class='Knoten')]">
    19. <xsl:variable name="current.Id">
    20. <xsl:value-of select="@Id"/>
    21. </xsl:variable>
    22. <xsl:if test="count(//node[@Id = $current.Id])&gt;1">
    23. <xsl:value-of select="count(//node[@Id = $current.Id])"/>
    24. </xsl:if>
    25. </xsl:for-each>
    26. </xsl:variable>
    27. <xsl:call-template name="group-by-use">
    28. <xsl:with-param name="liste-ids" select="$liste-reused-ids"/>
    29. <xsl:with-param name="letztes-Modul" select="''"/>
    30. <xsl:with-param name="haeufig" select="$haefigkeit"/>
    31. </xsl:call-template>
    32. </xsl:template>
    33. <xsl:template name="group-by-use"> <!-- gibt alle mehrfach verwendeten Module nur ein Mal an -->
    34. <xsl:param name="liste-ids"/>
    35. <xsl:param name="letztes-Modul" select="' '"/>
    36. <xsl:param name="haeufig"/>
    37. <xsl:variable name="next-Modul">
    38. <xsl:value-of select="substring-before($liste-ids, ' ')"/> <!-- gibt die nächste ID aus -->
    39. </xsl:variable>
    40. <xsl:variable name="weitere-Module">
    41. <xsl:value-of select="substring-after($liste-ids, ' ')"/> <!-- gibt die folgende ID aus -->
    42. </xsl:variable>
    43. <xsl:choose>
    44. <xsl:when test="not(string-length(normalize-space($liste-ids)))"/> <!-- wenn die Liste der IDs leer ist passiert nichts -->
    45. <xsl:when test="not($letztes-Modul=$next-Modul)"> <!-- wenn die nächste Id NICHT leer ist -->
    46. <xsl:value-of select="$next-Modul"/> <!-- schreibe die nächste Id mit Leerzeichen -->
    47. <xsl:text> </xsl:text>
    48. <!-- <xsl:value-of select="$haeufig"/><xsl:text> </xsl:text> -->
    49. <xsl:call-template name="group-by-use"> <!-- starte das Template von Beginn -->
    50. <xsl:with-param name="liste-ids" select="$weitere-Module"/> <!-- mit der folgenden Id -->
    51. <xsl:with-param name="letztes-Modul" select="$next-Modul"/>
    52. </xsl:call-template>
    53. </xsl:when>
    54. <xsl:when test="$letztes-Modul=$next-Modul"> <!-- wenn die nächste Id leer ist -->
    55. <xsl:call-template name="group-by-use">
    56. <xsl:with-param name="liste-ids" select="$weitere-Module"/>
    57. <xsl:with-param name="letztes-Modul" select="$next-Modul"/>
    58. </xsl:call-template>
    59. </xsl:when>
    60. </xsl:choose>
    61. </xsl:template>
    62. </xsl:stylesheet>
    Alles anzeigen

    Ich bekomme damit folgendes Ergebnis.
    7<br/>52942347 <!-- 2 2 -->

    Die Gruppierung funktioniert also, jetzt habe ich nur wieder das Problem, mir die Häufigkeit der Vorkommen zu der entsprechenden ID auszugeben. Ich habe versucht die Vorkommen mit einer eingenen Variablen an einen Parameter zu übergeben, allerdings schreibt er mir dann logischerweise die Zahl in ihrer Häufigkeit dahinter, also wenn der Knoten 2x vorkommt schreibt er 2 2. Und wenn ein weitere knoten mehrfach verwendet wird wird die Zahl nicht hinter die entsprechende ID geschrieben sondern auch hinter die Erste, da die gesamte Liste ausgegeben wird.
    Das ganze ist inzwischen schon ziemlich komplex, aber ich hoffe mir kann trotzdem jemand einen Tipp geben!

    Vielen Dank und Grüße
    Helix

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von Helix ()

  • so, hab die Zählung inzwischen gelöst, musste einfach

    <xsl:value-of select="count(//node[@Id = substring-after($next-Modul, '')])"/> hinter

    <xsl:value-of select="$next-Modul"/> <!-- schreibe die nächste Id mit Leerzeichen -->
    <xsl:text> </xsl:text>

    schreiben.

    jetzt habe ich aber wieder ein Problem mit dem Zählen, ich möchte die Summe aller Module haben, die mehrfach vorkommen. In dem minimierten Beispiel wäre das Ergebnis 1, da "Eb2_Unterknoten" der einzige Knoten ist, der doppelt vorkommt.
    In Wort gefasst sieht meine Abfrage folgendermaßen aus:
    zähle alle Nodes wo @Id = $current.Id])&gt;1 ist.
    Im Prinzip ein count im count oder so?! in xslt 2.0 ist Welt doch schöner geworden!

    Ich habe keinen blassen schimmer wie ich das hinbekomme und hoffe mir kann jemand helfen!

    Grüße
    Helix
  • lösung mit wenig xsl:template

    XML-Quellcode

    1. <?xml version="1.0"?>
    2. <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    3. <xsl:output method="html" indent="yes"/>
    4. <xsl:key name="wieviel" match="//node" use="@Id"/>
    5. <xsl:variable name="knall" select="//node"/>
    6. <xsl:template match="/">
    7. <xsl:value-of select="count($knall)"/>
    8. <xsl:call-template name="go">
    9. <xsl:with-param name="all" select="//node"/>
    10. </xsl:call-template>
    11. </xsl:template>
    12. <xsl:template name="go">
    13. <xsl:param name="all"/>
    14. <table border="solid 2px black">
    15. <tr>
    16. <td>@Id</td>
    17. <td>@Class</td>
    18. <td>Häufigkeit</td>
    19. </tr>
    20. <xsl:text>&#xA;</xsl:text>
    21. <xsl:for-each select="$all[generate-id()= generate-id(key('wieviel', @Id)[1])]">
    22. <xsl:sort select="@Id" order="ascending" data-type="text"/>
    23. <tr>
    24. <td>
    25. <xsl:value-of select="@Id"/>
    26. </td>
    27. <td>
    28. <xsl:value-of select="@Class"/>
    29. </td>
    30. <td>
    31. <xsl:value-of select="count(key('wieviel',@Id))"/>
    32. </td>
    33. </tr>
    34. </xsl:for-each>
    35. </table>
    36. </xsl:template>
    37. </xsl:stylesheet>
    Alles anzeigen


    Quellcode

    1. 11
    2. <table border="solid 2px black">
    3. <tr>
    4. <td>@Id</td>
    5. <td>@Class</td>
    6. <td>Häufigkeit</td>
    7. </tr>
    8. <tr>
    9. <td>52930571</td>
    10. <td>TextFolder</td>
    11. <td>1</td>
    12. </tr>
    13. <tr>
    14. <td>52931339</td>
    15. <td>TextFolder</td>
    16. <td>1</td>
    17. </tr>
    18. <tr>
    19. <td>52932107</td>
    20. <td>TextFolder</td>
    21. <td>1</td>
    22. </tr>
    23. <tr>
    24. <td>52932875</td>
    25. <td>TextFolder</td>
    26. <td>1</td>
    27. </tr>
    28. <tr>
    29. <td>52933643</td>
    30. <td>Knoten</td>
    31. <td>1</td>
    32. </tr>
    33. <tr>
    34. <td>52935179</td>
    35. <td>Knoten</td>
    36. <td>1</td>
    37. </tr>
    38. <tr>
    39. <td>52936715</td>
    40. <td>Knoten</td>
    41. <td>1</td>
    42. </tr>
    43. <tr>
    44. <td>52938763</td>
    45. <td>Unterknoten</td>
    46. <td>1</td>
    47. </tr>
    48. <tr>
    49. <td>52942347</td>
    50. <td>Unterknoten</td>
    51. <td>2</td>
    52. </tr>
    53. <tr>
    54. <td>52946059</td>
    55. <td>Unterknoten</td>
    56. <td>1</td>
    57. </tr>
    58. </table>
    Alles anzeigen


    hoffe dies ist die lösung
    Helmut Hagemann
    Derjenige, der sagt: Das geht nicht, soll den nicht stören, der's gerade tut.