[XSLT] Template matchen op een variabele

Pagina: 1
Acties:

  • Captain N
  • Registratie: Maart 2001
  • Laatst online: 10-05-2024

Captain N

Back in NL. T_T

Topicstarter
Ik heb een Xpath query opgslagen in een variabele genaamd xpath. Nu wil ik een template maken die matched op die Xpath query. Maar de volgende code geeft de error "cause: javax.xml.transform.TransformerException: A node test that matches either NCName:* or QName was expected".

code:
1
2
3
<xsl:template match="{$xpath}">
bladiebla
</xsl:template>


Ik heb wat zitten zoeken, en kwam via Google tegen dat variabelen niet gebruikt kunnen worden in het match attribuut van template. Als ik de inhoud van $xpath gewoon er met de hand neer zet werkt het inderdaad wel gewoon prima. Is er een manier om toch een variabele te kunnen gebruiken?

[ Voor 8% gewijzigd door Captain N op 16-06-2005 15:22 ]

Specs: NES | M82 | (T)FC | SNES | BS-X | VB | N64 | 64DD | NGC | Q | Q GBP | G&Ws | GB(L) | GB(A) (SP) | GBM | DS(L) | Wii
Mijn foto's op Flickr.


  • djc
  • Registratie: December 2001
  • Laatst online: 08-09-2025

djc

Nou; je zou een template kunnen maken die diverse call-templates in een when-choose-otherwise block zet, met tests op je variabele. Hangt een beetje van je source tree af of dat scalable is.

[ Voor 19% gewijzigd door djc op 16-06-2005 22:35 ]

Rustacean


  • Captain N
  • Registratie: Maart 2001
  • Laatst online: 10-05-2024

Captain N

Back in NL. T_T

Topicstarter
De situatie is als volgt: Ik heb een Cocoon sitemap, waarin ik de opdracht geef een XML file te transformen door een XSLT sheet. Hiermee geef ik een parameter mee waarin een pad staat in die XML file, wat een paragraaf selecteert. Die paragraaf wil ik een andere backgroundcolor geven in de XSL. Het pad is afhankelijk van een zoekopdracht, dus vandaar dat die als parameter wordt meegegeven, en niet hard gecodeerd is.

Specs: NES | M82 | (T)FC | SNES | BS-X | VB | N64 | 64DD | NGC | Q | Q GBP | G&Ws | GB(L) | GB(A) (SP) | GBM | DS(L) | Wii
Mijn foto's op Flickr.


  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
met xpath1.0 kan je geen expressies evaluaten zonder extra plugins te gebruiken.

exslt schijnt het te kunnen :-)

laat ff weten of het is gelukt

  • Captain N
  • Registratie: Maart 2001
  • Laatst online: 10-05-2024

Captain N

Back in NL. T_T

Topicstarter
Ja, ik heb gevonden dat in XSLT 1.0 het niet kan omdat de variabele bij runtime zijn waarde krijgt, en die match moet hem daarvoor al weten. Maar in XSLT 2.0 schijnt het wel te kunnen, maar ik weet alleen nog niet hoe.

code:
1
<xsl:template match="*[name() = {$xpath}]">


Dit is bijna wat ik zoek. Ik wil alleen in plaatje van naar de naam van het huidige element, naar het pad en de naam kijken. Maar ik ben er nog niet achter hoe.

En bedankt voor de tip. Ik heb liever een oplossing zonder extensies, maar mocht het toch echt niet lukken in XSLT 2.0 dan wordt het toch maar dat :)

Specs: NES | M82 | (T)FC | SNES | BS-X | VB | N64 | 64DD | NGC | Q | Q GBP | G&Ws | GB(L) | GB(A) (SP) | GBM | DS(L) | Wii
Mijn foto's op Flickr.


  • Captain N
  • Registratie: Maart 2001
  • Laatst online: 10-05-2024

Captain N

Back in NL. T_T

Topicstarter
Nieuw idee: Een XSLT sheet maken die een stukje XSLT code genereert, met daarin een value-of select die de waarde van $xpath geeft. Als ik dit stukje dan importeer in de uiteindelijke XSLT staat de waarde van $xpath al vast voor run-time.... of niet? En zo ja, hoe pak ik dit aan?

Ik ben nu al 2 dagen bezig met iets dat zo simpel lijkt. Erg frustrerend :P

Specs: NES | M82 | (T)FC | SNES | BS-X | VB | N64 | 64DD | NGC | Q | Q GBP | G&Ws | GB(L) | GB(A) (SP) | GBM | DS(L) | Wii
Mijn foto's op Flickr.


  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
Of vanaf de andere kant:

je xml genereren zodat alleen de juiste xml aan de xslt gegeven wordt.

  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
Nieuw idee: Een XSLT sheet maken die een stukje XSLT code genereert
2 fasen aanpak.

