Pfadprobleme bei When-Abfrage
TorstenTKH
- xsl
0 Olaf Schneider0 TorstenTKH0 Thomas J.S.
0 TorstenTKH
Hallo,
ich habe eine XML-Datei folgender Art
<data>
<liste>
<zeile>
<farben_id>4</farben_id>
<farbe>blau</farbe>
</zeile>
...(mehrere Zeilen)
<grid>
<row>
<product_id>1</product_id>
<name>Santa Costume </name>
<price>14.99</price>
<on_promotion>0</on_promotion>
<farbenId>1</farbenId>
</row>
... (mehrere rows)
</grid>
<data>
ich möchte jetzt über eine xslt-Datei ein HTML-Select-Feld mit den Farben als Option-Felder erstellen. Dieses funktioniert soweit. Mein Problem ist, dass meine when-Abfrage zur Vorbelegung (<option selected>) der Farbe aus data/grid/row nicht das gewünschte Ergebnis liefert.
Hier mein xslt-code:
<xsl:element name="select">
<xsl:attribute name="disabled">true</xsl:attribute>
<xsl:for-each select="../../liste/zeile">
<xsl:element name="option">
<xsl:value-of select="farbe"></xsl:value-of>
xsl:choose
<xsl:when test="farben_id = 3">
<xsl:attribute name="selected">true</xsl:attribute>
</xsl:when>
</xsl:choose>
</xsl:element>
</xsl:for-each>
</xsl:element>
"farben_id=3" ist nur ein Test, der immer das 3. Element selektieren soll.
ausprobiert habe ich hier:
Das Attribut selected habe ich hier im Beispiel auf true. Ausprobiert habe ich auch selected.
Mir ist schon klar, dass englisch und deutsch hier durcheinander gehen und somit der Stil schlecht ist. Es geht nur um einen "schnell und schmutzig Test", wie ich ein DropdownFeld über dieses Konstrukt realisieren kann.
Wem die Daten bekannt vorkommen:
Ich versuche momentan das Ajax-Grid Skript aus "AJAX and PHP: Building Responsive Web Applications" um besagtes Dropdown zu erweitern, damit ich danach etwas ähnliches in einem eigenen Projekt realisieren kann.
Danke für eure Hilfe
Torsten
Hallo,
wenn ich es recht sehe, gibt es beliebig viele Zeilen, über die Du mit xsl:for-each iterierst, aber genau nur ein grid/row. Dann könnte Dir
helfen. farben_id ist dann relativ zum XPath im for-each-select-Atribut und /data/grid/row/farbenId beginnt mit einem Slash, ist also absolut.
(ungetestet)
Gruß
Olaf
P.S.: Warum schreibst Du mal farbenId und mal farben_id. Ich würde mich für eine Art entscheiden.
Hallo Olaf,
farben_ID kommt aus einer SQL-Tabelle, in der alle möglichen Farben gesammelt sind. Diese Farben sind mit ihren IDs in data/liste/zeile gespeichert und werden über die for-each-Schleife eingelesen.
Innerhalb der for-each-Schleife soll mit dem Eintrag farbenId aus der Produkte-Tabelle verglichen werden. Die SQL-Produkttabelle füttert somit die grid/row. Es handelt sich also um eine 1:n-Beziehung. Sind die IDs gleich soll diese Option vorausgwewählt sein.
Mein Grundgedanke war auch, dass farben_Id durch die for-each-Schleife keine Pfadangabe braucht und farbenId einen absoluten Pfad benötigt, aber der Vergleich funktioniert wie beschrieben leider nicht.
Dass die IDs unterschiedlich lauten, ist bei mehreren Versuchen so entstanden, da ich mir nicht sicher war, ob ich in verschiedenen Pfaden gleiche Tags verwenden kann. (Das scheint ja wohl nicht mein Problem zu sein)
Gruß
Torsten
Hallo,
farben_ID kommt aus einer SQL-Tabelle, in der alle möglichen Farben gesammelt sind. Diese Farben sind mit ihren IDs in data/liste/zeile gespeichert und werden über die for-each-Schleife eingelesen.
Innerhalb der for-each-Schleife soll mit dem Eintrag farbenId aus der Produkte-Tabelle verglichen werden. Die SQL-Produkttabelle füttert somit die grid/row. Es handelt sich also um eine 1:n-Beziehung.
Das heisst zu einer Zeile können mehrere Rows passen?
Sind die IDs gleich soll diese Option vorausgwewählt sein.
Tja, aber welche IDs? Was ist wenn mehrere Rows die gleiche FarbenID haben?
Du willst ja nur eine option vorselektieren: was soll passieren wenn aber sowohl bei den Zeilen als auch in den Rows z.B. die FarbenID 4 _und_ 5 vorkommt?
Mein Grundgedanke war auch, dass farben_Id durch die for-each-Schleife keine Pfadangabe braucht
Das ist fast korrekt, "farben_Id" ist ja schon eine Pfadangabe, aber mehr braucht es in der Tat im for-each nicht (und for-each ist keine Schleife im XSLT).
und farbenId einen absoluten Pfad benötigt,
Nicht notwendiger Weise, aber mir ist die Aufbau deines XMLs aus dem kleinen Beispiel nicht so ersichtlich, dass ich darauf konkret antworten könnte.
Grüße
Thomas
Hallo Thomas,
ich probiere es mal etwas ausführlicher.
Ich habe eine Produkte-Tabelle, wo jedes Produkt verschiedene Eigenschaften zugeordnet bekommt. Eine dieser Eigenschaften ist die Farbe. Nach den Normalitätsregeln, da natürlich beliebig viele Produkte die gleiche Farbe haben können, habe ich ich hier eine zweite Tabelle angelegt, in der die Farben abgelegt sind. Ein Produkt der Produkttabelle hat genau eine Farbe. Ein Produkt soll nur einmal in der Produkttabelle auftauchen.
Über php erstelle ich mir eine xml-Datei, die zunächst in data/liste/zeile die Farben mit ihren IDs (farben_id) ablegt.
In die gleiche Datei schreibe ich anschließend meine Produkttabelle mit dem Pfad data/grid/row. Die Eigenschaft Farbe wird hier über farbenId festgelegt.
Weiter unten habe ich die Listings etwas längeren eingepflegt.
Ich glaube ich beginne zu verstehen, wo mein Problem liegt.
Der absolute Pfad, den ich für farbenId angebe, weiss wahrscheinlich nicht an welcher Position ich im XML-Dokument bin. Dennoch sollte dann die Abfrage funktionieren, wenn ich einen festen Zahlenwert in der When-Abfrage eingebe.
Falls jemand eine andere Lösung in xslt für das Problem weiss oder eine andere Struktur für die XML wäre ich dankbar.
Das zu lösende Problem ist also, dass das Dropdownmenü alle Farben aus data/liste/zeile beinhalten soll (funktioniert soweit) und den identischen Wert des entsprechenden Produktes aus data/grid/row/farbenId vorselektieren soll.
Ich hoffe, dass das Problem jetzt etwas klarer ist.
Vielen Dank für eure Hilfe.
Grüße
Torsten
XML:
<data>
<liste>
<zeile>
<farben_id>4</farben_id>
<farbe>blau</farbe>
</zeile>
<zeile>
<farben_id>3</farben_id>
<farbe>gelb</farbe>
</zeile>
...weitere Farben
<zeile>
<farben_id>6</farben_id>
<farbe>gruen</farbe>
</zeile>
</liste>
<grid>
<row>
<product_id>1</product_id>
<name>Santa Costume </name>
<price>14.99</price>
<on_promotion>0</on_promotion>
<farbenId>3</farbenId>
</row>
<row>
<product_id>2</product_id>
<name>Medieval Lady</name>
<price>49.99</price>
<on_promotion>1</on_promotion>
<farbenId>3</farbenId>
</row>
...weitere Produkteinträge
<row>
<product_id>3</product_id>
<name>Caveman geändert</name>
<price>12.99</price>
<on_promotion>0</on_promotion>
<farbenId>4</farbenId>
</row>
</grid>
</data>
XSLT:
<table class="list">
<tr>
<th class="th1">ID</th>
<th class="th2">Name</th>
<th class="th3">Price</th>
<th class="th4">Promo</th>
<th class="th5">Aktion</th>
<th class="th6">Color</th>
</tr>
<xsl:for-each select="data/grid/row">
<xsl:element name="tr">
<xsl:attribute name="id">
<xsl:value-of select="product_id" />
</xsl:attribute>
<td><xsl:value-of select="product_id" /></td>
<td><xsl:value-of select="name" /> </td>
<td><xsl:value-of select="price" /></td>
<td>
xsl:choose
<xsl:when test="on_promotion > 0">
<input type="checkbox" name="on_promotion"
disabled="disabled" checked="checked"/>
</xsl:when>
xsl:otherwise
<input type="checkbox" name="on_promotion"
disabled="disabled"/>
</xsl:otherwise>
</xsl:choose>
</td>
<td>
<xsl:element name="a">
<xsl:attribute name = "href">#</xsl:attribute>
<xsl:attribute name = "onclick">
editId(<xsl:value-of select="product_id" />, true)
</xsl:attribute>
Edit
</xsl:element>
</td>
<td>
<xsl:element name="select">
<xsl:attribute name="disabled">true</xsl:attribute>
<xsl:for-each select="../../liste/zeile">
<xsl:element name="option">
<xsl:value-of select="farbe"></xsl:value-of>
xsl:choose
<xsl:when test="farben_id = /data/grid/row/farbenId">
<xsl:attribute name="selected">selected</xsl:attribute>
</xsl:when>
</xsl:choose>
</xsl:element>
</xsl:for-each>
</xsl:element>
</td>
</xsl:element>
</xsl:for-each>
</table>
Hallo,
Weiter unten habe ich die Listings etwas längeren eingepflegt.
Das war wirklich hilfreich, damit geht es einfach.
<xsl:for-each select="data/grid/row">
<xsl:variable name="frabe" select="farbenId" />
<xsl:element name="tr">
<xsl:attribute name="id">
<xsl:value-of select="product_id" />
</xsl:attribute>
(das kannst du abkürzen: <tr id="{product_id}">, auch dann bei anderen Elementen)
<xsl:element name="select">
<xsl:attribute name="disabled">true</xsl:attribute>
<xsl:for-each select="../../liste/zeile">
<xsl:element name="option">
<xsl:value-of select="farbe"></xsl:value-of>
xsl:choose
<xsl:when test="farben_id = $farbe">
<xsl:attribute name="selected">selected</xsl:attribute>
</xsl:when>
</xsl:choose>
Hier reicht aber eigentlich auch nur ein <xsl:if test="farben_id = $farbe"> statt when.
Grüße
Thomas
Hallo Thomas,
im nachhinein kann ich Dir nur zustimmen: war doch einfach.
Daraus ergibt sich, dass Deine Lösung tatsächlich funktioniert.
Rein interessehalber habe ich aber noch eine Frage:
Du hattest in einem früheren Post erwähnt, dass man for-each nicht als Schleife betrachten kann. Das ist mir nicht ganz klar.
Letztendlich passiert doch nichts anderes als bei einer Schleife.
$farbe wird z.B. bei jedem Durchlauf ein neuer Wert zugewiesen.
Tausend Dank.
Vielleicht kann ich ja auch mal die ein oder andere Frage hier beantworten.
Gruß
Torsten
Hallo,
Rein interessehalber habe ich aber noch eine Frage:
Du hattest in einem früheren Post erwähnt, dass man for-each nicht als Schleife betrachten kann. Das ist mir nicht ganz klar.
Letztendlich passiert doch nichts anderes als bei einer Schleife.
$farbe wird z.B. bei jedem Durchlauf ein neuer Wert zugewiesen.
Man mag for-each als Schleife betrachten, dennoch ist es keine. Diese irrtümlicher Betrachtungsweise führt zu vielen "typischen" Fehler, die man eben macht, weil man denkt, man befände sich in einer Schleife.
Ganz einfacher test:
<data>
<elem>a</elem>
<elem>b</elem>
<elem>c</elem>
<elem>d</elem>
<elem>e</elem>
</data>
<xsl:template match="/data">
<xsl:variable name="count" select="0" />
<xsl:for-each select="elem">
<elem>
<xsl:value-of select="." />
<xsl:value-of select="$count + 1" />
</elem>
</xsl:for-each>
</xsl:template>
"count" wird immer eins sein.
for-each iteriert nicht über die Konten, viel mehr ist for-each selbst ein Template: es werden für jeden Knoten auf die es zutrifft die Anweisungen die in ihm stehen neu ausgeführt. D.h. dieses Template wird (wie andere Templates auch) für jedes Element neu instanziiert.
Versuche beim obigen Biespiel ein: <xsl:value-of select="count(.)" /> im for-each. Das Ergebnis wird auch wieder immer 1 sein.
$farbe wird nicht bei jedem Durchlauf ein neuer Wert zugewiesen, denn der "vorige Durchlauf" weiss nichts von diesem Wert, vor allem nicht weil aus der Sicht vom for-each keinen "voriger Durchlauf" gibt. Variablen im XSLT können auch nicht geendert werden, man kann sie quasi als Konstanten betrachten.
In unserem Fall wird die Variable also für jedes Element neu erzeugt und wenn die Anweisungen im for-each alle ausgeführt sind, endet auch der Sichtbarkeitsbereich der Variable.
Ich hoffe das hilft ein wenig zum Verständnis.
Grüße
Thomas
Das Problem hat sich teilweise gelöst.
Durch das Vertauschen der choose-Anweisung mit der value-of select="farbe" funktioniert jetzt die Wenn-Abfrage, wenn ich farben_id= fester Zahlenwert setze.
Die Abfrage "farben_id = /data/grid/row/farbenId" liefert mir nur die Einstellung für den ersten Treffer in /data/grid/row.
Wie kann ich also farben_id mit der passenden farbenId aus dem aktuellen Produkt vergleichen? Ich brauche zuzüglich zu der Pfadangabe, die aktuelle Position im äußeren "for-each"
<xsl:for-each select="data/grid/row">
<xsl:element name="tr">
<td>...</td>
<td>
<xsl:element name="select">
<xsl:for-each select="/data/liste/zeile">
<xsl:element name="option">
xsl:choose
<xsl:when test="farben_id = /data/grid/row/farbenId">
<xsl:attribute name="selected">selected</xsl:attribute>
</xsl:when>
</xsl:choose>
<xsl:value-of select="farbe"></xsl:value-of>
</xsl:element>
</xsl:for-each>
</xsl:element>
</td>
<td>...</td>
</xsl:element>
</xsl:for-each>