position
Techniques : XML
XSLT

Language de Style de Transformations

Le langage XSLT permet de transformer un document XML en un autre.

Par exemple, un document correspondant à un schema personnalisé peut être converti en html ou en smil.

Cette technique permet de générer des présentations multiples à partir d’une seule source de données.

Prenons l’exemple suivant :

Nous avons une source de données xml :

<Page xmlns="http://www.torrent-universe.com/schema/Page.xsd">
<Title>
<Paragraph Language="English">XML Schema</Paragraph>
<Paragraph Language="French">Schémas XML</Paragraph>
</Title>
<Subtitle>
<Paragraph Language="English">Custom XML Namespaces</Paragraph>
<Paragraph Language="French">Création de languages XML Personnalisés</Paragraph>
</Subtitle>
<Abstract>
<Paragraph Language="English">XML Schemas provide a means for defining the structure, content and semantics of XML documents.</Paragraph>
<Paragraph Language="French">Les schémas XML permettent de définir des structures de documents XML.</Paragraph>
</Abstract>
<Body>
<Paragraph Language="English">This document complies with the “http://www.torrent-universe.com/schema/Page.xsd” namespace.</Paragraph>
<Paragraph Language="French">Ce document repecte la définition “http://www.torrent-universe.com/schema/Page.xsd”.</Paragraph>
</Body>
</Page>

et la feuille de style xsl :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/TR/xhtml1" xmlns:p="http://www.torrent-universe.com/schema/Page.xsd">
<xsl:output method="xml" encoding="utf-8" version="1.0" omit-xml-declaration="no" media-type="text/xml" indent="yes"/>
<xsl:variable name="Language">English</xsl:variable>
<xsl:template match="/">
<html xmlns="http://www.w3.org/TR/xhtml1">
<xsl:apply-templates select="child::p:Page" mode="htmlDocument"/>
</html>
</xsl:template>
<xsl:template match="p:Page" mode="htmlDocument">
<head>
<xsl:apply-templates select="child::p:Title" mode="htmlTitle"/>
<link rel="stylesheet" type="text.css" href="page.css"/>
</head>
<body>
<div class="PageContent">
<xsl:apply-templates select="child::p:Title" mode="htmlBody"/>
<xsl:apply-templates select="child::p:Subtitle" mode="htmlBody"/>
<xsl:apply-templates select="child::p:Abstract" mode="htmlBody"/>
<xsl:apply-templates select="child::p:Body" mode="htmlBody"/>
</div>
</body>
</xsl:template>
<xsl:template match="p:Title" mode="htmlTitle">
<title>
<xsl:value-of select="child::p:Paragraph[@Language = $Language]"/>
</title>
</xsl:template>
<xsl:template match="p:Title|p:Subtitle|p:Abstract|p:Body" mode="htmlBody">
<div>
<xsl:attribute name="class">
<xsl:value-of select="local-name()"/>
</xsl:attribute>
<xsl:apply-templates select="child::p:Paragraph[@Language = $Language]" mode="htmlBody"/>
</div>
</xsl:template>
<xsl:template match="p:Paragraph" mode="htmlBody">
<p>
<xsl:apply-templates select="child::text()" mode="htmlBody"/>
</p>
</xsl:template>
<xsl:template match="text()" mode="htmlBody">
<xsl:value-of select="."/>
</xsl:template>
</xsl:stylesheet>

compiler les données xml à travers la feuille de style xslt donnera la résultat suivant :

<html>
<head>
<title>XML Schema</title>
<link rel="stylesheet" type="text.css" href="page.css"/>
</head>
<body>
<div class="PageContent">
<div class="Title">
<p>XML Schema</p>
</div>
<div class="Subtitle">
<p>Custom XML Namespaces</p>
</div>
<div class="Abstract">
<p>XML Schemas provide a means for defining the structure, content and semantics of XML documents.</p>
</div>
<div class="Body">
<p>This document complies with the “http://www.torrent-universe.com/schema/Page.xsd” namespace.</p>
</div>
</div>
</body>
</html>

Interprété par un navigateur web, le code html ci-dessus s´affichera comme suit :

XML Schema

XML Schema

Custom XML Namespaces

XML Schemas provide a means for defining the structure, content and semantics of XML documents.

This document complies with the “http://www.torrent-universe.com/schema/Page.xsd” namespace.

Voyons un exemple plus concret.

Imaginons que nous recevons une facture nécessitant d’additionner des pommes, des oranges et des bananes.

Les données proviennent d’un tier business ou d’un tier de données et sont présentées comme suit :

<order>
<invoice>
<item>
<name>apples</name>
<quantity>2</quantity>
</item>
<item>
<name>oranges</name>
<quantity>2</quantity>
</item>
<item>
<name>bananas</name>
<quantity>3</quantity>
</item>
</invoice>
<pricelist>
<item>
<name>apples</name>
<unitprice>3.00</unitprice>
</item>
<item>
<name>oranges</name>
<unitprice>4.00</unitprice>
</item>
<item>
<name>bananas</name>
<unitprice>5.00</unitprice>
</item>
</pricelist>
</order>

