bremic: automatischer Tabellenaufbau

Hallo,

ich möchte aus einer XML Datei eine Tabelle aufbauen.
In der XML-Datei stehen nur field-Elmente, die die zusätzlichen Attribute row und column besitzen. Ich möchte jetzt vor jedem field, bei dem Column = 1 ist eine neue Zeile beginnen (also <tr>) und nach jedem field mit column = 9 die Zeile beenden (also </tr>). Im Beispiel wie folgt:

<table border="1">
  <xsl:for-each select="field">
    xsl:choose
      <xsl:when test="./@column != 1 and ./@column != 9">
        <td>..........</td>
      </xsl:when>
      <xsl:when test="./@column = 1">
        <tr><td>..........</td>
      </xsl:when>
      <xsl:when test="./@column = 9">
       <td>..........</td></tr>
      </xsl:when>
    </xsl:choose>
  </xsl:for-each>
</table>

Jetzt meckert aber der Parser zu Recht herum, dass es sowohl ein nichtschliessendes </tr>-Element gibt (für den Fall column = 1), als auch eine nichtöffnendes <tr>-Tag (für den Fall column = 9).
Hat vielleicht jemand eine elegante funktionierende Lösung für das Problem.

Gruß,
Micahel

  1. Hi,

    verstehe ich das richtig, dass jede Zeile eine unterschiedliche Anzahl an Zellen haben kann? Gibt das überhaupt Sinn?

    Grüße - Frank

    1. Hi,

      verstehe ich das richtig, dass jede Zeile eine unterschiedliche Anzahl an Zellen haben kann? Gibt das überhaupt Sinn?

      Grüße - Frank

      Nein, eben nicht.
      Jede Zeile hat genau 9 Zellen. Das wird auch beim Erstellen der XML abgesichert. Es soll also mit jeder 1. Zelle(field) eine neue Zeile beginnen und mit jeder 9. Zelle (field) die Zeile enden.
      Zur Verdeutlichung mal hier noch ein Auszug aus der XML-Datei:

      ...
      <!-- beginn der ersten Zeile -->
      <field id="1" row="1" column="1">blabla</field>
      <field id="2" row="1" column="2">blabla</field>
      ...
      <!-- ende der ersten Zeile -->
      <field id="9" row="1" column="9">blabla</field>
      <!-- beginn der zweiten Zeile -->
      <field id="10" row="2" column="1">blabla</field>
      ...
      <!-- ende der zweiten Zeile -->
      <field id="18" row="2" column="9">blabla</field>
      ...

      Allgemein:
      <!-- beginn der ceil(n/9). Zeile -->
      <field id="n-8" row="ceil(n/9)" column="1">blabla</field>
      ...
      <!-- ende der ceil(n/9). Zeile -->
      <field id="n" row="ceil(n/9)" column="9">blabla</field>

      Das Problem Ansich liegt auch nicht an der Datenstruktur, sondern vielmehr am Parsen der xsl:when-Anweisungen mit den nichtschliessenden und öfnnenden <tr>-Elementen.

      1. Werden die "tr" vor und nach dem choose nicht akzeptiert?

        <table border="1">

        <xsl:for-each select="field">
           <tr>
            xsl:choose
              <xsl:when test="./@column != 1 and ./@column != 9">
                <td>..........</td>
              </xsl:when>
              <xsl:when test="./@column = 1">
                <td>..........</td>
              </xsl:when>
              <xsl:when test="./@column = 9">
               <td>..........</td>
              </xsl:when>
            </xsl:choose>
            </tr>
          </xsl:for-each>
        </table>

        1. Hi Frank!

          Deine vorgeschlagene würde um jedes Field Element ein (<tr><td>....</td></tr>){n} legen.

          Er will aber (*):
          (<tr>(<td>...</td>){9}</tr>){n}

          Auch nach außen (vor die for-each) ziehen bringt nix, da dann alle contents in einer tr stehen:
          <tr>(<td>...</td>){n}</tr>

          Meine Lösung tut das (*).

          Viele Grüsse,
          Richard.

          1. Hi Richard,

            ah jetzt ja! ;-)

            Da hast Du natürlich absolut Recht! Es muss erst eine Abfrage gemacht werden, ob ein Feld das Attribut "row" hat und darin verschachtelt dann der Aufbau der Zeile. Richtig?

            Schöne Grüße
            Frank

            1. Ein Feld hat immer das Attribut Row und Column. Eigentlich enthält das XML-Dokument schon eine formale Tabellenbeschreibung. Nur an deren (einfachstmöglicher :)) automatischer Darstellung im HTML tue ich mich im Moment schwer. Mit einigen wilden xsl:if Konstrukten, könnte ich das Problem bestimmt in den Griff bekommen, aber eigentlich war ich auf der Suche nach einer "schönen und einfachen" Lösung.
              Die Lösung von Richard werde ich mal testen, sieht mir aber eigentlich auch schon zu wild aus ;). Es ist halt ärgerlich, dass man die Validierung der <tr>-Elemente nicht auf das xsl:choose-Element beschränken kann und somit die den Teil der xsl:when-Anweisung anders behandelt.

              1. Hi Michael!

                Also, das Beispiel ist nicht auf meinem Mist gewachsen, sondern aus dem folgenden Artikel:
                http://www.ibm.com/developerworks/library/x-divel.html

                Ich denke, wenn du es tatsächlich einfacher &  besser hinbekommst, dann kannst du dir einen kleinen Preis abholen...
                P.S.: Im Link wird auch gezeigt, wie man es NICHT machen soll...

                Viele Grüsse,
                Richard

                1. Ich denke, wenn du es tatsächlich einfacher &  besser hinbekommst, dann kannst du dir einen kleinen Preis abholen...
                  P.S.: Im Link wird auch gezeigt, wie man es NICHT machen soll...

                  Na wenn das nichtmal nen Ansporn ist ;)

                  Danke für deine Mühen.

                  Liebe Grüße,
                  Michael

                2. Danke für den Link. Der beschreibt tatsächlich genau das Problem.

                  Gruß,
                  Michael

        2. Richard hat vollkommen recht.

          Bei deiner Variante bräuchte ich ja auch die ganzen when-Abfragen, da sie sich zu einem Ganzen <td></td> ergänzen würden. Somit erhalte ich nach deiner Variante:

          <tr>
            </ td>
          </tr>
          <tr>
            </ td>
          </tr>
          <tr>
            </ td>
          </tr>
          ...

          Was ich aber benötige ist:
          <tr>
            </ td></ td></ td>... (insgesamt 9 mal)
          </tr>
          <tr>
            </ td> (9 mal)
          </tr>
          ...

  2. Hi Micahel!

    Ich habe mal für ein ähnliches Problem folgende Lösung gefunden:

    ******************
    XML
    ******************
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <?xml-stylesheet type="text/xsl" href="./crossTab.xsl"?>
    <products>
       <name>WizzBang Ultra Word Processor</name>
       <description>More words per minute than the competition.</description>
       <price>$799.99</price>
       <name>Super WizzBang Calculator</name>
       <description>Cheap and reliable with power saving.</description>
       <price>$5.99</price>
       <name>WizzBang Safest Safe</name>
       <description>Choose the authentic WizzBang Safest Safe.</description>
       <price>$1,999.00</price>
    </products>

    *******************
    XSL
    *******************

    <?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="html"/>

    <xsl:template match="products">
       <html>
          <head><title>Product List</title></head>
          <body>
             <table>
                <tr><td>Name</td><td>Description</td><td>Price</td></tr>
                <xsl:apply-templates select="name"/>
             </table>
          </body>
       </html>
    </xsl:template>

    <xsl:template match="name">
       <tr>
          <td>xsl:apply-templates/</td>
          <xsl:apply-templates select="following-sibling::*[1]" mode="within"/>
       </tr>
    </xsl:template>

    <xsl:template match="*" mode="within">
       <xsl:apply-templates select="."/>
       <xsl:apply-templates select="following-sibling::*[1]" mode="within"/>
    </xsl:template>

    <xsl:template match="name" mode="within"/>

    <xsl:template match="description">
       <td>xsl:apply-templates/</td>
    </xsl:template>

    <xsl:template match="price">
       <td>xsl:apply-templates/</td>
    </xsl:template>

    </xsl:stylesheet>

    Das sollte sich anpassen lassen...

    Viele Grüsse,
    Richard

  3. Hellihello,

    wie sieht denn dein xml-dokument genau aus?

    Dank und Gruß,

    frankx

    --
    tryin to multitain  - Globus = Planet != Welt
    1. XML-Dokument

      Gruß,
      Michael

      1. Hellihello

        XML-Dokument

        Naja, ein XML-Dokument sieht anders aus (;-).

        Warum orientierst Du Dich für die Zeilen nicht am Attribut rows?

        Dank und Gruß,

        frankx

        --
        tryin to multitain  - Globus = Planet != Welt
        1. Hellihello

          XML-Dokument

          Naja, ein XML-Dokument sieht anders aus (;-).

          Es war ja auch nur ein Link zu dem Beitrag, wo einige Auszüge sowie eine Generalisierung des field-Elements aus dem Dokument standen.

          Warum orientierst Du Dich für die Zeilen nicht am Attribut rows?

          1. Weils beliebig viele Rows sein können, und ich nicht alle einzeln abfragen möchte.
          2. Änderts am Sachverhalt auch nichts, da dann auch wieder ein öffnendes <tr> in einer when-Abfrage steht und das schliessende </tr> in einer anderen.

          Aber Richard hat mir bereits eine Lösung geschickt, die wohl funktioniert, die ich aber noch anpassen muss.

          Danke und Gruß,
          Michael

          1. Hellihello

            Hellihello

            XML-Dokument

            Naja, ein XML-Dokument sieht anders aus (;-).

            Es war ja auch nur ein Link zu dem Beitrag, wo einige Auszüge sowie eine Generalisierung des field-Elements aus dem Dokument standen.

            Warum orientierst Du Dich für die Zeilen nicht am Attribut rows?

            1. Weils beliebig viele Rows sein können, und ich nicht alle einzeln abfragen möchte.
            2. Änderts am Sachverhalt auch nichts, da dann auch wieder ein öffnendes <tr> in einer when-Abfrage steht und das schliessende </tr> in einer anderen.

            Aber Richard hat mir bereits eine Lösung geschickt, die wohl funktioniert, die ich aber noch anpassen muss.

            Nun ja, die verlinkte Lösung fusst ja auf einer Struktur:

              
              
            <root>  
             <a>a1</a>  
             <b>b1</b>  
             <c>c1</c>  
             <a>a2</a>  
             <b>b2</b>  
             <c>b2</c>  
            </root>  
              
            
            

            während Du hast:

              
              
            <root>  
             <a b="1">a1</a>  
             <a b="1">b1</a>  
             <a b="1">c1</a>  
             <a b="2">a2</a>  
             <a b="2">b2</a>  
             <a b="2">c2</a>  
            </root>  
            
            

            Frage wäre vielleicht auch, ob Du das nur allein mit XSLT lösen musst. Denn der Artikel sagt ja:

            Unfortunately products.xml has a flat structure. More specifically, it lacks tags to group all the data pertaining to a given product. One can infer that a new name marks the beginning of a new product, but it's not explicit in the markup.

            Und Du hast noch eine flachere Struktur, was die Elemente angeht.

            Dank und Gruß,

            frankx

            --
            tryin to multitain  - Globus = Planet != Welt
            1. Hellihello

              Nun ja, die verlinkte Lösung fusst ja auf einer Struktur:

              <root>
              <a>a1</a>
              <b>b1</b>
              <c>c1</c>
              <a>a2</a>
              <b>b2</b>
              <c>b2</c>
              </root>

              
              >   
              > während Du hast:  
              > ~~~xml
                
              
              >   
              > <root>  
              >  <a b="1">a1</a>  
              >  <a b="1">b1</a>  
              >  <a b="1">c1</a>  
              >  <a b="2">a2</a>  
              >  <a b="2">b2</a>  
              >  <a b="2">c2</a>  
              > </root>  
              > 
              
              

              Frage wäre vielleicht auch, ob Du das nur allein mit XSLT lösen musst. Denn der Artikel sagt ja:

              Unfortunately products.xml has a flat structure. More specifically, it lacks tags to group all the data pertaining to a given product. One can infer that a new name marks the beginning of a new product, but it's not explicit in the markup.

              Und Du hast noch eine flachere Struktur, was die Elemente angeht.

              Zumal das verlinkte Beispiel darauf beruht, im Elementenbaum die Geschwister durchzugehen, bis das Element mit einem bestimmten Namen wieder auftaucht.

              Dank und Gruß,

              frankx

              --
              tryin to multitain  - Globus = Planet != Welt