QL.túra

Kulturális smörgåsbord Esterházytól Wass Albertig, a gumicsizmától az iPad-ig, a Teletabiktól Sexpírig, a makrofágtól a mikrokontrollerig, miazmás...

Címkék

2000 (20) 2001 (6) 2002 (16) 2003 (164) 2004 (61) 2005 (40) 2006 (31) 2007 (28) 2008 (33) 2009 (175) 2010 (188) 2011 (201) 2012 (86) 2013 (40) 2014 (36) 2015 (26) 2016 (10) adáshiba (91) android (1) animáció (93) cygwin (3) film (410) gezarol (13) hájtek (159) hangoskönyv (32) ipad (17) klip (12) könyv (191) linux (29) színház (169) vers (17) windows (37) zene (111) Címkefelhő

+jegyzések

Most ...

... múlok .osan

bmi_tiny.png


... hallgatom
Szabó Magda: Régimódi történet
https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSqTmZEqlCRFgojyt52Q2n_qiMTyVlt-zJu-DpbNKVY6OQbBh4u


... olvasom
Alexander Steele (szerk.): Kezdő írók kézikönyve


... (Kik ezek? Kik ezek az embek? Kik ezek?)
profile for TrueY on Stack Exchange, a network of free, community-driven Q&A sites
free counters

[Hájtek] XSLT 1.0 tippek és trükkök

2011.09.28. 11:00 | TrueY | Szólj hozzá!

Címkék: 2011 hájtek

XSLT v1.0-ban kellett egy XML file-ból pofás kis HTML riportot generálnom. Mivel ez volt az első ütközésem az XSLT-vel, némileg bele kellett jönnöm. A belejövés folyamatát idedokumentáltam egy kicsit.

Egy kis bevezetés: w3schools.com. Sajnos ez a legnagyobb trükkről egy szót sem ejt, azaz, hogy az XSLT-ben egy definiált változót nem tudunk később megváltoztatni. Már a feltételtől függő értékadás is érdekes.

Referencia doksik:

  • XSLT 1.0 referencia: w3.org xslt v1.0
  • XSLT 2.0 referencia: XSLT v2.0, hogy egy kis kitekintésünk is legyen.
  • És egy jó kis szakácskönyv: java2s.com. Nekem sok ötletet adott.

Az xslt-vel xml doksikból XHTML doksikat gyártani. Illetve egy pici trükközéssel bármilyen más formátumú file-t is. Elég egyszerű a nyelv (lásd csatolt linket), de a logikája nagyon nem nem triviális.

A nyelv elemei nagyon vázlatosan:

  • <xsl:template match="...">: Ezek egy adott al-csomópontot keresnek meg és a hozzá tartozó al-fát (mégsem írhattam, hogy alfát) dolgozzák fel. Direketben is meghívható az <xsl:apply-templates select="..."> hivatkozással. A select-ben több template-re is hivatkozhatunk "tag1|tag2|tag2". Ekkor azt a template-et fogja hívni, amilyen tag-et talál az adott xml al-fában.
  • <xsl:value-of select="...">: Egy adott csomópont értékét veszi ki. Hasonló az <xsl:copy-of select="...">, de ekkor a HTML formázó karaktereket is kiírja.
  • <xsl:for-each select="...">: az adott csomópont alatti ismétlődő csomópontokon megy végig. A csomópont alatti elemeket a már jól ösmert <xsl:value-of>-fal lehet kiszedni. Ezen belül az <xsl:sort select="...">-tal lehet valamelyik csomópont tartalma alapján sorrendbe tenni.
  • <xsl:if test="...">: egy feltétel teljesülését ellenőrizhetjük. Van '<', '>' stb., de a leírásból nem derült ki számomra, hogyan lehet megnézni, hogy egy adott csomópont definiálva van-e.
    <xsl:if test="not(title)"> - a title node nincs definiálva
    <xsl:if test="title"> - a title node definiálva van
    <xsl:if test="title=''"> - title node nincs definiálva, VAGY a title node definiálva van és üres (<title></title>, vagy <title/>). A végén két aposztróf van és egy macskaköröm.
    <xsl:if test="title!=''"> - a title node definiálva van és nem üres (<title>akármi</title>)
  • <xsl:choose>, <xsl:when test="expression">, <xsl:otherwise>: Megnézni, hogy egy érték egyenlő-e valamilyen értékekkel (l. switch-case-...-default)
  • <xsl:apply-templates select="...">: a template-tel definiált template-eket meghívja. Ha abban is van apply-remplates, akkor lehet rekurzívan is hívni a template-eket. Paramétereket is átadhatunk (call-template, with-param).
  • <xsl:variable name="..." select="..."/>, vagy <xsl:variable name="...">...</xsl:variable> - változó definiálsása. Ha egy változót definiáltunk, akkor soha többé nem változtathatjuk meg az értékét (a miértekről >itt<). Ne próbáljunk if-ben definiálni változót, mert a if-fen kívül nem lesz használható. Ha azt szeretnénk, hogy az if-fen kívül is használhassuk, akkor így kell tennünk:

    <xsl:variable name="bgcolor">
      <xsl:choose>
        <xsl:when test="valamilyen_tag">blue</xsl:when>
        <xsl:otherwise>red</xsl:otherwise>
      </xsl:choose>
    </xsl:variable>

    <tr bgcolor="{$bgcolor}">
    Az sajna nem megoldás, akár mennyire is tetszetősnek tűnik, hogy a choose-on belül definiálunk egy változót, mert a scope-ja csak a choose-n belül lesz értelmes. Sőt az sem jó, ha a <tr>-t így, vagy úgy írjuk ki a choos-on belül. Valami miatt ha egy blokk nem tartalmazza a lezáró tag-et is, akkor szintaktikai hibát ad. Szóval ez sem jó:

    <xsl:choose>
      <xsl:when test="profile"><tr bgcolor="blue"></xsl:when>
      <xsl:otherwise><tr></xsl:otherwise>
    <xsl:choose>

