[XPath] een bepaalde node opvragen

Pagina: 1
Acties:
  • 200 views sinds 30-01-2008
  • Reageer

  • Rense Klinkenberg
  • Registratie: November 2000
  • Laatst online: 15-09 23:45
ok, stel ik heb de volgende XML:
code:
1
2
3
4
5
6
7
8
<list>
    <item>1</item>
    <item>2</item>
    <item>3</item>
    <item>4</item>
    <item>5</item>
    <item>6</item>
</list>

Nu wil ik bijv. de 3e item node opvragen.

In dit voorbeeld zou dat bijvoorbeeld kunnen met
code:
1
/list/item[text() = '3']

maar helaas bevat het straks niet mooi de op volgorde staande getalletjes.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Je kan simpel gebruiken:
code:
1
item[position() = 3]

Of als je de (te) afgekorte syntax wilt gebruiken:
code:
1
item[3]

Er staan een paar voorbeelden op: http://www.w3.org/TR/xpath

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


Verwijderd

mbravenboer: ... Of als je de (te) afgekorte syntax wilt gebruiken...
Hoezo te? :?

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Arien: Hoezo te? :?
Ik vind zelf in dit geval het aangeven van de functie postition wel duidelijk. De verkorte notatie lijkt natuurlijk wel erg op het gebruik in arrays, maar tussen de [ ... ] moet bij XPath gewoon een predicaat staan. Ik vind het wel duidelijk om aan te geven waarover je je predicaat laat gelden, in dit geval dus de positie :) . Ik ben ook een voorstander van het gebruik van text() op de plaatsen waar dit weggelaten mag worden. Gewoon voor de duidelijkheid...

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Rense Klinkenberg
  • Registratie: November 2000
  • Laatst online: 15-09 23:45
ok, gaan we het effe anders voorleggen. Het komt nl. uit een XSL probleem. Ik wil nl. de lijst over 2 kolommen verdelen. Als je de volgende code gebruikt, lukt dat:
code:
1
2
3
4
5
6
7
8
<xsl:template match="list/item">
    <xsl:if test="(position() mod 2) = '1'">
      <tr>
        <td><xsl:value-of select="." /></td>
        <td><xsl:value-of select="./following-sibling::*" /></td>
      </tr>
    </xsl:if>
</xsl:template>

maar dan komt het op de volgende manier te staan:
1 2
3 4

Wat ik eigenlijk wil is dat het
1 3
2 4
komt te staan.

Dus dacht ik:
code:
1
2
3
4
5
6
7
8
9
10
11
12
<xsl:template match="/news/item">
    <!-- Ga alleen verder als de huidige node voor de helft is, of als ie gelijk is aan de helft.-->
    <xsl:if test="(last() / 2) >= position()">
      <xsl:variable name="pos"><xsl:value-of select="position()" /></xsl:variable>
      <tr>
        <!-- Pak de huidige node -->
        <td><xsl:value-of select="." /></td>
        <!-- Pak de node die de helft verder is -->
        <td><xsl:value-of select=".[position() = ((last() /2) + $pos)" /></td>
      </tr>
    </xsl:if>
</xsl:template>

maar helaas lukt dat niet, omdat variabelen niet opnieuw ogen worden gedefinieerd.

Heeft er iemand een oplossing hiervoor?

Verwijderd

Neem eens 1 en helft+1, etc. ;)

edit: oeps dat doe je al... |:(

Kan je niet de oneven pakken voor links en dan following-sibling nemen voor rechts ofzo? :?

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Gemeen hoor, heb ik de oplossing gegeven gaat ie het moeilijker maken ;) .

De oplossing is vrij eenvoudig eigenlijk. Als je matched op een item kan je nooit meer controle uitvoeren op de volgorde van de items. Dat gaat dus niet goed...

Je moet dus een template maken voor list, en van daaruit de templates toepassen op de gewenste items. Voila: geen variabelen meer nodig ;) .

