Toon posts:

[XML/XLST] Recursie probleem (for-each)

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig met het maken van een XML bestand wat doormiddel van XSLT naar een mooie html opmaak getransformeerd moet worden, maar ik loop tegen wat problemen met de recursie aan.

Relevant XML bestand:
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
41
42
43
44
<clienten xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="clienten_schema.xsd">
    <client clientid="2" sofinummer="1002330AD">
        <naam>blub</naam>
        <geslacht>man</geslacht>
        <straat>dddddd</straat>
        <huisnummer huisnummer="333" />
        <postcode>3452NG</postcode>
        <woonplaats>loodrecht</woonplaats>
        <telefoon>0123456789</telefoon>
        <gebdatum>23-12-1976</gebdatum>
        <email>een.email@host.com</email>
        <rekeningen>
            <rekening reknummer="11234344">
                <saldo>-100.00</saldo>
                <maxcrediet>1000.00</maxcrediet>
                <rentepercentage>3</rentepercentage>
                <transacties>
                    <transactie>
                        <transactieid>1</transactieid>
                        <bedrag>100</bedrag>
                        <bijaf>af</bijaf>
                    </transactie>
                    <transactie>
                        <transactieid>5</transactieid>
                        <bedrag>500</bedrag>
                        <bijaf>bij</bijaf>
                    </transactie>
                </transacties>
            </rekening>
            <rekening reknummer="333345345">
                <saldo>1500.00</saldo>
                <maxcrediet>0.00</maxcrediet>
                <rentepercentage>5</rentepercentage>
                <transacties>
                    <transactie>
                        <transactieid>2</transactieid>
                        <bedrag>100</bedrag>
                        <bijaf>af</bijaf>
                    </transactie>
                </transacties>
            </rekening>
        </rekeningen>
    </client>
</clienten>


In het bijbehorende schema heb ik bepaald dat clienten 0 of meerdere client elementen bevat.
Het probleem ontstaat als ik met een for-eachloop door de rekeningen en transacties heen loop.
Omdat bij een client meerdere rekeningen horen en bij een rekening meerdere transacties lijkt een for-each loop een cartesisch product op te leveren van de mogelijkheden.
Bij tweede rekening in dit bestand krijg ik dus 2*1 transactie entries terwijl er maar 1 moet bestaan.
Ik hoop dat ik mijn probleem op deze manier goed verwoord heb.

Wat zou ik kunnen doen om dit te voorkomen?

Hier overigens een deel van het XSL bestand waar het probleem ontstaat.
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
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:template match="/clienten/client">
        <html>
            <head>
                <title></title>
            </head>
            <body>
                <table>
                    <tr><td>Naam: </td><td><xsl:value-of select="naam" /></td></tr>
                    <tr><td>Geslacht: </td><td><xsl:value-of select="geslacht" /></td></tr>
                    <tr><td>Straat: </td><td><xsl:value-of select="straat" /></td></tr>
                    <tr><td>Postcode: </td><td><xsl:value-of select="postcode" /></td></tr>
                    <tr><td>Woonplaats: </td><td><xsl:value-of select="woonplaats" /></td></tr>
                    <tr><td>Geboortedatum: </td><td><xsl:value-of select="gebdatum" /></td></tr>
                    <tr><td>Email: </td><td><xsl:value-of select="email" /></td></tr>
                </table>    
                Rekeningen:<br />
                
                <xsl:for-each select="/clienten/client/rekeningen/rekening">
                <p>
                    <table>
                        <tr><td>Rekeningnummer: </td><td><xsl:value-of select="@reknummer"/></td></tr>
                        <tr><td>Crediet (maximaal): </td><td><xsl:value-of select="maxcrediet"/></td></tr>
                        <tr><td>Rentepercentage: </td><td><xsl:value-of select="rentepercentage"/></td></tr>
                        <tr><td>Saldo: </td><xsl:if test="saldo &gt; 0"><td bgcolor="green"><xsl:value-of select="saldo" /></td></xsl:if>
                                                       <xsl:if test="saldo &lt; 0"><td bgcolor="red"><xsl:value-of select="saldo" /></td></xsl:if></tr>
                    </table>
                </p>
                </xsl:for-each>
                                </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

