home_site

Lab04 - XSL i XSLT [ ver. TI.2025.10.22.004 ]

Zawartość strony

Plan zajęć

Transformacja dokumentów XML - XSLT

Technologia XSLT [8,9,10,11,12] umożliwia transformację dokumentów XML z wykorzystaniem języka XSL [13].

Proces transformacji XSLT przedstawia poniższy algorytm [14]:

Na rys. 1 przedstawiono proces transformacji dokumentu XML w ramach serwisu WWW z wykorzystaniem styli XSL i pliku styli CSS.

Lab04_img01
Rys.2 Przykładowa strona dokumentu XML z arkuszem styli CSS

Do prezentacji technologii wykorzystamy dokument XML przedstawiony poniżej.

<?xml version="1.0" encoding="UTF-8" ?>
<dane>
  <osoba>
    <imie>Adam</imie>
    <nazwisko>Kowalski</nazwisko>
  </osoba>
  <osoba>
    <imie>Marek</imie>
    <nazwisko>Abacki</nazwisko>
  </osoba>
  <osoba>
    <imie>Andrzej</imie>
    <nazwisko>Babacki</nazwisko>
  </osoba>
</dane>

Odpowiedni dokument XSL transformujący dokument XML przedstawia wydruk poniżej. Dokument XSL składa się z dwóch szablonów. Pierwszy szablon dopasowywany jest do korzenia / dokumentu XML, natomiast drugi szablon dopasowywany jest do węzła student. Po uruchomieniu przetwarzania dokumentu XML przez procesor XSLT dopasowany jest korzeń dokumentu do pierwszego wzorca, którego zawartość przekierowana jest na zbiór wynikowy. W trakcie przetwarzania szablonu procesor znajduje polecenie <xsl:apply-templates select="dane" />, które przerywa działanie pierwszego wzorca i następuje wyszukiwanie węzłów dokumentu przy pomocy polecenia "xpath" zgodnie z definicją zawartą w atrybucie select, w tym przypadku węzła - elementu dane. Procesor przeszukuje kolejne węzły potomne dla węzła dane dokumentu XML i dopasowuje węzły do istniejących szablonów w dokumencie XSL - w naszym przypadku znajduje węzły osoba i realizuje drugi szablon. W ramach tego szablonu występuje polecenie <xsl:value-of select="węzeł" />, które pobiera zawartość wezła i przekierowuje na strumień wyjściowy. Atrybut select występujący w poleceniu jest obowiązkowy. Po znalezieniu wszystkich węzłów spełniających reguły procesor XSLT wraca od realizacji przerwanego szablonu.

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
<xsl:output method="html" version="1.0"  />
<xsl:template match="/">
        <html>
            <head>
                <title>
                    Tabela osob
                </title>
            </head>
            <body>
                <h1>
                    Lista osob
                </h1>
                <table border="1" cellpadding="5">
                    <tr>
                        <td>Imie</td>
                        <td>Nazwisko</td>
                    </tr>
                  <xsl:apply-templates select="dane" />
                </table>
            </body>
        </html>
</xsl:template>
<xsl:template match="osoba" >
  <tr>
   <td><xsl:value-of select="imie" /></td>
   <td><xsl:value-of select="nazwisko" /></td>
  </tr>
</xsl:template>
</xsl:stylesheet>

Transformację dokumentu XML do dokumentu wynikowego można wykonać z wykorzystaniem programów xsltproc [15] lub xmlstarlet [16] dostępnych na serwerze "pascal". Składnię odpowiednich poleceń przedstawiono poniżej.

xsltproc osoby.xsl osoby.xml
xmlstarlet tr osoby.xsl osoby.xml

Dokument XML można również przetworzyć z wykorzystaniem styli XSL przez przeglądarkę, które posiada wbudowany procesor XSLT. Wymagany jest wtedy odpowiedni wpis w dokumencie XML informujący przeglądarkę o lokalizacji arkuszy styli XSL.

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="osoby.xsl"?>
<!-- dalsza część dokumentu XML -->