További referencia az elemekről és a függvényekről. Persze elég sokféle matematikai művelet végzésére is rávehetjük. 

Nézzünk egy kicsit komplexebb példákat:

  • Adva van egy XML ami kb. így néz ki:
    ...
    <basetag>
      <name>ez_a_neve</name>
    ...
              <lasttag>akarmi</lasttag>
    ...
                          <lasttag>akarmi</lasttag>
    </basetag>
    <basetag>



    ...
    No és ez sokszor ismétlődik. A lasttag értékei lehetnek azonosak, de lehetnek eltérőek is. Egy lasttag érték szerepelhet több basetag-ban is. A name-ek minden <basetag>-ban egyediek. Hogyan tudunk olyan táblázatot csinálni, ami úgy néz ki, hogy "lasttag | melyik basetag(ok)-ban van használva". Én úgy csináltam, hogy először egy uniq listán megyek végig, ami a <lasttag>-okat tartalmazza (abc sorrdendben), majd megnézem, hogy mely basetag-oknak van az adott lasttag-gal egyező eleme. Kb. így:
    <!-- valahol az elején kell definiálni -->
    <xsl:key name="lasttags" match="basetag//*/lasttag" use="."/>

    ...

    <table>
    <xsl:for-each select="basetag//*/lasttag[generate-id() = generate-id(key('lasttags', .)[1])]"> <!-- uniq -->
    <xsl:sort select="."/> <!-- sort -->
      <xsl:variable name="lasttag" select="."/>
      <tr>
        <td><xsl:value-of select="$lasttag"/></td>
        <td>
          <xsl:for-each select="//basetag">
            <xsl:variable name="basetag" select="name"/>
            <xsl:if test="count(descendant::*[lasttag=$lasttag])>0">
              <xsl:value-of select="$basetag"/><br/>
            </xsl:if>
          </xsl:for-each>
        </td>
      </tr>
    </xsl:for-each>
    </table>
    Hát nem szép? Hát nem... de működik! A nagy trükk a "descendant::" használata volt. Bár valszeg a legbelső if-ben nem kell a count, de így mégis csak beszédesebb.

    Persze lehetne a uniq kulcs ciklust egyszerűbben is létrehozni a distinct-values() függvénnyel, ami XSLT 2.0-ában defriniálva vagyon. Csak az msxml nem nagyon ösmeri. MSXML 3 által támogatott függvények listáját >itt< tekinthetjük meg.
  • Szeretnénk regular expressiont használni. Sajnos az msxml nem támogatja az <xsl:if test="matches(...)"> függvényt (pedig még a fejlécben is próbáltam a <xsl:stylesheet version="2.0"-t nem jött be.), de pl. JavaScript kódot lehet hívni. Kicsit trükkös, de végül sikerült zöld ágra vergődnöm vele. A megfelelő eredményhez a fejlécben is hozzá kell nyúlni:
    <xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:msxsl="urn:schemas-microsoft-com:xslt"
        xmlns:JS="urn:my-scripts">
    Ez után már meg is írhatjuk a függvényünket:
    <msxsl:script language="JavaScript" implements-prefix="JS">
      <![CDATA[
        function xxx(value) {
          val = "x_" + typeof(value) + "_x";
          return val;
        }
      ]]>
    </msxsl:script>
    Ezt már csak meg kellene tudni hívni a xslt kódból. Első próba nem sikerült: <xsl:value-of select="JS:xxx(name)"/>Érdekes, hogy ha a return-ban visszaadjuk a value-t változtatás nélkül, akkor az átadott értéket kapjuk. A return "xxx" is jó. De a return "xxx" + value már nem működik, mert a value mindig üres string lesz. Ha megnézzük, hogy mi a typeof(value), akkor egy az "object" string-et kapjuk. Tehát valami konverziós problema van. Próbálkoztam trükközni a val = new String()-gel, de nem sikerült. A megoldás az, hogy a hívásnál kell konvertálni!
    <xsl:value-of select="JS:xxx(string(name))"/>Ekkor a typeof(value) már "string" lesz! Egy számokat tartalmazó változó értéke "number" lesz.
  • Megpróbáltam a JS kóddal visszaadni egy teljesen beformázott HTML sort is, de csak a string jelenik meg én nem szúrja be a HTML tag-eket, inkább a '<' és '>'-t lecseréli &lt; és &gt;-re. Próbálkoztam value-of-fal és copy-of-fal is.
    Megpróbáltam a value-of végére hozzáírni a disable-output-escaping="yes"-t (<xsl:value-of select="JS:..." disable-output-escaping="yes" />), És így már ment is!

Amit nem sikerült megoldanom:

  • Megpróbáltam egy select="JS:xxx(//tag_name)" hívást is. A //tag_name kifejezés egy tag listát ad vissza. JS egy objektum tömböt lát, amelynek minden tagja objektum típusú. De hogy hogyan lehet ebből kinyerni, hogy mi a tartalma az egyes objektumoknak, arra nem jöttem rá. No és hogyan lehet egy ilyen listát visszaadni? Mondjuk ha szeretnénk egy for-each-ban használni...
     

Formázódjunk minden nap!

A bejegyzés trackback címe:

https://qltura.blog.hu/api/trackback/id/tr653182851

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása