XSLT a JavaScript Autor: Petr Dvořák (http://joshis.iprofil.cz/) Úvod Dokumenty XML (můžeme rovnou říct, že narozdíl od dokumentů (X)HTML) nenesou žádnou informaci, která by prohlížeči sdělila, jakým způsobem se má ten či onen element zobrazit, jakou má mít text v daném elementu barvu, jaké má být použito písmo, či třeba jaká má být barva pozadí. Proto je do většiny moderních prohlížečů integrován takzvaný XSLT Processor. Ten zpracovává daný XML dokument spolu s tzv. XML Stylesheetem (XSL) a transformuje tak daný XML dokument např. do XHTML (nebo i do libovolného jiného XML dokumentu), čímž pomáhá prohlížeči konkretizovat vzhled jednotlivých částí XML dokumentu. Popis jazyka pro XSLT (XSLT je natolik silné, že je možno hovořit dokonce o programovacím jazyku) je mimo rámec tohoto textu. U čtenáře se v tomto směru předpokládá jistá základní erudice. Zmíníme jen, že XSLT je rovněž založeno na XML. Článek si klade za úkol vysvětlit mírně pokročilým tvůrcům webových aplikací, jak XSLT používat v prohlížečích právě pomocí JavaScriptu. V následujícím textu si ukážeme kusy zdrojových kódů, na kterých je možno XSLT transformaci otestovat. Potřebujeme tedy: XML soubor, který bude transformován XML Stylesheet kterým budeme transformovat JavaScript funkce XSLT pomocí JavaScriptu v Mozille (... Opeře a Safari) Prohlížeče z rodiny Mozilla používají (od verze 1.2) pro XML Transformace engine TransforMiiX. Pro používání XSLT v Mozille je nejprve nutné vytvořit objekt XSLTProcessor. Následně je nutno importovat do tohoto objektu stylesheet voláním funkce importstylesheet(node). Parametr Node určuje uzel XML dokumentu, který obsahuje popis XML transformací. Ten je samozřejmě možno získat více způsoby - můžeme například XSLT dokument "sestavit na místě", načíst jej pomocí metody document.load("xmldoc.xml") nebo je i možné využít AJAX a dotázat se na responsexml (např. chceme-li dělat XML Transformace "za běhu", to znamená nejen po načtení stránky). My si zde ukážeme poslední jmenovaný postup, protože je pravděpodobně nejvíce obecný a je zároveň nejčastěji uváděn v jiných tutoriálech. Pro provedení transformace samotné máme k dispozici dvě metody objektu typu XSLTProcessor. Metoda XSLTProcessor::transformToDocument(xmlfile_xml) přijímá jeden argument a tím je XML dokument, který chceme transformovat pomocí importovaného XML stylesheetu a jako výsledek vrací celý DOM dokument. Metoda XSLTProcessor::transformToFragment(xmlfile_xml, ownerobj) vrací "pouze" DOM DocumentFragment Node, který se může následně připojit k jinému dokument objektu. Proto tato metoda přijímá ještě druhý parametr, který tento objekt specifikuje (každý fragment musí patřit dokumentu). Metoda transformtofragment je tedy o něco obecnější a je proto v mnoha případech vhodnější. Samozřejmě si musíme také načíst XML dokument, který chceme transformovat. Celý níže uvedený kód zavoláme například při načtení elementu body, tedy <body onload="transform()">.
Nezapomínejme, že tento kód nefunguje v prohlížeči Internet Explorer! function Transform(xsltFile, xmlfile, wheretowrite) { // not for IE!!! // Vytvorime objekt XSLTProcessor var xsltproc = new XSLTProcessor(); // Vytvorime objekt pro HTTP zadosti var xmlhttp = new XMLHttpRequest(); // Ziskame XML dokument s popisem transformaci xmlhttp.open("get", xsltfile, false); xmlhttp.send(null); var xslstylesheet = xmlhttp.responsexml; // Importujeme stylesheet xsltproc.importstylesheet(xslstylesheet); // Nacteme XML soubor ktery chceme transformovat xmlhttp.open("get", xmlfile, false); xmlhttp.send(null); var xmldoc = xmlhttp.responsexml; // Provedene transformaci XML dokumentu // Tento kod je ekvivalentni volani transformtodocument var fragment = xsltproc.transformtofragment(xmldoc, document); // Zapiseme do elementu s id=wheretowrite document.getelementbyid(wheretowrite).appendchild(fragment); Více informací lze najít na stránkách Mozilly na stránce: Using the Mozilla JavaScript interface to XSL Transformations http://developer.mozilla.org/en/docs/using_the_mozilla_javascript_interface_to_xsl_transformations XSLT v MS Internet Exploreru 7 Přístup k XML Transformacím je v MS Internet Exploreru oproti Mozille poněkud odlišný - XSLT je součástí MSXML (Microsoft XML Core Services). Nejjednodušší způsob (uvedený na MSDN), jak používat XSLT v prohlížeči IE je upravit funkci Transform do níže uvedené podoby (ostatní soubory můžeme nechat tak jak jsou). Využíváme zde ActiveX objekty pro vytvoření XML HTTP requestů. Důležitá je zde především metoda transformnode(xslt), která transformuje XML uložené v srctree pomocí stylesheetu načteného v xslttree. Toto řešení funguje pouze v Internet Exploreru (testováno bylo ve verzi 7). function Transform(xsltFile, xmlfile, wheretowrite) { // just for IE!!! // vytvorime XMLHTTP Request pro XML var srctreexmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); srctreexmlhttp.open("get", xmlfile, false); srctreexmlhttp.send(null); // Ulozime zdrojove XML srctree = srctreexmlhttp.responsexml; // Vytvorime XMLHTTP Request pro XSLT var xslttreexmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); xslttreexmlhttp.open("get", xsltfile, false); xslttreexmlhttp.send(null);
// Ulozime transformace (XSLT) xslttree = xslttreexmlhttp.responsexml; // Zapiseme transformovany XML kod document.getelementbyid(wheretowrite).innerhtml = srctree.transformnode(xslttree); Více informací lze najít na stránkách Microsoftu na stránce: XSLT for MSXML http://msdn.microsoft.com/en-us/library/ms759204.aspx Implementace fungující jak v IE tak v Mozille a Opeře Asi je přirozené, že řešení které funguje pouze v jednom ze dvou majoritních prohlížečů není příliš zajímavé. Proto se pokusím napsat řešení, které funguje v obou prohlížečích. De facto si rozdělíme celý kód na dva případy dle prohlížečů. Takto provedeme transofrmaci nezávisle na prohlížeči. Ve skriptu nejprve získáme XML dokument, který budeme chtít transformovat, poté soubor s XSLT a nakonec provedeme transformaci samotnou. function Transform(xsltFile, xmlfile, wheretowrite) { var xmlhttp; var xslthttp; if (window.xmlhttprequest) { // Mozilla + Opera + Safari xmlhttp = new XMLHttpRequest(); xslthttp = new XMLHttpRequest(); else if (window.activexobject) { try { // MSIE 6+ xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); xslthttp = new ActiveXObject("Msxml2.XMLHTTP"); catch (e) { try { // MSIE 5.5+ xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); xslthttp = new ActiveXObject("Microsoft.XMLHTTP"); catch (e) { return false; else return false; xmlhttp.open("get", xmlfile, false); xmlhttp.send(null); var XML = xmlhttp.responsexml; xslthttp.open("get", xsltfile, false); xslthttp.send(null); var XSLT = xslthttp.responsexml; var xsltproc; if (typeof XSLTProcessor!= "undefined") { xsltproc = new XSLTProcessor(); xsltproc.importstylesheet(xslt); var fragment = xsltproc.transformtofragment(xml, document); document.getelementbyid(wheretowrite).appendchild(fragment); else { document.getelementbyid(wheretowrite).innerhtml = XML.transformNode(XSLT);
Tento kód byl otestován a funkční v MS IE 7, Mozilla Firefox 2, Opera 9, Safari 3 for Windows. Nefunguje v prohlížeči Konqueror (Linux). Využití: Zobrazování cizích RSS kanálů na svých stránkách Výše uvedený kód je možno upravit tak, aby (za předpokladu správného nastavení serveru) posloužil ke zobrazování cizích RSS kanálů na stránkách. Je však nutno přenést část úkolů spojených se získáváním RSS kanálu na server-side skriptování, například v PHP. Není totiž možné (z bezpečnostních důvodů) volat metodu XMLHTTPRequest::open (ale ani třeba document::load) do jiné než vlastní domény. Zde si ukážeme pouze nejjednodušší možný skript (rss.php), průměrně zdatný PHP kodér si skript odpovídajícím způsobem upraví. // Soubor: rss.php // Posilani obsahu RSS kanalu jako XML header("content-type: Text/xml"); $rss = "http://www.zive.cz/default.aspx?server=1§ion=47&rss=1"; echo file_get_contents($rss); Tento skript dělá následující: na serveru se pomocí funkce file_get_contents stáhne obsah RSS kanálu a ten se pomocí funkce header odešle jako Mime-type Text/XML (je samozrejmě možné specifikovat i kódování znaků). Máme tedy skript uložený na našem serveru, který posílá RSS obsah, získaný pomocí server-side skriptování z jiné domény. Nyní je tedy možno použít upravenou metodu UniversalTransform() (XMLHTTPRequest::open už projde, skript rss.php, který posílá obsah RSS kanálu ve formě XML, je u nás na doméně) - stačí jako soubor xmlfile zadat "rss.php". Samozřejmě je nutné použít vhodný XSLT stylesheet, jendoduchý si můžete zkopírovat níže...
<?xml version="1.0" encoding="iso-8859-2"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/xsl/transform"> <xsl:output method="html" omit-xml-declaration="no" indent="yes" encoding="utf-8" media-type="text/xml; charset=utf-8" /> <xsl:template match="rss/channel"> <html> <head> <title> <xsl:value-of select="title"/> - <xsl:value-of select="lastbuilddate"/> </title> </head> <body> <div id="obsah"> <h1 class="rss_channel"> <a> <xsl:attribute name="href"> <xsl:value-of select="link"/> <xsl:attribute name="onclick"> <xsl:text> return!window.open(this.href); </xsl:text> <xsl:value-of select="title"/> </a> </h1> <p> <xsl:value-of select="description" disable-output-escaping="yes"/> </p> <hr /> <xsl:for-each select="//item"> <span class="rss_topic"> <xsl:attribute name="title"> <xsl:value-of select="pubdate"/> <a> <xsl:attribute name="href"> <xsl:value-of select="link"/> <xsl:attribute name="onclick"> <xsl:text> return!window.open(this.href); </xsl:text> <xsl:value-of select="title"/> </a> </span> <p class="rss_description"> <xsl:value-of select="description" disable-output-escaping="yes"/> </p> </xsl:for-each> </div> </body> </html> </xsl:template> </xsl:stylesheet>