Announcement

Collapse
No announcement yet.

Nummerierung & Liste erstellen

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Nummerierung & Liste erstellen

    Hallo zusammen,

    ich sitze bereits seit mehreren Tagen an folgendem Problem:

    Die XML - Datei
    Code:
    <test>
      <provider>
       <offer id="1" name="a">
        <location id="67890" name="def" />
        <location id="12345" name="abc" />
       </offer>
       <offer id="2" name="b">
        <location id="12345" name="abc" />
       </offer>
       <offer id="3" name="c">
        <location id="12345" name="abc" />
        <location id="67890" name="def" />
       </offer>
      </provider>
    </test>
    Nun erstelle ich mir eine Liste mit allen Angeboten, welche durchnummeriert werden:
    Code:
    <?xml version="1.0" encoding="iso-8859-1"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:key name="id" match="location" use="@id" />
    
      <xsl:template match="/">
      <xsl:apply-templates />     
      </xsl:template>
      
      <xsl:template match="provider">  
        Orte_Liste:<xsl:text> </xsl:text>
        <xsl:call-template name="List_location" />
        
        <xsl:apply-templates select="offer" /> 
        </xsl:template> 
        
      <xsl:template match="offer">
        Angebot<xsl:value-of select="@name" /><xsl:text>: </xsl:text>
        <xsl:apply-templates select="location" />
        <xsl:text>&#xa;</xsl:text>
      </xsl:template> 
    
      <xsl:template match="location"> 
          <xsl:text> </xsl:text><xsl:value-of select="@id" />
          <xsl:text> </xsl:text><xsl:value-of select="@name" />
          <xsl:text> 
          </xsl:text> 
      </xsl:template> 
    
      <xsl:template name="List_location"> 
        <xsl:for-each select="//location[generate-id() = generate-id(key('id', @id)[1])]">
          <xsl:text> 
          </xsl:text> <xsl:value-of select="position()" />
          <xsl:text> </xsl:text><xsl:value-of select="@name" />
        </xsl:for-each>
        <xsl:text> 
        </xsl:text>
      </xsl:template>
    
    </xsl:stylesheet>
    Als nächstes will ich die einzelnen Angebote zusammen mit der Nummer aus der Liste ausgeben. Also folgendes Ergebnis erhalten:
    Code:
    Orte_Liste:  
          1 def 
          2 abc 
        
      Angebot a:  1, 2 
          
    
      Angebot b:  2
          
    
      Angebot c:  2, 1
    Wie kann ich dies erreichen?

    Danke für Eure Hilfe
    Andrea

  • #2
    Ansatz mit einer Hilfsvariablen $auftrag, die am Anfang global erzeugt wird und im location-Template mittels String-Funktionen ausgewertet wird:

    Code:
    <!-- direkt nach <xsl:key ... /> einfügen: -->
    <xsl:variable name="auftrag">
      <xsl:for-each select="//location[generate-id() = generate-id(key('id', @id)[1])]">
        <xsl:value-of select="position()"/><xsl:value-of select="@name"/>
      </xsl:for-each>
    </xsl:variable>
    <!-- $auftrag enthält im Beispiel die Zeichenkette 1def2abc -->
    Code:
    <!-- neues location-Template: -->
    <xsl:template match="location"> 
      <xsl:value-of select="substring(substring-before($auftrag,@name),string-length(substring-before($auftrag,@name)))"/>
      <xsl:if test="position() != last()"><xsl:text>, </xsl:text></xsl:if>
    </xsl:template>
    Ergebnis:
    Code:
        Orte_Liste:  
          1 def 
          2 abc
        
        Angebot a: 1, 2
    
        Angebot b: 2
    
        Angebot c: 2, 1

    Comment


    • #3
      Originally posted by Thomas Meinike View Post
      Ansatz mit einer Hilfsvariablen $auftrag, die am Anfang global erzeugt wird und im location-Template mittels String-Funktionen ausgewertet wird
      Hallo Thomas,

      auf die Idee eine Hilfsvariable zu verwenden bin ich nicht gekommen.

      Danke für Deine Hilfe
      Avallyn

      Comment


      • #4
        Hallo zusammen,

        ich habe mich jetzt einige Zeit mit den Variablen beschäftigt und es hat auch fürs erste gut funktioniert. Wenn meine XML - Datei allerdings größer wird, also mehr als einen <provider /> enthält, funktioniert es nicht mehr.

        Code:
        <test>
          <provider>
           <offer id="1" name="a">
            <location id="67890" name="def" />
            <location id="12345" name="abc" />
           </offer>
           <offer id="2" name="b">
            <location id="12345" name="abc" />
           </offer>
           <offer id="3" name="c">
            <location id="12345" name="abc" />
            <location id="67890" name="def" />
           </offer>
          </provider>
          <provider>
           <offer id="4" name="d">
            <location id="23456" name="xyz" />
            <location id="78901" name="uvw" />
           </offer>
           <offer id="5" name="e">
            <location id="78901" name="uvw" />
           </offer>
          </provider>
        </test>
        Meine nummerierten Listen kann ich einfach anpassen:
        Code:
        <xsl:template name="List_location"> 
            <xsl:for-each select=".//location[generate-id() = generate-id(key('id', @id)[1])]"> 
              <xsl:text> 
              </xsl:text> <xsl:value-of select="position()" />
              <xsl:text> </xsl:text><xsl:value-of select="@name" />
            </xsl:for-each>
            <xsl:text> 
            </xsl:text>
          </xsl:template>
        Ergebnis momentan:
        Code:
        Orte_Liste:  
              1 def 
              2 abc 
             
            Angebot a: 1, 2   
            Angebot b: 2
            Angebot c: 2, 1  
          
            Orte_Liste:  
              1 xyz 
              2 uvw 
             
            Angebot d: 3, 4
            Angebot e: 4
        Die Nummern (Referenzen) des zweiten Anbieters stimmen nicht.

        Kann ich die Variable auch lokal mit der Liste erzeugen und die Werte dann an ein anderes Template übergeben, wie z.B. einen return - Wert in Java oder C++?

        Danke für Eure Hilfe
        Avallyn

        Comment


        • #5
          Probiere es aus mit xsl:call-template und xsl:with-param / xslaram zur Parameterübergabe im Sinne von Funktionsaufrufen.

          Comment


          • #6
            Leider hilft mir auch die Verwendung von xsl:call-template und xsl:with-param / xsl: param nicht weiter.

            Deswegen kurz zurück zum Ausgangsproblem:
            1. Vorgabe: eine XML - Datei mit mehreren Anbietern mit jeweils mehreren Angeboten, mit jeweils mehreren Orten.
            2. je Anbieter soll eine nummerierte Liste mit allen Orten (ohne Duplikate) erstellt werden
            3. je Anbieter soll eine Liste mit allen Angeboten erstellt werden, welche die Nummer aus der Ortsliste enthält


            Das ist die XML - Datei (vereinfacht):
            Code:
            <test>
              <provider>
               <offer id="1" name="a">
                <location id="67890" name="def" />
                <location id="12345" name="abc" />
               </offer>
               <offer id="2" name="b">
                <location id="12345" name="abc" />
               </offer>
               <offer id="3" name="c">
                <location id="12345" name="abc" />
                <location id="67890" name="def" />
               </offer>
              </provider>
              <provider>
               <offer id="4" name="d">
                <location id="23456" name="xyz" />
                <location id="78901" name="uvw" />
               </offer>
               <offer id="5" name="e">
                <location id="78901" name="uvw" />
                <location id="67890" name="def" />
               </offer>
              </provider>
            </test>
            und so soll das Ergebnis aussehen:
            Code:
            Orte_Liste:  
                  1 def 
                  2 abc 
                 
                Angebot a: 1, 2   
                Angebot b: 2
                Angebot c: 2, 1  
              
                Orte_Liste:  
                  1 xyz 
                  2 uvw 
                  3 def
                 
                Angebot d: 1, 2
                Angebot e: 2, 3
            Da ich erst seit kurzem xsl verwende habe ich keine Ahnung, ob dies überhaupt möglich ist. Ich jedenfalls finde keine Lösung.

            Was denkt Ihr?

            Gruß
            Avallyn

            Comment


            • #7
              Mit einer reinen Gruppierung bin ich nicht auf das gesuchte Ergebnis gekommen, jedoch mit dem folgenden Versuch unter Verwendung von XSLT/XPath 2.0, speziell der Funktion fn:distinct-values():
              Code:
              <?xml version="1.0" encoding="UTF-8"?>
              <xsl:stylesheet version="2.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:fn="http://www.w3.org/2005/xpath-functions">
              
                <xsl:output method="text"/>
              
                <xsl:template match="test">
                  <xsl:apply-templates select="provider"/>
                </xsl:template>
              
                <xsl:template match="provider">Orte_Liste:<xsl:text>&#xA;</xsl:text>
                  <xsl:for-each select="fn:distinct-values(offer/location/@name)">
                    <xsl:text>  </xsl:text><xsl:value-of select="position()"/>
                    <xsl:text> </xsl:text><xsl:value-of select="."/><xsl:text>&#xA;</xsl:text>
                    <xsl:if test="position() = last()"><xsl:text>&#xA;</xsl:text></xsl:if>
                  </xsl:for-each>
              
                  <xsl:variable name="location_name">
                    <xsl:for-each select="fn:distinct-values(offer/location/@name)">
                      <xsl:value-of select="position()"/><xsl:value-of select="."/>
                    </xsl:for-each>
                  </xsl:variable>
              
                  <xsl:for-each select="offer">
                    <xsl:text>  </xsl:text>Angebot <xsl:value-of select="@name"/>
                    <xsl:text>: </xsl:text>
                    <xsl:for-each select="location">
                      <xsl:value-of select="substring(substring-before($location_name,@name),
                        string-length(substring-before($location_name,@name)))"/>
                      <xsl:if test="position() != last()"><xsl:text>, </xsl:text></xsl:if>
                      <xsl:if test="position() = last()"><xsl:text>&#xA;</xsl:text></xsl:if>
                    </xsl:for-each>
                    <xsl:if test="position() = last()"><xsl:text>&#xA;</xsl:text></xsl:if>
                  </xsl:for-each> 
              
                </xsl:template>
              
              </xsl:stylesheet>
              Ergebnis:
              Code:
              Orte_Liste:
                1 def
                2 abc
              
                Angebot a: 1, 2
                Angebot b: 2
                Angebot c: 2, 1
              
              Orte_Liste:
                1 xyz
                2 uvw
                3 def
              
                Angebot d: 1, 2
                Angebot e: 2, 3
              Für XSLT 1.0 müsste diese XPath-Funktion über rekursive xsl:call-template-Aufrufe nachgebildet werden, vielleicht liefert die XSLT FAQ einen nutzbaren Code. Dort gibt es auch eine Rubrik zur Gruppierung.

              Comment


              • #8
                Hallo Thomas,

                danke für Deine ausführliche Hilfe bei meinem Problem!

                Mit der Variablen
                Code:
                <xsl:variable name="varLocation" select="offer/location[not(@id = ../preceding-sibling::offer/location/@id)]" />
                und dem späteren durchlaufen dieser, habe ich das Problem lösen können.

                nochmals danke für Deine ausführliche Hilfe

                Grüße
                Avallyn

                Comment

                Working...
                X