W ramach funkcjonalności procesor XSLT umożliwia wykorzystanie funkcji sterujących i warunkowych, tworzenie definicji funkcji własnych czy realizowanie sortowania danych. Przykładowy kod XSL realizujący sortowanie danych przedstawia poniższy szablon umożliwiający posortowanie osób po nazwisku. Polecenie <xsl:for-each select="węzeł" /> tworzy iterator wyszukujący węzły znajdujące się w atrybucie select. Polecenie <xsl:sort select="węzeł" /> posortuje węzły wyszukiwane przez iterator po zawartości węzła znajdującego się w atrybucie select.

<xsl:template match="dane" >
  <xsl:for-each select="//osoba" >
  <xsl:sort select="./nazwisko/text()" />
    <tr xmlns="http://www.w3.org/1999/xhtml" >
      <td><xsl:value-of select="nazwisko" /></td>
      <td><xsl:value-of select="imie" /></td>
    </tr>
  </xsl:for-each>
</xsl:template> 

Przykładowe przetwarzanie dokumentu XML z wykorzystaniem arkuszy XSL

Na potrzeby ćwiczenia wykorzytamy przedstawiony poniżej dokument XML zawierający listę studentów na trzech kierunkach.

Dokument XML - plik dok2.xml ( [listing dokumentu] [link do dokumentu] )

   <?xml version="1.0" ?>
<?xml-stylesheet type="text/xsl" href="test.xsl"?>
<wydzial>
	<kierunek>
		<nazwa>Informatyka Stosowana</nazwa>
		<student>
			<imie>Adam</imie>
			<nazwisko>Zawadzki</nazwisko>
			<rok>3</rok>
		</student>
		<student>
			<imie>Bogdan</imie>
			<nazwisko>Cabacki</nazwisko>
			<rok>1</rok>
		</student>
		<student>
			<imie>Aleksandra</imie>
			<nazwisko>Abacka</nazwisko>
			<rok>2</rok>
		</student>
		<student>
			<imie>Miroslaw</imie>
			<nazwisko>Dadacki</nazwisko>
			<rok>1</rok>
		</student>
		<student>
			<imie>Marek</imie>
			<nazwisko>Nanacki</nazwisko>
			<rok>5</rok>
		</student>
	</kierunek>
	<kierunek>
		<nazwa>Fizyka Techniczna</nazwa>
		<student>
			<imie>Ewa</imie>
			<nazwisko>Dadacka</nazwisko>
			<rok>4</rok>
		</student>
		<student>
			<imie>Karol</imie>
			<nazwisko>Ebacki</nazwisko>
			<rok>3</rok>
		</student>
		<student>
			<imie>Witold</imie>
			<nazwisko>Sabacki</nazwisko>
			<rok>1</rok>
		</student>
		<student>
			<imie>Adrian</imie>
			<nazwisko>Babacki</nazwisko>
			<rok>1</rok>
		</student>
		<student>
			<imie>Anna</imie>
			<nazwisko>Kowalska</nazwisko>
			<rok>2</rok>
		</student>
	</kierunek>
	<kierunek>
		<nazwa>Fizyka Medyczna</nazwa>
		<student>
			<imie>Dominik</imie>
			<nazwisko>Lasek</nazwisko>
			<rok>1</rok>
		</student>
		<student>
			<imie>Katarzyna</imie>
			<nazwisko>Nanacka</nazwisko>
			<rok>2</rok>
		</student>
		<student>
			<imie>Edward</imie>
			<nazwisko>Lalacki</nazwisko>
			<rok>1</rok>
		</student>
		<student>
			<imie>Bogdan</imie>
			<nazwisko>Zawadzki</nazwisko>
			<rok>3</rok>
		</student>
		<student>
			<imie>Marcin</imie>
			<nazwisko>Tarski</nazwisko>
			<rok>2</rok>
		</student>
	</kierunek>
</wydzial>
  

Ćwiczenie 1 - lista wszystkich studentów

Do realizacji tego zadania zostanie wykorzystany dokument XSL (dok1.xsl) zawierający dwa szablony, pierwszy zostanie dopasowny do korzenia dokumentu XML, drugi natomiast będzie odczytywał zawartość węzłów student. Przetworzenie arkusza XSL przez procesor XSLT jest zgodne z wcześniej opisanym przypadkiem. W wyniku transformacji XSLT zostanie utworzony dokument HTML. Zawartość dokumentu HTML przedstawia dokument dok1.html.

Ćwiczenie 2 - posortowana lista studentów

Do realizacji tego zadania zostanie wykorzystany dokument XSL (dok2.xsl) zawierający dwa szablony, pierwszy zostanie dopasowny do korzenia dokumentu XML, drugi natomiast będzie szablonem nazwanym, który będzie odczytywał zawartość węzłów student. Tak jak poprzednio wzorzec pierwszy jest dopasowany do korzenia dokumentu XML. W ramach szablonu wykorzystano wcześniej omówioną funkcjonalność iteratora i polecenia sortującego (polecenia <xsl:for-each > i <xsl:sort />). Po znalezieniu odpowiednich węzłów następuje wywołanie szablonu nazwanego <xsl:call-template name="nazwa" />, gdzie "nazwa" jest nazwą szablonu. W ramach szablonu zostanie pobrana zawartość podelementów wybranego węzła. Wygenerowany dokument HTML przedstawia plik dok2.html.

Ćwiczenie 3 - posortowana lista studentów po roku studiów, nazwisku i imieniu

Do realizacji tego zadania zostanie wykorzystany dokument XSL (dok3.xsl) zawierający dwa szablony, pierwszy zostanie dopasowny do korzenia dokumentu XML, drugi natomiast będzie szablonem nazwanym, który będzie odczytywał zawartość węzłów student. Konstrukcja szablonów jest kopią ćwiczenia drugiego. Do sortowania studentów wykorzystamy jednak trzy polecenia <xsl:sort /> w żądanej kolejności sortowania. W ramach polecenia <xsl:sort /> umieszczono dodatkowy atrybut data-type, który dla sortowanych wartości numerycznych przyjmuje wartość "number" a dla wartości tekstowych "text". Zawartość dokumentu HTML przedstawia dokument dok3.html.

Ćwiczenie 4 - lista studentów na poszczególnych kierunkach

Do realiacji tego zadania zostanie wykorzystany dokument XSL (dok4.xsl) zawierajacy trzy szablony. Pierwszy szablon dopasowuje korzeń dokumentu XML, drugi dopasowuje kolejne wydziały, natomiast trzeci dopasowuje węzły student. W wyniku transformacji XSLT zostanie utworzony dokument HTML przedstawiony w dokumencie dok4.html

Ćwiczenie 5 - posortowana lista studentów na poszczególnych kierunkach

Do realizacji tego zadania zostanie wykorzystany dokument XSL (dok5.xsl) zawierajacy trzy szablony. Pierwszy szablon dopasowuje korzeń dokumentu XML, drugi dopasowuje kolejne wydziały, natomiast trzeci szablon nazwany pobiera zawartość węzła student. Kolejność wydziałów reprezentowana w dokumencie końcowym jest narzucona w szablonie drugim, gdzie w wyrażeniu ścieżkowym polecenia XPath, podany został predykat wybierający żądany wydział. Utworzony dokument HTML przedstawiono w dokumencie dok5.html

Wybrane polecenia języka XSL

<xsl:output method="" >
Polecenie formatujące wynikowy dokument. Dostępne atrybuty:
  • method - definiuje format dokumnetu wejściowego, dostępne wartości: {xml, text, html}
  • version - wymagany w przypadku gdy atrybut method = "html" lub "xml"
  • encoding - typ kodowania dokumentu wyjściowego
  • omit-xml-declaration -
  • doctype-public - ustawia wartość atrybutu PUBLIC w deklaracji DOCTYPE
  • doctype-system - ustawia wartość atrybutu SYSTEM w deklaracji DOCTYPE
<xsl:template match="" >
Najważnieszy element w technologii XSLT. Jest to szablon, który zostanie wykorzystany przez procesor po dopasowaniu wzorca znajdującego się w atrybucie "match" [17] zgodnego z językiem XPath do węzłów w dokumencie wejściowym. Szablon zostanie przesłany do dokumentu wyjściowego.
<xsl:apply-templates />
Zadania realizowane przez polecenie:
  • element apply-templates powoduje przerwanie bieżącego procesu przetwarzania w szablonie i wymuszenie na procesorze XSLT przejścia do potomków bieżącego wierzchołka;
  • procesor znajduje inny szablon, który służy do przetwarzania wierzchołków potomnych;
  • po przetworzeniu wezwanego szablonu XSLT powraca do macierzystego szablonu;
  • umożliwia to działanie rekurencyjne;
  • dostępny opcjonalny atrybut select umożliwia wskazanie wezłów.
<xsl:value-of select="" />
Zwraca zawartość węzła określonego przez XPath zawarte w atrybucie select.
<xsl:for-each select >
Po napotkaniu tego polecenia procesor XSLT przetwarza rekurencyjnie wszystkie węzły odpowiadające wzorcowi zawartemu w atrybucie select.
<xsl:sort select="" />
Polecenie umożliwia sortowanie węzłów wskazanych w atrybucie select. Reguły sortowania ustawiają dostępne atrybuty polecenia.
  • order - porządek sortowania, dostępne wartości: {ascending, descending};
  • lang - język, w którym następuje sortowanie;
  • data-type - określa czy sortujemy liczby czy litery, dostępne wartości: {text, number};
  • case-order - określa priorytet wielkości liter, dostępne wartości: {upper-first, lower-first}.

Grafika SVG w języku HTML5

  1. Trójkąt i okrąg w grafice SVG, pliki "dok6_1.html" i "dok6_1.css".
    • Plik dok6_1.html - ( [listing dokumentu] [link do dokumentu] [widok dokumentu])

      <!DOCTYPE html >
      <html>
         <head>
            <meta charset="utf-8" />
            <title>Trojkat</title>
            <link rel="stylesheet" href="dok6_1.css" type="text/css" media="all" />
        </head>
        <body>
            <div class="trojkat_svg_box">
            <svg encoding="utf-8"  id="svg" width="100%" height="100%" style="background-color:#000000;"  xmlns="http://www.w3.org/2000/svg">
               <!-- prostokat points = ( x1,y1, x1,y2, y2,x2, x2,y1 ) -->
               <polygon id ="tlo" points="0,0,0,500,500,500,500,0"  class="tlo"/>
               <!-- trojkat points = ( x1,y1, x2,y2, x3,y3 ) -->
               <polygon id ="trojkat" points="50.00,50.00,350.00,150.00,100.00,300.00" class="trojkat"/>
               <!-- kolo  cx = x, cy = y, R = r -->
               <circle id="kolo" cx="200" cy="200" r="141.42" fill="none" stroke="blue" stroke-width="1" class="kolo" />
               <circle id ="K" cx="200.00" cy="200.00" r="2" stroke="black" stroke-width="1" fill="black"/>
            </svg>
            </div>
        </body>
      </html>
        
    • Plik dok6_1.css - ( [listing dokumentu] [link do dokumentu] )

      /* lab4 */
      .trojkat_svg_box {
          text-align: center;
          width: 500px;
          height: 500px;
          border: none;
          float: left;
          margin: 10px;
      }
      .tlo{
      		pointer-events: none;
      		fill:white;
      		stroke:none
      }
      .trojkat{
      		fill:#cccccc;
      		stroke:#000000;
      		stroke-width:1;
      }
      .punkt{
      		stroke:black;
      		stroke-width:2;
      		fill:black;
      		pointer-events:all;
      		cursor: pointer;
      }
      
      /*
      .trojkat_svg {
          text-align: center;
          width: 500px;
          height: 500px;
          border: black solid 1px;
          float: left;
      }
      .xyz_input {
          width: 30px;
      }
      .naviation_panel {
          float: left;
          width: 200px;
          margin: 10px;
      }
      .legend {
          float: left;
          width: 700px;
          margin: 10px;
      }
      .opis {
          float: left;
          width: 700px;
          margin: 10px;
      }
      .wysokosci{
        	visibility: hidden;
      		stroke:green;
      		stroke-width:1;
      }
      .srodkowe{
      		visibility: hidden;
      		stroke:blue;
      		stroke-width:1;
      }
      .symetralne{
      		visibility: hidden; 
      		stroke:rgb(99,99,99);
      		stroke-width:1;
      }
      */  
  2. Dane XML, grafika SVG i transformacja XSLT, pliki "dok6_2.xml" i "dok6_2.xsl".
    • Plik dok6_2.xml - ( [listing dokumentu] [link do dokumentu] [widok dokumentu])

      <?xml version="1.0"?>
      <?xml-stylesheet href="dok6_2.xsl" type="text/xsl"?>
      <report>
        <title>Wyniki ankiety</title>
        <results>
          <row>
            <response n="1" title="wybor 1">100</response>
            <response n="2" title="wybor 2">10</response>
            <response n="3" title="wybor 3">56</response>
            <response n="4" title="wybor 4">5</response>
            <response n="5" title="wybor 5">45</response>
          </row>
        </results>
      </report>
        
    • Plik dok6_2.xsl - ( [listing dokumentu] [link do dokumentu] )

      <?xml version="1.0" encoding="utf-8"?>
      <xsl:stylesheet version="1.0" 
         xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
         xmlns="http://www.w3.org/1999/xhtml"
         xmlns:svg="http://www.w3.org/2000/svg">
      <xsl:output method="html" 
           version="1.0"
           indent="yes" 
           omit-xml-declaration = "yes"
           encoding="UTF-8"     
           doctype-system="about:legacy-compact" />
        <xsl:template match="/">                    
      
          <xsl:variable name="max">
            <xsl:for-each select="report/results/row/*">
              <xsl:sort select="." data-type="number" order="descending"/>
              <xsl:if test="position()=1">
                  <xsl:value-of select="."/>
              </xsl:if>
            </xsl:for-each>
          </xsl:variable>
      
          <svg width="650" height="500"
             xmlns="http://www.w3.org/2000/svg">
             <g id="axis" transform="translate(0 500) scale(1 -1)">
               <line id="axis-y" x1="30" y1="20" x2="30" y2="450" style="fill:none;stroke:rgb(0,0,0);stroke-width:2"/>
               <line id="axis-x" x1="30" y1="20" x2="460" y2="20"  style="fill:none;stroke:rgb(0,0,0);stroke-width:2"/>
             </g>  
        
             <xsl:for-each select="report/results/row">
               <g id="bars" transform="translate(30 479) scale(1 -430)">
                  <rect x="30"  y="0" width="50" height="{response[@n=1] div $max}"  style="fill:rgb(81,223,13);stroke:rgb(0,0,0);stroke-width:0"/>     
                  <rect x="100" y="0" width="50" height="{response[@n=2] div $max}"  style="fill:rgb(224,12,12);stroke:rgb(0,0,0);stroke-width:0"/>  
                  <rect x="170" y="0" width="50" height="{response[@n=3] div $max}"  style="fill:rgb(245,136,37);stroke:rgb(0,0,0);stroke-width:0"/>  
                  <rect x="240" y="0" width="50" height="{response[@n=4] div $max}"  style="fill:rgb(248,241,7);stroke:rgb(0,0,0);stroke-width:0"/>  
                  <rect x="310" y="0" width="50" height="{response[@n=5] div $max}"  style="fill:rgb(180,180,180);stroke:rgb(0,0,0);stroke-width:0"/>  
               </g> 
               <text id="choise-1" x="465px" y="92px"  style="fill:rgb(0,0,0);font-size:18;font-family:Arial">  
                 <xsl:value-of select="response[@n=1]/@title"/> (<xsl:value-of select="response[@n=1]"/>)</text>  
               <text id="choise-2" x="465px" y="112px"  style="fill:rgb(0,0,0);font-size:18;font-family:Arial">  
                 <xsl:value-of select="response[@n=2]/@title"/> (<xsl:value-of select="response[@n=2]"/>)</text>  
               <text id="choise-3" x="465px" y="132px"  style="fill:rgb(0,0,0);font-size:18;font-family:Arial">  
                 <xsl:value-of select="response[@n=3]/@title"/> (<xsl:value-of select="response[@n=3]"/>)</text>  
               <text id="choise-4" x="465px" y="152px"  style="fill:rgb(0,0,0);font-size:18;font-family:Arial">  
                 <xsl:value-of select="response[@n=4]/@title"/> (<xsl:value-of select="response[@n=4]"/>)</text>  
               <text id="choise-5" x="465px" y="172px"  style="fill:rgb(0,0,0);font-size:18;font-family:Arial">  
                 <xsl:value-of select="response[@n=5]/@title"/> (<xsl:value-of select="response[@n=5]"/>)</text> 
      
            </xsl:for-each>
            <g id="title">
               <text x="325px" y="30px"  style="text-anchor:middle;fill:rgb(0,255,0);font-size:32px;font-family:Arial">
                 <xsl:value-of select="report/title" />  </text>
            </g>      
          </svg>
       </xsl:template>
      </xsl:stylesheet>