Voorbeeldje (ff snel)
code:
1
2
3
4
5
6
7
8
9
<table>
  <tr>
    <xsl:apply-templates select="item[(position() mod 2) = '1']"/>
  </tr>

  <tr>
    <xsl:apply-templates select="item[(position() mod 2) = '0']"/>
  </tr>
</table>

Dit is dus eigenlijk een hele makkelijke oplossing :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


Verwijderd

Ik heb nog zoveel te leren op XML / XSL(T) / XPath gebied, maar dit is echt heel gaaf spul, en de mogelijkheden lijken onbeperkt. :9~

edit:

Ja, zelfs ik val weleens uit mijn semi-profi rol en ben weleens off topic en ongeremd enthousiast. Hierbij mijn nederige excuses! :+ :P

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
MrX: maar dit is echt heel gaaf spul
:) Mee eens. XSLT is een prachtig instrument. Qua transformatie-taal is het niet superieur, maar het brengt transformaties wel op een hele makkelijke manier in de gewone wereld...
en de mogelijkheden lijken onbeperkt. :9~
Helaas klopt dat lijken ook wel weer... ;)

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Rense Klinkenberg
  • Registratie: November 2000
  • Laatst online: 15-09 23:45
Op donderdag 11 oktober 2001 13:08 schreef mbravenboer het volgende:
Gemeen hoor, heb ik de oplossing gegeven gaat ie het moeilijker maken ;)
Goed hè :P
Voorbeeldje (ff snel)
code:
1
2
3
4
5
6
7
8
9
<table>
  <tr>
    <xsl:apply-templates select="item[(position() mod 2) = '1']"/>
  </tr>

  <tr>
    <xsl:apply-templates select="item[(position() mod 2) = '0']"/>
  </tr>
</table>

Dit is dus eigenlijk een hele makkelijke oplossing :) .
Dan krijg ik:
1 3 5
2 4 6
Als ik 6 items heb, maar dat moet dan
1 4
2 5
3 6
zijn.

* Rense Klinkenberg heeft het weer moeilijker gemaakt :P

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
freak007 heeft het weer moeilijker gemaakt :( ;)
Allemachtig, dit lijkt wel bezigheids therapie ;) .[quote]
Dan krijg ik:
1 3 5
2 4 6
[/quote[
Vind ik ook best mooi hoor :+ ;)
Als ik 6 items heb, maar dat moet dan
1 4
2 5
3 6
zijn.
Uhme... das een lastige...

Schetjes voor een mogelijke oplossing:

1. s = aantal kinderen / 2
2. for-each select kinderen position = 0 - s
3. apply-templates op current + apply-templates op kind op position + 1/2 * aantal kinderen.


zoiets :?

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Rense Klinkenberg
  • Registratie: November 2000
  • Laatst online: 15-09 23:45
Op donderdag 11 oktober 2001 14:23 schreef mbravenboer het volgende:Allemachtig, dit lijkt wel bezigheids therapie ;)
heeft ie eindelijk eens een lastig XSL topic, is het weer iet goed ;)
Schetjes voor een mogelijke oplossing:

1. s = aantal kinderen / 2
2. for-each select kinderen position = 0 - s
3. apply-templates op current + apply-templates op kind op position + 1/2 * aantal kinderen.


zoiets :?
Jep, maar hoe schrijf ik dat in XSL, want stap 1 gaaat al mis :'(
code:
1
2
3
<xsl:template match="list">
    <xsl:value-of select="count('./item')" />
</xsl:template>

levert nl. 671088689 op en da's toch net iets meer dan de verwachte 4

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
freak007: heeft ie eindelijk eens een lastig XSL topic, is het weer iet goed ;)
hehe ;) .
Jep, maar hoe schrijf ik dat in XSL, want stap 1 gaaat al mis :'(
<code>
levert nl. 671088689 op en da's toch net iets meer dan de verwachte 4
Hum ik heb nu niet veel tijd en kan het ook niet zo uit m'n hoofd. Ik zal vanavond als ik terug ben (laat) ff kijken of ik wat kan maken.

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ik had nog ff een gaatje dus heb het nog ff in elkaar gezet...

XML file:
code:
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0"?>

<list>
    <item>A</item>
    <item>B</item>
    <item>C</item>
    <item>D</item>
    <item>E</item>
    <item>F</item>
</list>

Stylesheet:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?xml version="1.0"?>

<xsl:stylesheet version="1.0"
                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns="http://www.w3.org/1999/xhtml">

    <xsl:output method="xml" indent="yes"
                doctype-public="-//W3C//DTD XHTML 1.0 Transitional//EN"
                doctype-system="DTD/xhtml1-transitional.dtd"/>

    <xsl:template match="/">
        <html xml:lang="en" lang="en">
            <head>
                <title>Tricky table example</title>
            </head>

            <body>
                <xsl:apply-templates/>
            </body>
        </html>
    </xsl:template>

    <xsl:template match="list">
        <xsl:variable name="rowcount" select="ceiling(count(item) div 2)"/>
        <table>
            <xsl:for-each select="item[position() &lt;= $rowcount]">
                <tr>
                    <td>
                        <xsl:apply-templates/>
                    </td>
                    <td>
                        <xsl:variable name="second" select="position() + $rowcount"/>

                        <xsl:apply-templates select="/list/item[position() = $second]"/> 
                    </td>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>
</xsl:stylesheet>

Output:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
    <head>
        <title>Tricky table example</title>
    </head>

    <body>

        <table>
            <tr>
                <td>A</td>
                <td>D</td>
            </tr>
            <tr>
                <td>B</td>
                <td>E</td>
            </tr>
            <tr>
                <td>C</td>
                <td>F</td>
            </tr>
        </table>
    </body>
</html>

Viel best mee he? :) .

Bij oneven aantallen:
code:
1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0"?>

<list>
    <item>A</item>
    <item>B</item>
    <item>C</item>
    <item>D</item>
    <item>E</item>
    <item>F</item>
    <item>G</item>
</list>

Doetie het keurig naar:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
    <head>
        <title>Tricky table example</title>
    </head>
    <body>
        <table>
            <tr>
                <td>A</td>
                <td>E</td>
            </tr>
            <tr>
                <td>B</td>
                <td>F</td>
            </tr>
            <tr>
                <td>C</td>
                <td>G</td>
            </tr>
            <tr>
                <td>D</td>
                <td />
            </tr>
        </table>
    </body>
</html>

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Die td kan btw misschien beter in een template voor item... ;)

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Is het een beetje duidelijk wat ik hier doe of is het teveel slikken?

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Rense Klinkenberg
  • Registratie: November 2000
  • Laatst online: 15-09 23:45
Op vrijdag 12 oktober 2001 00:18 schreef mbravenboer het volgende:
Is het een beetje duidelijk wat ik hier doe of is het teveel slikken?
'k had er nog effe geen tijd voor gehad om er weer naar te kijken, maar dat zal ik zo effe doen.

Een ander bijkomend probleem is trouwens dat hetzelfde stuk enkele keren voorkomt op de pagina en variabele zetten dus waarschijnlijk niet goed zal gaan, maar misschien dat ik dat andeers kan oplossen.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
freak007: Een ander bijkomend probleem is trouwens dat hetzelfde stuk enkele keren voorkomt op de pagina en variabele zetten dus waarschijnlijk niet goed zal gaan, maar misschien dat ik dat andeers kan oplossen.
Die variablen worden slechts gebruikt om de code duidelijk te houden, Ik weet he trouwens niet zeker, maar die variabelen hebben toch een lokale scope? Dan kan dat toch geen problemen opleveren?

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Rense Klinkenberg
  • Registratie: November 2000
  • Laatst online: 15-09 23:45
Op vrijdag 12 oktober 2001 09:37 schreef mbravenboer het volgende:
Die variablen worden slechts gebruikt om de code duidelijk te houden, Ik weet he trouwens niet zeker, maar die variabelen hebben toch een lokale scope? Dan kan dat toch geen problemen opleveren?
Klopt idd. als een bus. Als de template opnieuw wordt opgevraagd, bestaan de vars niet meer uit de vorige oproep.