1e ronde: genereer met xslt een nieuwe xslt
2e ronde: transform je xml met je nieuwe (gegenereerde) xslt

Het lijkt me het makkelijkst als je deze twee ronden in de code uitvoert en niet binnen 1 xslt, want dan zit je weer met hetzelfde probleem van dynamic evaluaten nl.

  • Captain N
  • Registratie: Maart 2001
  • Laatst online: 10-05-2024

Captain N

Back in NL. T_T

Topicstarter
Ik probeerde dat inderdaad al zo te doen. Maar daarmee loop ik al vast in cocoon.

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<map:match pattern="publish/collection:**/file:**/xpath:**">
  <map:generate type="file" src="preprocessed_xslt.xml"/>
  <map:transform src="Collections/{1}/xsl/pre_process.xsl">
    <map:parameter name="xpath" value="{3}"/>
  </map:transform>
  <map:generate type="file" src="Collections/{1}/xml/{2}"/>
  <map:transform type="xslt-saxon" src="Collections/{1}/xsl/publish_file.xsl">
    <map:parameter name="COLLECTION" value="{1}"/>
    <map:parameter name="COCOON_BASE" value="/home/>
    <map:parameter name="file" value="{2}"/>
    <map:parameter name="xpath" value="{3}"/>
  </map:transform>
  <map:serialize/>
</map:match>


Dit werkt niet omdat er geen twee generate's in een match voor kunnen komen. preprocessed_xslt.xml is een lege file met alleen een root, om de xsl file te kunnen uitvoeren. Daarin wil ik een stukje code maken die dus zegt template match="inhoud van die variabele", en die dan in publish_file.xsl includen. Wat doe ik fout? Of liever gezegd: hoe moet het wel? :)

Specs: NES | M82 | (T)FC | SNES | BS-X | VB | N64 | 64DD | NGC | Q | Q GBP | G&Ws | GB(L) | GB(A) (SP) | GBM | DS(L) | Wii
Mijn foto's op Flickr.


  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
Ik heb geen verstand van Cocoon, dus hoe je het gaat implementeren zul je ff moeten bekijken. Ik heb wel voor je gemaakt wat xml/xslt om te laten zien wat ik bedoel.

de bron xml waar je dynamisch uit wilt selecteren (versimpeld;-))
code:
1
2
3
4
5
<?xml version="1.0" encoding="UTF-8"?>
<root>
   <elem1>value van elem 1</elem1>
   <elem2>value van elem 2</elem2>
</root>


om deze te kunnen transformeren gaan we dynamisch een xslt maken die de juiste xpaths bevat. Hiervoor heb ik een dummy input xml:
code:
1
2
<?xml version="1.0" encoding="UTF-8"?>
<dummy />

en een hippe xslt die dus een xslt maakt:
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
<?xml version="1.0" encoding="UTF-8"?>
<!-- the default namespace is the same as the xsl namespace so the output document is also in the xslt namespace -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   <!-- 
      parameters for dynamic xsl creation
   -->
   <xsl:param name="template-match-xpath">/root/elem1</xsl:param>
   <!-- a root template that matches the dummy -->
   <xsl:template match="/">
      <!-- create the stylesheet element -->
      <xsl:element name="stylesheet" >
         <xsl:attribute name="version">1.0</xsl:attribute>
         <!-- create the output element -->
         <xsl:element name="output">
            <xsl:attribute name="method">xml</xsl:attribute>
            <xsl:attribute name="version">1.0</xsl:attribute>
            <xsl:attribute name="encoding">UTF-8</xsl:attribute>
            <xsl:attribute name="indent">yes</xsl:attribute>
         </xsl:element>
         <!--
            now create a default template
         -->
         <xsl:element name="template">
            <!-- create the match attribute with the value from the parameter -->
            <xsl:attribute name="match"><xsl:value-of select="$template-match-xpath" /></xsl:attribute>
            <!-- get some value of it -->
            <xsl:element name="value-of">
                  <xsl:attribute name="select">.</xsl:attribute>
            </xsl:element>
         </xsl:element>
      </xsl:element>
   </xsl:template>
</xsl:stylesheet>


als ik deze xslt uitvoer, dan krijg ik de volgende xml:
code:
1
2
3
4
5
6
7
<?xml version="1.0" encoding="UTF-8"?>
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform">
   <output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   <template match="/root/elem1">
      <value-of select="."/>
   </template>
</stylesheet>


en die is gemaakt om die eerste xml te transformen.


note: die xslt die ik heb gemaakt om de 'echte' xslt te maken kan ook simpeler .. je kan ook ff je bestaande xslt 'aanpassen' mbv copy en copy-of .. Als je deze demo aan de praat krijgt in cocoon en je denk gaaf, nu wil ik die coole xslt met copy/copy-of EN je krijgt niet voor mekaar, dan moet je het maar ff posten :)

  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
