XSLT Funktion für Anzahl Nodes

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

  • XSLT Funktion für Anzahl Nodes

    Hallo,
    ich arbeite mit xslt und brauche eure Hilfe bei einem Problem!

    Folgende xml Datei wird untersucht:

    Quellcode

    1. <?xml version="1.0"? encoding="UTF-8">
    2. <root>
    3. <scroll>
    4. <column>
    5. <row>
    6. <image></image>
    7. </row>
    8. <row>
    9. <content></content>
    10. </row>
    11. </column>
    12. <column>
    13. <row>
    14. <image></image>
    15. </row>
    16. <row>
    17. <content></content>
    18. </row>
    19. <row>
    20. <image></image>
    21. </row>
    22. </column>
    23. <column>
    24. <row>
    25. <image></image>
    26. </row>
    27. <row>
    28. <image></image>
    29. </row>
    30. <row>
    31. <content></content>
    32. </row>
    33. </column>
    34. </scroll>
    35. </root>
    Alles anzeigen


    Ich möchte mich an beliebiger Stelle im xml im node "row" befinden und bestimmen können, wie hoch die Anzahl nodes "row" pro Elternnode column maximal sein wird und wie hoch sie im nächstfolgenden Nachbarelement ist.
    Am besten wäre es im template von row kann aber auch ausserhalb sein falls notwendig. Das führt mich dann zur 2.Frage wie ich den ermittelten Wert in andere <xsl:templates> übergeben bzw. ob globales Zugreifen auf die Variable möglich ist.

    meine bisherigen versuche zum testen ob der rückgabe wert wenigstens eine sinnvolle zahl enthält geben mir immer nur 0 zurück.

    :shock:

    Quellcode

    1. <xslt:apply-templates select="row">
    2. <xsl:value-of select="count(parent::column/following-sibling::child::row)"/>
    3. </xslt:apply-templates>


    EDIT: sehe grad Formatierung entfernt die Absätze ich hoff es ist trotzdem lesbar
    //EDIT by d0nut: Syntax Highlighting geadded
  • Wenn ich das richtig verstehe, klingt das ziemlich strange.... Dann solltest du dir besser nochmal Gedanken über die Struktur machen. Warum soll denn jeder einzelne Node seinem Parent mitteilen können wie es sich zu verhalten hat.
    Das einzusetzen hat doch sowieso nur 1x Sinn und dann könntest du es ja auch ins Eltern-Element stecken.

    Habe ich es überhaupt richtig verstanden.

    Du definierst in irgendeinem Node ein Limit...

    Quellcode

    1. <root>
    2. <scroll>
    3. <column>
    4. <row>
    5. <image limit="5"></image>
    6. </row>


    Und nun darf es über image (also in row) nur maximal 4 weitere row Einträge geben?
  • Hi,

    sorry aber wahrscheinlich habe ich meine Frage zu komplex formuliert.
    Ich versuche immer soviel Information wie möglich einzubauen so dass es manchmal unübersichtlich wird.

    Zur Struktur: die ist so vorgegeben und lässt sich leider nicht mehr ändern.

    Zu dem Problem: ich möchte aus den nodes columns / row eine HTML table bauen.
    "column" entspricht "tr", "row" entspricht td (-> whyever)
    Da die 1. column meist! (nicht immer) nur die Überschrift ( + zus. Grafik) enthält will ich prüfen wieviel td in der 1. tr generiert werden und dies mit der max. anzahl td im dokument vergleichen und ggf (if first < max) ein colspan setzen damit die allgemein Tabellenformatierung erhalten bleibt.

    Ich hoffe damit ist das Problem besser zu verstehen.
  • Mit einem konkreten Problem macht das doch viel mehr Sinn ;)

    Am besten du suchst dir erstmal das Maxmimum an Spalten:

    Quellcode

    1. <xsl:variable name="maximum">
    2. <xsl:for-each select="//scroll/column">
    3. <xsl:sort select="count(row)" order="descending" />
    4. <xsl:if test="position()=1">
    5. <xsl:value-of select="count(row)" />
    6. </xsl:if>
    7. </xsl:for-each>
    8. </xsl:variable>


    Wenn du das vorher weißt, kannst du dann die Überprüfung jeweils an letzter Position machen und dort ein colspan einfügen:

    Quellcode

    1. <xsl:element name="table">
    2. <xsl:attribute name="border">1</xsl:attribute>
    3. <xsl:for-each select="//scroll/column">
    4. <xsl:element name="tr">
    5. <xsl:for-each select="row">
    6. <xsl:element name="td">
    7. <xsl:value-of select="." />
    8. <xsl:if test="position()=last()">
    9. <xsl:if test="position() &lt; $maximum">
    10. <xsl:attribute name="colspan">2</xsl:attribute>
    11. </xsl:if>
    12. </xsl:if>
    13. </xsl:element>
    14. </xsl:for-each>
    15. </xsl:element>
    16. </xsl:for-each>
    17. </xsl:element>
    Alles anzeigen


    Auch wenn die Bedingung trifft.. irgendwie hat der colspan keine Auswirkungen... es ist aber sehr, sehr nahe an der Lösung.
  • wow,

    ersten mal Vielen Dank für das template zum rausfinden der Maximal Zellenanzahl.

    Das kann ich gut gebrauchen. Ich hab nach einigem hin und her mal deinen code 1:1 in mein xsl eingebaut.

    Das eine neue table erzeugt wird kommt mir erstmal ganz recht.

    Ich bekomm jetzt aber immer folgende fehlermeldung:


    Warning: process() [function.process]: runtime error: file xslt/NaviDaten.xsl line 163 element attribute in /mnt/workspace/xslt-test/trunk/index_html.php on line 135

    Warning: process() [function.process]: xsl:attribute: Cannot add attributes to an element if children have been already added to the element. in /mnt/workspace/xslt-test/trunk/index_html.php on line 135



    hab das ganze in einem template name="test" was einfach per call-template aufgerufen wird hatte element name="table" direkt mit table ersetzt da ich dachte es würde einen unterschied machen...

    Quellcode

    1. <xsl:template name="test">
    2. <xsl:variable name="maximum">
    3. <xsl:for-each select="//scroll/column">
    4. <xsl:sort select="count(row)" order="descending" />
    5. <xsl:if test="position()=1">
    6. <xsl:value-of select="count(row)" />
    7. </xsl:if>
    8. </xsl:for-each>
    9. </xsl:variable>
    10. <table cellpadding="0" cellspacing="0" border="1">
    11. <xsl:for-each select="//scroll/column">
    12. <xsl:element name="tr">
    13. <xsl:for-each select="row">
    14. <xsl:element name="td">
    15. <xsl:value-of select="." />
    16. <xsl:if test="position()=last()">
    17. <xsl:if test="position() &lt; $maximum">
    18. <xsl:attribute name="colspan">2</xsl:attribute> -> Zeile 163
    19. </xsl:if>
    20. </xsl:if>
    21. </xsl:element>
    22. </xsl:for-each>
    23. </xsl:element>
    24. </xsl:for-each>
    25. </table>
    26. </xsl:template>
    Alles anzeigen
  • Warning: process() [function.process]: xsl:attribute: Cannot add attributes to an element if children have been already added to the element

    ich teste derzeit nur mit dem Firefox (Keine Fehlertexte). Die Fehlermeldung erklärts..

    Das <xsl:value-of select="." /> darf erst nach der colspan Definition aufgerufen werden.

    Quellcode

    1. <xsl:element name="td">
    2. <xsl:if test="position()=last()">
    3. <xsl:if test="position() &lt; $maximum">
    4. <xsl:attribute name="colspan"><xsl:value-of select="$maximum - position() + 1"/></xsl:attribute>
    5. </xsl:if>
    6. </xsl:if>
    7. <xsl:value-of select="." />
    8. </xsl:element>


    Und schon klappt der Code. Habe auch gleich die Berechnung des colspans eingefügt ;)
  • Vielen Dank für den code.
    Hab sonst immer nur mit apply-templates gearbeitet.
    Foreach werd jetzt in Zukunft mehr benutzen ist wesentlich kompakter zu halten.

    Die Tabelle wird jetzt astrein formatiert :D
    Ich werd jetzt erstmal mit css bzw. div blöcken für die Darstellung experimentieren da ich noch einige andere Formatierungen wie Abstand zwischen 2 colnode by bedingung following::row/@type=fmt_headline_2 und x,y,width,height pro column/row einbauen muss.