Nube2021: Doppelte Einträge ausfiltern

Hi,

ich bin relativ neu in XSL, habe aber bereits ein ganzes Buch verschlungen. Dennoch finde ich keine zufriedenstellende Lösung für mein aktuelles Problem, auch die Suche im mehreren Foren, einschließlich diesem, hat zu keinem Ergebnis geführt. Ich schildere einfach mal das Problem, doch zuerst die Struktur meiner XML-Datei:

<productlist>
<product>
 <num>000160562</num>
 <cat>Waschmaschinen</cat>
 <name>Miele XY1</name>
</product>
<product>
 <num>000160563</num>
 <cat>Waschmaschinen</cat>
 <name>Siemens CR3</name>
</product>
<product>
 <num>000160565</num>
 <cat>Radios</cat>
 <name>Philips CT-1</name>
</product>
.
.
</productlist>

Nun möchte ich, dass mir der Inhalt von <cat>(Kategorie) ausgegeben wird, wenn jedoch eine Kategorie bereits vorkam, soll diese nicht nochmal ausgegeben werden. Für obigen Ausschnitt sollte das gewünschte Ergebnis wie folgt aussehen:

Waschmaschinen
Radios

Mit der preceding-Achse habe ich das hinbekommen, jedoch vergeht bei der Größe der Datei (über 10.000 Datensätze) eine halbe Ewigkeitbis das Ergebnis ausgegeben wird, falls nicht vorher der Browser mitsamt Webserver abstürzt. In einem anderen Forum habe ich gelesen, dass man bei größeren Dateien besser xsl:key verwenden sollte, daraufhin habe ich mir was zusammengeschustert, was bei wenigen Datensätzen zu funktionieren scheint, aber bei Anwendung auf die komplette Datei ebenfalls total versagt:

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

<xsl:key name="category" match="productlist/product" use="cat"/>

<xsl:template match="/productlist">
    <xsl:for-each select="product[count(key('category',cat))]">
        <div><xsl:value-of select="cat"/></div>
    </xsl:for-each>
  </xsl:template>

</xsl:stylesheet>

Demnach müsste die for-each-Schleife immer nur das letzte Produkt einer bestimmten Kategorie zurückgeben. Wie gesagt, bei kleinen Dateien klappts, bei großen leider nicht.

Vielen Dank schon mal für jede Hilfe.
Nube2021

  1. Hallo Nube2021,

    Demnach müsste die for-each-Schleife immer nur das letzte Produkt einer bestimmten Kategorie zurückgeben. Wie gesagt, bei kleinen Dateien klappts, bei großen leider nicht.

    Probiere es so:

    <?xml version="1.0" encoding="ISO-8859-1"?>  
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  
      
    <xsl:output method="xml" encoding="ISO-8859-1" indent="yes" version="1.0"  
      doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN"  
      doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"/>  
      
    <xsl:key name="cat_key" match="product" use="cat"/>  
      
    <xsl:template match="productlist">  
      
    <html xmlns="http://www.w3.org/1999/xhtml" lang="de" xml:lang="de">  
    <head><title>Test</title></head><body>  
      <ul>  
        <xsl:for-each select="product[generate-id() = generate-id(key('cat_key',cat)[1])]">  
          <xsl:sort select="cat" data-type="text" order="ascending"/>  
          <li><xsl:value-of select="cat"/></li>  
        </xsl:for-each>  
      </ul>  
    </body></html>  
      
    </xsl:template>  
      
    </xsl:stylesheet>
    

    Sofern XSLT 2.0 zur Verfügung steht, wäre xsl:for-each-group eine Alternative.

    Ergebnis:
    ...
    <ul>
      <li>Radios</li>
      <li>Waschmaschinen</li>
    </ul>
    ...

    Grüße,
    Thomas

    1. Hi Thomas,

      danke für die schnelle Antwort, doch leider führt das zum gleichen Ergebnis: Bei wenigen Datensätzen funktioniert es wunderbar, mit der kompletten Datei jedoch nicht.

      Scheinbar scheint es für so große Dateien keine Lösung mit XSLT zu geben, so dass ich das Ganze doch mit mysql realisieren muss. Das betrübt mich sehr, denn ich habe viel wertvolle Zeit damit verbracht mich in XSLT einzuarbeiten. Wirklich sehr ärgerlich, weil ich mich auch richtig darauf gefreut hatte, endlich die Theorie in die Praxis umzusetzen.

      Ich habe zum einen die xml-Datei direkt aus dem Browser (Firefox) aufgerufen. Und dann habe ich es noch mit dem XSLT-Prozessor von php probiert (libxslt).

      Grüße
      Nube2021

      1. Hallo Nube2021,

        Scheinbar scheint es für so große Dateien keine Lösung mit XSLT zu geben, so dass ich das Ganze doch mit mysql realisieren muss.

        Das leuchtet mir nicht ein. Mit XSLT werden produktiv oft sehr große Dokumente verarbeitet.

        Ich habe zum einen die xml-Datei direkt aus dem Browser (Firefox) aufgerufen.

        Die Browser-Implementierungen sind nicht sehr robust. Probiere es mal mit Saxon 9.0B.

        java -jar pfad/zu/saxon9.jar -o name.html name.xml name.xsl

        Grüße,
        Thomas

        1. Die Browser-Implementierungen sind nicht sehr robust.

          Mit dem libxslt-Prozessor von php ist das genauso langsam.

          »»Probiere es mal mit Saxon 9.0B.

          Kann ich machen, aber da das Stylesheet in ein PHP-Projekt integriert ist, muss das halt auch mit libxslt funktionieren, und das tut es leider nicht. Dennoch werde ich es gleich probieren, einfach um die Ursache des Problems ausfindig zu machen.

          Grüße
          Nube2021

          1. Hallo Nube2021,

            Mit dem libxslt-Prozessor von php ist das genauso langsam.

            Was denn nun: "langsam" oder "funktioniert nicht"? Ein großes XML-Dokument frisst natürlich Ressourcen und die Performance bricht ein, wenn ein PHP-Speicherlimit von 8 MB oder ähnlich existiert ...

            ... aber da das Stylesheet in ein PHP-Projekt integriert ist, muss das halt auch mit libxslt funktionieren, und das tut es leider nicht.

            Wie erfolgt die Transformation mit PHP?

            Grüße,
            Thomas

        2. Hallo Thomas,

          hinsichtlich des libxslt-Prozessors habe ich mich geirrt, denn mit deinem Code-Vorschlag funktioniert das Ganze schon, es benötigt aber immer noch ca. 8 Sekunden, was für den Aufbau einer Website natürlich inakzeptabel ist. Mit einer gut indexierten mysql-Datenbank sind es gerade mal ein Bruchteil einer Sekunde. Schade. Dennoch probiere ich es bei Gelegenheit mit dem Saxon, einfach um zu sehen, dass XSLT zumindest das Potential gehabt hätte, wenn nur nicht...

          Grüße
          Nube2021