La section facture (“invoice”) est distincte de la section liste de prix (“pricelist”) car chacune peut provenir d’une source différente.

Pour convertir les données en tableau html, nous avons besoin d’un modèle xslt :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns="http://www.w3.org/1999/xhtml">
<xsl:preserve-space elements="span"/>
<xsl:output method="xml" version="1.0" encoding="utf-8" omit-xml-declaration="no" media-type="text/html" indent="yes"/>
<xsl:template match="/">
<html>
<head>
<title>invoice</title>
<style type="text/css">td.number{text-align:right}</style>
</head>
<body>
<xsl:apply-templates select="//invoice" mode="table"/>
</body>
</html>
</xsl:template>
<xsl:template match="invoice" mode="table">
<table class="invoice">
<tr>
<th>Product</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Price</th>
</tr>
<xsl:apply-templates select="item" mode="table"/>
<tr class="total">
<td colspan="3">total</td>
<td class="number">
<xsl:apply-templates select="self::invoice" mode="total"/>
</td>
</tr>
</table>
</xsl:template>
<xsl:template match="item" mode="table">
<xsl:variable name="UnitPrice">
<xsl:apply-templates select="self::item" mode="unitprice"/>
</xsl:variable>
<xsl:variable name="Price">
<xsl:apply-templates select="self::item" mode="price"/>
</xsl:variable>
<tr>
<xsl:apply-templates select="name" mode="table"/>
<td class="number">
<xsl:value-of select="format-number(number(quantity), '#,###')"/>
</td>
<td class="number">
<xsl:value-of select="format-number(number($UnitPrice), '#,###.00')"/>
</td>
<td class="number">
<xsl:value-of select="format-number(number($Price), '#,###.00')"/>
</td>
</tr>
</xsl:template>
<xsl:template match="item/name" mode="table">
<td>
<xsl:value-of select="."/>
</td>
</xsl:template>
<xsl:template match="invoice" mode="total">
<script language="JavaScript">
<xsl:text>var numTotal = new Number(0);</xsl:text>
<xsl:for-each select="item"> numTotal +=
<xsl:apply-templates select="self::item" mode="price"/>;
</xsl:for-each>
<xsl:text>document.write(parseInt(numTotal) + "." + parseInt((numTotal - parseInt(numTotal)) * 10) + "" + parseInt((numTotal - parseInt(numTotal)) * 100 - parseInt((numTotal - parseInt(numTotal)) * 10)));</xsl:text>
</script>
</xsl:template>
<xsl:template match="item" mode="unitprice">
<xsl:variable name="ItemName">
<xsl:value-of select="name"/>
</xsl:variable>
<xsl:value-of select="number(//pricelist/item[name = $ItemName]/unitprice)"/>
</xsl:template>
<xsl:template match="item" mode="price">
<xsl:variable name="ItemQuantity">
<xsl:value-of select="number(quantity)"/>
</xsl:variable>
<xsl:variable name="ItemUnitPrice">
<xsl:apply-templates select="." mode="unitprice"/>
</xsl:variable>
<xsl:value-of select="number($ItemQuantity) * number($ItemUnitPrice)"/>
</xsl:template>
</xsl:stylesheet>

Le code html résultant est :

<html>
<head>
<title>invoice</title>
<style type="text/css">td.number{text-align:right}</style>
</head>
<body>
<table class="invoice">
<tr>
<th>Product</th>
<th>Quantity</th>
<th>Unit Price</th>
<th>Price</th>
</tr>
<tr>
<td>apples</td>
<td class="number">2</td>
<td class="number">3.00</td>
<td class="number">6.00</td>
</tr>
<tr>
<td>oranges</td>
<td class="number">2</td>
<td class="number">4.00</td>
<td class="number">8.00</td>
</tr>
<tr>
<td>bananas</td>
<td class="number">3</td>
<td class="number">5.00</td>
<td class="number">15.00</td>
</tr>
<tr class="total">
<td colspan="3">total</td>
<td class="number">
<script language="JavaScript">var numTotal = new Number(0); numTotal += 6; numTotal += 8; numTotal += 15; document.write(parseInt(numTotal) + "." + parseInt((numTotal - parseInt(numTotal)) * 10) + "" + parseInt((numTotal - parseInt(numTotal)) * 100 - parseInt((numTotal - parseInt(numTotal)) * 10)));</script>
</td>
</tr>
</table>
</body>
</html>

Interprété par un navigateur Internet, ce code html a la forme suivante :

invoice
ProductQuantityUnit PricePrice
apples23.006.00
oranges24.008.00
bananas35.0015.00
total

Conclusion: les transformations XSLT peuvent devenir assez complexes car le langage implémente de nombreuses fonctionalités.

Toutefois, quiconque obtient des résultats semblables en manipulant des chaînes de caractères comme “response.write("<td>"+strPrice+"</td>")” ou en utilisant le dom comme “elTableRow.appendChild(elTableCell)”, trouvera le XSLT plus simple et plus facile à débuguer.

XSLT · Informations Complémentaires :

Recommandation w3
Le XSLT vu par Microsoft