ik was toch bezig .. enne xslt is best kewl :)

stel jehebt een xslt waar je een template met match in hebt die je dus dynamisch wilt invullen.
bijv:
code:
1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   <xsl:template match="/">
      <!-- do stuff -->
      <xsl:apply-templates />
   </xsl:template>
   <!-- the template that needs a dynamic match -->
   <xsl:template match="replace-me-please">
      <!-- do interesting stuff with xml -->
   </xsl:template>
</xsl:stylesheet>


dan wil je dus eigenlijk die hele xslt copieren en dan ff die match aanpassen. daarvoor haal je de hierboven genoemde xlst ff door de xslt hieronder:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
   <xsl:param name="dynamic-xpath">my-query</xsl:param>
   <!-- copy all elements and attributes -->
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
   <!-- specific match for our replace-me-please-template -->
   <xsl:template match="@match[.='replace-me-please']">
      <xsl:attribute name="match"><xsl:value-of select="$dynamic-xpath"/></xsl:attribute>
   </xsl:template>
</xsl:stylesheet>


de output is dan een xslt met daarin je dynamische match :)

EN je hoeft je kop niet te breken als je een aanpassing wilt maken in je xslt-template ;-)


happy programming!

  • Captain N
  • Registratie: Maart 2001
  • Laatst online: 10-05-2024

Captain N

Back in NL. T_T

Topicstarter
Wow, bedankt voor je uitgebreide antwoord! Ik kan alles volgens wat in je code staat, alleen wat ik dus nog niet helemaal begrijp is: hoe roep ik het hele boeltje nu aan? Je hebt dus je bron XML file. Die wil je transformen met de gegenereerde XSLT. Maar hoe zorg ik er nu voor dat ik die krijg? Hoe roep ik aan: maak die dynamisch gegenereerde XSLT? Misschien dat ik even iets heel doms over het hoofd zie, maar het kwartje wil nog even niet vallen :P

En over het copy voorbeeld: hoe hang je die tweede XSLT aan die eerste? Die eerste als .xml opslaan, of...? En als dat zo is, dan snap ik dus nog niet hoe je ervoor kunt zorgen dat als je je bron.xml wilt laten transformen door die 2e XSLT, die XSLT eerst die bewerking op die eerste XSLT heeft uitgevoerd. :?

[ Voor 27% gewijzigd door Captain N op 17-06-2005 18:56 ]

Specs: NES | M82 | (T)FC | SNES | BS-X | VB | N64 | 64DD | NGC | Q | Q GBP | G&Ws | GB(L) | GB(A) (SP) | GBM | DS(L) | Wii
Mijn foto's op Flickr.


  • Captain N
  • Registratie: Maart 2001
  • Laatst online: 10-05-2024

Captain N

Back in NL. T_T

Topicstarter
Ik heb het gevoel dat ik er nu bijna ben. Ik heb nu het volgende in mijn Cocoon sitemap.xmap staan:

code:
1
2
3
4
5
6
7
<map:match pattern="publish/collection:**/file:**/xpath:**">
 <map:generate type="file" src="preprocess.xsl"/>
 <map:transform src="preprocessor.xsl">
  <map:parameter name="xpath" value="{3}"/>
 </map:transform>
 <map:serialize type="xml"/>
</map:match>


Dit levert de XSLT file op die ik wil hebben. Nu nog 1 stap. De XML file transformen met die zojuist gegenereerde XSLT. Maar ik kom er niet uit hoe ik dat op moet schrijven :?

edit: Het werkt!! (8> De volgende code did the trick:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
<map:match pattern="publish/collection:**/file:**/xpath:**">
 <map:generate type="file" src="Collections/{1}/xml/{2}"/>
 <map:transform src="cocoon:/preprocess/xpath:{3}"/>
 <map:serialize/>
</map:match>
            
<map:match pattern="preprocess/xpath:**">
 <map:generate type="file" src="preprocess.xsl"/>
 <map:transform src="xsl/preprocessor.xsl">
  <map:parameter name="xpath" value="{1}"/>
 </map:transform>
 <map:serialize type="xml"/>
</map:match>

[ Voor 41% gewijzigd door Captain N op 18-06-2005 01:40 ]

Specs: NES | M82 | (T)FC | SNES | BS-X | VB | N64 | 64DD | NGC | Q | Q GBP | G&Ws | GB(L) | GB(A) (SP) | GBM | DS(L) | Wii
Mijn foto's op Flickr.


  • joopst
  • Registratie: Maart 2005
  • Laatst online: 01-10-2024
heel stoere code :)

maar wat ik al zeg, ik snap geen zak van cocoon :P

wel leuk dat ik je toch ermee heb kunnen helpen ..

peace
Pagina: 1