XML extensible Markup Language część 4
XSL transformations (XSLT) XSLT (ang. extensible Stylesheet Language Transformations) jest opartym na XML językiem transformacji dokumentów XML XSLT umożliwia przetłumaczenie dokumentów z jednego formatu XML na inny format XML, ale również na HTML, PDF i inne. Arkusze XSLT określają w jaki sposób przekształcić poszczególne elementy wejściowe pliku XML. dokument XML arkusz XSLT procesor XSLT plik wyjściowy (XML, HTML, PDF etc.)
Struktura XSLT Arkusz XSLT ma następującą strukturę <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> INSTRUKCJE OKREŚLAJĄCE PRZEKSZTAŁCENIA ELEMENTÓW </xsl:stylesheet> Zapisujemy go w pliku z rozszerzeniem xsl np. arkusz.xsl W dokumencie XML, który ma być przekształcamy umieszczamy <?xml-stylesheet type="application/xml" href="arkusz.xsl"?>
<xsl:template> Dokument XML z atrybutami + XSLT <?xml version="1.0" encoding="utf-8"?> <?xml-stylesheet type="application/xml" href="arkusz.xsl"?> <spis_osob> <osoba wiek="29"> <imie>marek</imie> <nazwisko>nowak</nazwisko> </osoba> <osoba wiek="33"> <imie>tomasz</imie> <nazwisko>pawlak</nazwisko> </osoba> <osoba wiek="35"> <imie>piotr</imie> <nazwisko>kaczkowski</nazwisko> </osoba> </spis_osob>
<xsl:template> Odwołanie do elementu z atrybutem o określonej wartości. Przykład <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:template match="osoba[@wiek = '33']"> abc </xsl:stylesheet> W przeglądarce:
<xsl: apply-templates select=" "/> Przetwarzanie (dzieci) elementu. Przykład <xsl:template match="/"> <html> <body> <h3>spis</h3> <xsl:apply-templates/> </body> </html> <xsl:template match="osoba"> <p> <xsl:apply-templates select="imie"/> <xsl:apply-templates select="nazwisko"/> Wiek: <span style="color:red"> <xsl:value-of select="@wiek"/> </span> </p>
<xsl: apply-templates select=" "/> Przetwarzanie (dzieci) elementu. Przykład (cd) <xsl:template match="imie"> Imie: <span style="color:blue"><xsl:value-of select="."/> </span><br/> <xsl:template match="nazwisko"> Nazwisko: <span style="color:green"><xsl:value-of select="."/> </span><br/>
<xsl: apply-templates select=" "> W przeglądarce:
<xsl: apply-templates select=" "/> Przetwarzanie (dzieci) elementu. Przykład (cd) Definiujemy szablon tylko dla elementu imie: <xsl:template match="imie"> Imie: <span style="color:blue"><xsl:value-of select="."/> </span><br/> W przeglądarce:
<xsl: apply-templates select=" "/> A teraz inna wersja znanego nam już arkusza XSLT. Przykład <xsl:template match="/"> <html> <body> <h3>spis</h3> <table border="1"> <tr> <th>first name</th> <th>last name</th> <th>age</th> </tr> <xsl:apply-templates/> </table> </body> </html>
<xsl: apply-templates select=" "/> Przykład (cd) Szablon dla elementu osoba: <xsl:template match="osoba"> <tr> <xsl:apply-templates select="imie"/> <xsl:apply-templates select="nazwisko"/> <xsl:apply-templates select="wiek"/> </tr>
<xsl: apply-templates select=" "/> Przykład (cd) Szablon dla pozostałych elementów: <xsl:template match="imie"> <td><xsl:value-of select="."/></td> <xsl:template match="nazwisko"> <td><xsl:value-of select="."/></td> <xsl:template match="wiek"> <td><xsl:value-of select="."/></td>
<xsl: apply-templates select=" "> W przeglądarce:
<xsl:attribute> Do elementu HTML możemy dodać atrybut będący zawartością jakiegoś elementu bądź wartością atrybutu z dokumentu XML. Przykład <galeria> <obrazek>most.jpg</obrazek> <obrazek>widok.jpg</obrazek> </galeria> <body> <h3>obrazki</h3> <xsl:for-each select="galeria/obrazek"> <img> <xsl:attribute name="src"> <xsl:value-of select="."/> </xsl:attribute> </img> </xsl:for-each> </body>
<xsl:attribute> Przykład Inaczej: <galeria> <obrazek plik="most.jpg"/> <obrazek plik="widok.jpg"/> </galeria> <body> <h3>obrazki</h3> <xsl:for-each select="galeria/obrazek"> <img> <xsl:attribute name="src"> <xsl:value-of select="@plik"/> </xsl:attribute> </img> </xsl:for-each> </body>
Element nie istnieje? Przykład <?xml version="1.0" encoding="utf-8"?> <?xml-stylesheet type="application/xml" href="arkusz.xsl"?> <spis_osob> <osoba> <imie>marek</imie> <nazwisko>nowak</nazwisko> <wiek>23</wiek> </osoba> <osoba> <imie>tomasz</imie> <nazwisko>pawlak</nazwisko> <wiek>33</wiek> </osoba> <osoba> <imie>piotr</imie> <nazwisko>kaczkowski</nazwisko> </osoba> </spis_osob>
Element nie istnieje? Przykład (cd) <table border="1"> <tr> <th>first name</th><th>last name</th><th>age</th> </tr> <xsl:for-each select="spis_osob/osoba"> <tr> <td><xsl:value-of select="imie"/></td> <td><xsl:value-of select="nazwisko"/></td> <xsl:choose> <xsl:when test="wiek"> <td><xsl:value-of select="wiek"/></td> </xsl:when> <xsl:otherwise> <td style="background-color:red"> <xsl:text>brak danych</xsl:text> </td> </xsl:otherwise> </xsl:choose> </tr> </xsl:for-each> </table>
<xsl:template> Do tej pory szablony były wywoływane w chwili napotkania elementu w dokumencie XML. Przykład <?xml version="1.0"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:template match="osoba"> abc </xsl:stylesheet> W przeglądarce:
<xsl:call-template> Szablon może być też wywołany przez nazwę, podobnie jak funkcja w języku C++ lub Java. Składnia: <xsl:call-template name="templatename"> <!-- Content:xsl:with-param* --> </xsl:call-template>
<xsl:call-template> Przykład (cd) Arkusz XSL: <xsl:template match="/"> <html> <body> <h3>obrazki</h3> <xsl:for-each select="galeria/obrazek"> <xsl:call-template name="test"/> </xsl:for-each> </body> </html> <xsl:template name="test"> abc <galeria> <obrazek plik="most.jpg"/> <obrazek plik="widok.jpg"/> </galeria>
<xsl:call-template> Przykład (cd) Czy można do szablonu przekazać zawartość elementu lub wartość atrybutu? <xsl:template match="/"> <html> <body> <h3>obrazki</h3> <xsl:for-each select="galeria/obrazek"> <xsl:call-template name="test"/> </xsl:for-each> </body> </html> <xsl:template name="test"> abc?
<xsl:param> Deklaracja lokalnego bądź globalnego parametru. Parametr jest lokalny jeżeli jest zadeklarowany w elemencie template. Składnia: <xsl:param name="name" select="expression"> <!-- Content:template --> </xsl:param> Atrybuty: name określa nazwę parametru (wymagany) select wartość w postaci wyrażenia XPath (opcjonalny)
<xsl:with-param> Definiujemy wartość parametru, który ma być przekazany do szablonu. Składnia: <xsl:with-param name="name" select="expression"> <!-- Content:template --> </xsl:with-param> Atrybuty: name określa nazwę parametru (wymagany) select wartość w postaci wyrażenia XPath (opcjonalny)
<xsl:param> + <xsl:with-param> Jeżeli szablon wymaga parametru to zapisujemy to tak: <xsl:template name="tname"> <xsl:param name="pname"/>... $pname... Wartość parametru musimy przesłać do szablonu przy wywołaniu: <xsl:call-template name="tname"> <xsl:with-param name="pname" select="expression"/> </xsl:call-template>
<xsl:param> + <xsl:with-param> Przykład <body> <h3>obrazki</h3> <galeria> <obrazek>most.jpg</obrazek> <obrazek>widok.jpg</obrazek> </galeria> <xsl:for-each select="galeria/obrazek"> <xsl:call-template name="test"> <xsl:with-param name="plik" select="." /> </xsl:call-template> </xsl:for-each> </body> <xsl:template name="test"> <xsl:param name="plik"/> <img> <xsl:attribute name="src"> <xsl:value-of select="$plik"/> </xsl:attribute> </img>
<xsl:param> Przykład <wspolczynniki a="0" b="1"/> <xsl:param name="a" select="/wspolczynniki/@a"/> <xsl:param name="b" select="/wspolczynniki/@b"/> <xsl:template match="/"> <html> <body> <h4>rozwiązanie równania: <span> <xsl:value-of select="$a"/>x+ <xsl:value-of select="$b"/> </span> </h4> <xsl:call-template name="ilerozwiazan"/> </body> </html>
<xsl:param> Przykład (cd) <wspolczynniki a="0" b="1"/> <xsl:template name="ilerozwiazan"> <xsl:choose> <xsl:when test="$a!=0"> <b>1 rozwiązanie:</b> x<sub>1</sub>= <xsl:value-of select="-($b div $a)"/> </xsl:when> <xsl:otherwise> <xsl:choose> <xsl:when test="$b=0"> <b>nieskończenie wiele rozw.</b> </xsl:when> <xsl:otherwise> <b>0 rozwiązań</b> </xsl:otherwise> </xsl:choose> </xsl:otherwise></xsl:choose>
<xsl:param> Przykład (cd) W oknie przeglądarki: <wspolczynniki a="0" b="1"/>
<xsl:param> Przykład <wspolczynniki a="1" b="2" c="10"/> <xsl:param name="a" select="/wspolczynniki/@a"/> <xsl:param name="b" select="/wspolczynniki/@b"/> <xsl:param name="c" select="/wspolczynniki/@c"/> <xsl:template match="/"> <html> <body> <h4>rozwiązanie równania:</h4> <span> <xsl:value-of select="$a"/>x<sup>2</sup>+ <xsl:value-of select="$b"/>x+ <xsl:value-of select="$c"/> </span> <xsl:call-template name="ilerozwiazan"/> </body> </html>
<xsl:param> Przykład (cd) <wspolczynniki a="1" b="2" c="10"/> <xsl:template name="ilerozwiazan"> <xsl:param name="delta" select="($b*$b)-(4*$a*$c)"/> <p> =<xsl:value-of select="$delta"/> </p> <xsl:choose> <xsl:when test="$delta > 0"> <b>2 rozwiązania</b> </xsl:when> <xsl:when test="$delta = 0"> <b>1 rozwiązanie</b> </xsl:when> <xsl:otherwise> <b>0 rozwiązań</b> </xsl:otherwise> </xsl:choose>
<xsl:param> Przykład (cd) W oknie przeglądarki:
<xsl:param> + <xsl:with-param> Przykład Arkusz XSL: <potega> <podstawa>4</podstawa> </potega> <xsl:template match="/"> <html> <xsl:value-of select="potega/podstawa"/> <sup>2</sup> = <xsl:call-template name="potega"> <xsl:with-param name="p" select="potega/podstawa"/> </xsl:call-template> </html> <xsl:template name="potega"> <xsl:param name="p"/> <span><xsl:value-of select="$p*$p"/></span>
Operacje matematyczne Przykład Arkusz XSL: <xsl:template match="liczby"> <html> <ul> <liczby> <x>4</x> <y>3.2</y> <z>11</z> </liczby> <li>a.4 + 3.2=<xsl:value-of select="x + y"/></li> <li>b.3.2-4=<xsl:value-of select="y - x"/></li> <li>c.4 * 3.2=<xsl:value-of select="x * y"/></li> <li>d.11/3.2=<xsl:value-of select="z div y"/></li> <li>e.4+3.2*11= <xsl:value-of select="x+y*z"/></li> <li>f.(4+3.2)*11=<xsl:value-of select="(x+y)*z"/></li> <li>g.11 mod 4=<xsl:value-of select="z mod x"/></li> <li>h.4+3.2+11=<xsl:value-of select="sum(*)"/></li> <li>i.floor(3.2)=<xsl:value-of select="floor(y)"/></li> <li>j.round(3.2)=<xsl:value-of select="round(y)"/></li> <li>k.3.2+string-length("3.2")= <xsl:value-of select="y+string-length(y)"/></li> <li>l. 11+"hello"=<xsl:value-of select="z+'hello'"/></li> </ul> </html>
Operacje matematyczne Przykład (cd) W oknie przeglądarki:
<xsl:variable> Deklaracja lokalnej bądź globalnej zmiennej. Zmienna jest loklana jeżeli jest zadeklarowana w elemencie template. Składnia: <xsl:variable name="name" select="expression"> <!-- Content:template --> </xsl:variable> UWAGA: raz ustalona zmienna nie powinna zmieniać wartości!!!
<xsl:variable> Nadanie wartości zmiennej przez atrybut. Przykład <xsl:variable name="osoba" select="'przemek'"/> <xsl:template match="/"> <html><body> <h3>spis</h3> <xsl:copy-of select="$osoba" /> </body></html> W przeglądarce:
<xsl:variable> Nadanie wartości zmiennej przez zawartość elementu. Przykład <xsl:variable name="osoba"> <osoba> <imie>przemek</imie> <nazwisko>kowal</nazwisko> <wiek>42</wiek> </osoba> W przeglądarce: </xsl:variable> <xsl:template match="/"> <html><body> <h3>spis</h3> <xsl:copy-of select="$osoba"/> </body></html>
<xsl:variable> A co jeżeli zmienimy wartość zmiennej? Przykład <xsl:variable name="osoba" select="'przemek'"/> <xsl:template match="/"> <html><body> <h3>spis</h3> <xsl:copy-of select="$osoba" /> </body> </html> <xsl:variable name="osoba" select="'agata'"/> W przeglądarce:
<xsl:variable> Nadanie wartości zmiennej przez wyrażenie XPath. Przykład Dokument XML: <liczby start="1" stop="31"/> Arkusz XSL: <xsl:variable name="a" select="/liczby/@start"/> <xsl:variable name="b" select="/liczby/@stop"/> <xsl:template match="/"> <html> <body> <p>a=<xsl:value-of select="$a"/></p> <p>b=<xsl:value-of select="$b"/></p> </body> </html>
<xsl:variable> Przykład <xsl:variable name="start" select="/tabela/@start"/> <xsl:variable name="stop" select="/tabela/@stop"/> <xsl:variable name="zm1" select="$start + $stop"/> <xsl:variable name="zm2" select="$start + $stop + 10"/> <xsl:template match="/"> <html> <body> <p>zmienna 1 = <xsl:value-of select="$zm1"/></p> <p>zmienna 2 = <xsl:value-of select="$zm2"/></p> </body> </html> W przeglądarce:
Iteracja Rozważmy teraz następujący program: Przykład int start=1; int stop=10; int main() { for(int i=start;i<=stop;i++) { cout<<i; } return 0; }
Rekurencja To samo rekurencyjnie: Przykład int start=1; int stop=10; void wypisz(int i) { if(i<stop+1) { cout<<i; wypisz(++i); } } int main() { wypisz(start); return 0; }
Rekurencja w XSLT Spróbujmy to samo uzyskać w XSLT. Przykład Dokument XML: <?xml version="1.0"?> <?xml-stylesheet type="application/xml" href="arkusz.xsl"?> <liczby start="1" stop="10"/> Arkusz XSL: <xsl:variable name="start" select="/liczby/@start"/> <xsl:variable name="stop" select="/liczby/@stop"/>
Rekurencja w XSLT Przykład (cd) <liczby start="1" stop="10"/> Arkusz XSL (cd): <xsl:template name="liczby"> <xsl:param name="index" select="$start"/> <xsl:if test="$index < $stop+1"> <span><xsl:value-of select="$index"/></span> <xsl:call-template name="liczby"> <xsl:with-param name="index" select="$index+1"/> </xsl:call-template> </xsl:if>
Rekurencja w XSLT Przykład (cd) <liczby start="1" stop="10"/> Arkusz XSL (cd): <xsl:template match="/"> <html> <body> <h3>wypisujemy liczby</h3> <xsl:call-template name="liczby"/> </body> </html> W przeglądarce:
<xsl:text> Element umożliwiający dodanie tekstu do pliku wynikowego. Przykład (już omawiany ale zmodyfikowany!) <xsl:template name="liczby"> <xsl:param name="index" select="$start"/> <xsl:if test="$index < $stop+1"> <span><xsl:value-of select="$index"/></span> <xsl:text>,</xsl:text> <xsl:call-template name="liczby"> <xsl:with-param name="index" select="$index+1"/> </xsl:call-template> </xsl:if>
<xsl:text> Usuńmy jeszcze ostatni przecinek <xsl:template name="liczby"> <xsl:param name="index" select="$start"/> <xsl:if test="$index < $stop+1"> <span><xsl:value-of select="$index"/></span> <xsl:if test="$index!=$stop"> <xsl:text>,</xsl:text> </xsl:if> <xsl:call-template name="liczby"> <xsl:with-param name="index" select="$index+1"/> </xsl:call-template> </xsl:if>
<xsl:text> I jeszcze jedna modyfikacja <xsl:template name="liczby"> <xsl:param name="index" select="$start"/> <xsl:if test="$index < $stop+1"> <span><xsl:value-of select="$index"/></span> <xsl:if test="$index=$stop"> <xsl:text>,</xsl:text> </xsl:if> <xsl:call-template name="liczby"> <xsl:with-param name="index" select="$index+1"/> </xsl:call-template> </xsl:if>