Ik heb een stukje XSL iets aangepast:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    <xsl:template match="list">
      <xsl:variable name="list_id" select="@id" />
        <xsl:variable name="rowcount" select="ceiling(count(item) div 2)"/>
        <table>
            <xsl:for-each select="item[position() &lt;= $rowcount]">
                <tr>
                    <td>
                        <xsl:apply-templates/>
                    </td>
                    <td>
                        <xsl:variable name="second" select="position() + $rowcount"/>
                
                        <xsl:apply-templates select="/page/list[@id = $list_id]/item[position() = $second]"/> 
                    </td>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>

Hierdoor moet je de XML ook iets aanpassen:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?xml version="1.0" encoding="UTF-8" ?>
<page>
<list id="1">
    <item>1</item>
    <item>2</item>
    <item>3</item>
    <item>4</item>
</list>
<list id="2">
    <item>1</item>
    <item>2</item>
    <item>3</item>
    <item>4</item>
    <item>5</item>
    <item>6</item>
    <item>7</item>
</list>
</page>

Maar dan werkt het ook perfect voor verschillende lijsten.

* Rense Klinkenberg gaat het nu implementeren en dankt mbravenboer

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
freak007: Klopt idd. als een bus. Als de template opnieuw wordt opgevraagd, bestaan de vars niet meer uit de vorige oproep.
Gelukkig maar, had het erg lelijk gevonden als dat wel het geval was :) .
Maar dan werkt het ook perfect voor verschillende lijsten.
Had daar inderdaad wat ranzigs gedaan ;) . Je kan het trouwens eigenlijk nog beter gewoon relatief maken, dat moet toch ook werken? Die list ids zijn ook niet echt bijzonder fraai natuurlijk ;)
* mbravenboer gaat het nu implementeren en dankt mbravenboer
Graag gedaan, was wel een leuk probleem :) . Jammer dat het vrij complex was, maar dat is eigenlijk ook wel weer logisch. Het is in ieder geval mogelijk :) .

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Rense Klinkenberg
  • Registratie: November 2000
  • Laatst online: 15-09 23:45
Op vrijdag 12 oktober 2001 10:00 schreef mbravenboer het volgende:
Had daar inderdaad wat ranzigs gedaan ;) . Je kan het trouwens eigenlijk nog beter gewoon relatief maken, dat moet toch ook werken? Die list ids zijn ook niet echt bijzonder fraai natuurlijk ;)
Ja, dat bedacht ik me ook net ja, maar waar ik het op moet toepasen heeft elke list een id, dus kan dit ook perfect.

  • mbravenboer
  • Registratie: Januari 2000
  • Laatst online: 06-11-2025
Ok, ik heb nog ff getest hoe het zat met die eerte apply-templates, want die werd denk ik alleen toegepast op de text van item. De tweede ook op item zelf... Das verwarrend :) .

Daarom kleine verbetering (+ relatief)
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
    <xsl:template match="list">
        <xsl:variable name="rowcount" select="ceiling(count(item) div 2)"/>
        <xsl:value-of select="$rowcount"/>
        <table>
            <xsl:for-each select="item[position() &lt;= $rowcount]">
                <tr>
                    <xsl:apply-templates select="."/>

                    <xsl:variable name="second" select="position() + $rowcount"/>
                    <xsl:apply-templates select="../item[position() = $second]"/> 
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>

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

Blog, Stratego/XT: Program Transformation, SDF: Syntax Definition, Nix: Software Deployment


  • Rense Klinkenberg
  • Registratie: November 2000
  • Laatst online: 15-09 23:45
Op vrijdag 12 oktober 2001 14:36 had mbravenboer het nog steeds niet opgegeven:
Als je die code ziet, lijkt 't allemaal best makkelijk, omdat het maar een paar regeltjes zijn :P
Pagina: 1