[ Voor 27% gewijzigd door Verwijderd op 17-10-2006 20:47 ]


Verwijderd

ik zou het opsplitsen in meerdere templates die je dan aanroept met apply-templates

dus een template voor client waar je de template voor rekening aanroept waar je de template voor transactie aaroept

Uit je xsl voorbeeld is het me trouwens onduidelijk wat je nu met die transacties wil

  • Gerco
  • Registratie: Mei 2000
  • Laatst online: 10-02 17:10

Gerco

Professional Newbie

Omdat bij een client meerdere rekeningen horen en bij een rekening meerdere transacties lijkt een for-each loop een cartesisch product op te leveren van de mogelijkheden.
Je krijgt zo inderdaad een carthesisch produkt van alle clienten en rekeningen, maar niet om de reden die jij denkt :) Je doet eigenlijk het volgende:

"Voor alle clienten, zoek alle rekeningen" van die client.

Als je nu in plaats van <xsl:for-each select="/clienten/client/rekeningen/rekening"> eens <xsl:for-each select="rekeningen/rekening"> zou gebruiken, werkte het opeens een stuk beter. Nog beter zou echter zoiets zijn:

XSLT:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<xsl:template match="client">
  Doe hier dingen per client

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

<xsl:template match="rekeningen">
  Rekeningen:
  <xsl:apply-templates/>
</xsl:template>

<xsl:template match="rekening">
  Doe hier dingen voor 1 rekening.
</xsl:template>


Op deze manier krijg je geen "Rekeningen:" te zien als de klant die niet heeft en kun je ook nog extra templates toevoegen voor het geval je bij die klant opeens ook kinderen of aandelen wil laten zien. Dan hoef je namelijk je "client" template niet aan te passen, alleen maar een template toe te voegen voor de kinderen of aandelen.

[ Voor 21% gewijzigd door Gerco op 18-10-2006 09:26 ]

- "Als ik zou willen dat je het begreep, legde ik het wel beter uit!" | All number systems are base 10!


Verwijderd

Gerco, you won :D 8)

De code van je XSL is fout.
Je roep binnen elke client alle rekeningen van elke client aan.

Oplossing:
verander <xsl:for-each select="/clienten/client/rekeningen/rekening">
in <xsl:for-each select="rekeningen/rekening">

XML:
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
<?xml version="1.0"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    
    <xsl:template match="/clienten/client">
        <html>
            <head>
                <title></title>
            </head>
            <body>
                <table>
                    <tr><td>Naam: </td><td><xsl:value-of select="naam" /></td></tr>
                    ............
                 </table>    
                Rekeningen:<br />
                
                <xsl:for-each select="rekeningen/rekening">
                <p>
                    <table>
                        <tr><td>Rekeningnummer: </td><td><xsl:value-of select="@reknummer"/></td></tr>
                        <tr><td>Crediet (maximaal): </td><td><xsl:value-of select="maxcrediet"/></td></tr>
                        <tr><td>Rentepercentage: </td><td><xsl:value-of select="rentepercentage"/></td></tr>
                        <tr><td>Saldo: </td><xsl:if test="saldo &gt; 0"><td bgcolor="green"><xsl:value-of select="saldo" /></td></xsl:if>
                                                       <xsl:if test="saldo &lt; 0"><td bgcolor="red"><xsl:value-of select="saldo" /></td></xsl:if></tr>
                    </table>
                </p>
                </xsl:for-each>
                                </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

Verwijderd

Topicstarter
Uit je xsl voorbeeld is het me trouwens onduidelijk wat je nu met die transacties wil
Heb ik ook niet aan het voorbeeld toegevoegd, dus daar heb je gelijk in :)
Als je nu in plaats van <xsl:for-each select="/clienten/client/rekeningen/rekening"> eens <xsl:for-each select="rekeningen/rekening"> zou gebruiken, werkte het opeens een stuk beter. Nog beter zou echter zoiets zijn:
Gerco, you won
Ik ben inderdaad heel erg geholpen met jullie antwoorden, ook al lag het meer voor de hand dan ik eigenlijk had gedacht.

Op het moment ben ik bezig de code om te zetten naar templates omdat dat toch een betere leesbaarheid oplevert.

Heel erg bedankt voor jullie input! O+