31 mars 2003

Comment écrire une boucle 'for' en XSL ?

Il n'est pas possible, nativement, de faire des boucles "For" ou des boucles "While" en XSL.
Rappelons que le XSL n'est pas un langage de programmation, mais un langage de template, son but est donc de manipuler des données.

Bien cela-dit il est quand même parfois utile de faire des boucles, alors voilà 2 méthodes :

  • la première consiste à utiliser des extensions XSL, vous trouverez plus d'informations 1
  • la seconde consiste à les écrire d'une autre manière. Comment ?

mais récursivement bien sûr !

La boucle suivante en C :


for(i = 0; i < 10; i++) {
 
    printf("Comptons %d \n", i);

}

Donnera en XSL un template :


   <xsl:template name="bouclefor">
    <xsl:param name="min"></xsl:param>
    <xsl:param name="max"></xsl:param>

    Comptons <xsl:value-of select="$min"></xsl:value-of>

    <xsl:if test="number($min) &lt; number($max - 1)">
      <xsl:call-template name="bouclefor">
        <xsl:with-param name="min">
          <xsl:value-of select="$min + 1"></xsl:value-of>
        </xsl:with-param>
        <xsl:with-param name="max">
          <xsl:value-of select="$max"></xsl:value-of>
        </xsl:with-param>
      </xsl:call-template>
    </xsl:if>

  </xsl:template>

que l'on appellera de la sorte :

 

  <xsl:template match="/">
      <xsl:call-template name="bouclefor">
        <xsl:with-param name="min">0</xsl:with-param>
        <xsl:with-param name="max">10</xsl:with-param>
      </xsl:call-template>
  </xsl:template>

28 mars 2003

Comment exécuter du PHP dans un script shell (sh, bash, ksh, etc...) ?

PHP est un langage tellement pratique qu'on souhaite parfois l'utiliser pour écrire des scripts batchs. Cela ne pose, bien évidement, aucun problème. Cependant, on se trouve rapidement confronté à des problèmes d'environnement. Pour palier à ce problème on crée, généralement, un petit script sh qui se chargera d'exécuter le script PHP.

Une solution plus élégante existe, elle consiste à mettre le code PHP dans le fichier de script sh. Oui c'est possible !

L'exemple suivant nous montre comment faire :

#!/bin/sh
export TRUC="Salut"
exec /usr/bin/php -C -q -d output_buffering=1 $0 $@
<?php
ob_end_clean();
ob_implicit_flush(true);

echo getenv('TRUC');

26 mars 2003

Comment transformer du HTML en XML ?

Pour cela il suffit d'utiliser l'utilitaire tidy

En fait ce petit utilitaire, disponible sur de très nombreuses plateformes, permet de nettoyer ou transformer facilement un document HTML.

Avec seulement quelques options, on peut ainsi transformer un fichier HTML en un fichier XML.

Par exemple, la commande suivante permet d'obtenir en XML, son fichier bookmark Mozilla.

tidy --output-xml yes      --char-encoding utf8      < bookmarks.html      > bookmarks.xml

25 mars 2003

Comment changer les couleurs de la commande ls ?

En ligne de commande, lorsque l'on exécute la commande ls, celle-ci colorie différemment les fichiers, les répertoires ...
Cette fonction est très pratique, elle permet d'identifier rapidement un lien symbolique, ou un fichier .bak etc...

Cependant les couleurs attribuées par défaut peuvent être peu harmonieuse avec le fond d'écran de votre terminal.
Rassurez on peut modifier tout ça.

Pour cela vous devez ajouter cette ligne dans votre fichier .bashrc

eval `/usr/bin/dircolors -b ~/.dircolors`

Ensuite il vous faut définir un fichier .dircolors dans votre répertoire personnel. Voyons comment constituer ce fichier :

Premièrement, on définit l'ensemble des terminaux capables d'afficher des couleurs :

TERM linux
TERM console
TERM con132x25
TERM con132x30
TERM con132x43
TERM con132x60
TERM con80x25
TERM con80x28
TERM con80x30
TERM con80x43
TERM con80x50
TERM con80x60
TERM xterm
TERM vt100
TERM xterm-xfree86

Deuxièmement, on définit les couleurs pour chaque type de fichier :

NORMAL 00       # tout sauf ce qui suit
FILE 00         # un fichier
DIR 01;35       # un répertoire
LINK 01;36      # un lien symbolique
FIFO 40;33      # pipe
SOCK 01;34      # une socket
BLK 40;33;01    # un bloc de périphérique
CHR 40;33;01    # un caractère de périphérique
ORPHAN 40;31;01 # lien symbolique sans destination
EXEC 01;32      # un fichier exécutables

Troisièmement, on définit les couleurs par extension :

*~    07;31 # Des fichiers inutiles ???
*.bak 07;31
*.old 07;31
.cmd 01;32  # Des exécutables window$ 
.exe 01;32
.com 01;32
.btm 01;32
.bat 01;32
.c   00;36  # Des fichiers sources
.h   00;36
.pl  00;36
.php 00;36
.pm  00;36
.cgi 00;36
.java 00;36
.html 00;36
.tar 01;31  # Des archives
.tgz 01;31
.arj 01;31
.taz 01;31
.lzh 01;31
.zip 01;31
.z   01;31
.Z   01;31
.gz  01;31
.jpg 01;35  # Des images
.jpeg 01;35
.JPG 01;35
.gif 01;35
.GIF 01;35
.bmp 01;35
.BMP 01;35
.xbm 01;35
.ppm 01;35
.xpm 01;35
.tif 01;35

On remarque que les couleurs sont désignés par un ensemble de 2 ou trois nombre séparés par des ';'.

En effet ce la correspond à :
Style d'écriture;Couleur du crayon; Couleur du fond

Les styles d'écriture possibles sont :

00
01 bold
04 underscore
05 blink
07 reverse
08 concealed

Les couleurs du crayon possibles sont :

30 black
31 red
32 green
33 yellow
34 blue
35 magenta
36 cyan
37 white

Les couleurs du crayon possibles sont :

40 black
41 red
42 green
43 yellow
44 blue
45 magenta
46 cyan
47 white

24 mars 2003

Comment écrire une requête récursive avec MySQL ?

Une représentation hiérarchie dans une table consiste à stocker pour chaque enregistrement l'identifiant de son père.

Par exemple pour représenter cette hiérarchie :

  • Europe
    • France
      • Lorraine
      • Alsace
    • Allemagne
      • Ruhr
      • Saar

On utilisera une table de ce style :

id libelle id_pere
1 Europe -
2 France 1
3 Allemagne 1
4 Alsace 2
5 Lorraine 2
6 Ruhr 3
7 Saar 3

Maintenant comment récupérer cette hiérarchie ? A ce que je sache, actuellement avec MySQL?, on ne peut pas le faire en une seule requête SQL (contrairement à ORACLE). Par conséquence, il nous faut ruser en utilisant une fonction récursive.

En PHP cela nous donne :

<?php

function select_recursif($id_pere = null)
{
  $rows = array();
  $i = 0;
  $requete = "SELECT * FROM matable WHERE id_pere";
  $requete .= ($id_pere == null) ? ' is null' 
                                 : ' = '.$id_pere;
  $res = $GLOBALS['db']->query($requete);
  while ($row = $res->fetchRow(DB_FETCHMODE_ASSOC)) {
    $rows[$i] = $row;
    $rows[$i]['fils'] = select_recursif($row['for_idt']);
    ++$i;
  }
  $res->free();

  return ((!$i) ? null : $rows);
}

require_once('DB.php');

$db = DB::connect('mysql://root:@localhost/mabase', true);
if (DB::isError($db)) die($db->getMessage());

print_r (select_recursif());

?>

20 mars 2003

Comment afficher l'arborescence d'un répertoire ?

En ligne de commande Unix/Linux, il est parfois utile de visulaliser l'arborescence d'un répertoire. Certe il existe la commande "ls -R" cependant on peut mieux faire...

Voici petit script qui sera toujours utile :


#!/bin/sh
dir=${1:-.}
cd ${dir};
pwd
find ${dir} -type d -print |      sort -f |      sed -e "s,^${dir},,"          -e "/^$/d"          -e "s,[^/]*/\([^/]*\)$,\`-----\1,"          -e "s,[^/]*/, |     ,g";

Il génèrera un affichage de ce style :

touv@localhost% treeview
/users/touv
`-----.autosave
`-----.dt
 |     `-----help
 |     `-----sessionlogs
 |     `-----sessions
 |      |     `-----home
`-----.elm
`-----.emacs.d
 |     `-----auto-save-list
`-----.ssh
`-----bin
`-----Mail
`-----private_html
 |     `-----apache
 |     `-----cgi-bin
 |     `-----htdocs
 |     `-----logs
touv@localhost% 

19 mars 2003

Comment supprimer les espaces de noms dans un document XML ?

Les espaces de noms en XML sont pratiques, cependant dans certain cas, on s'en passerait bien. Surtout si, dans un même document, plusieurs parties sont définies par des espaces de noms différents.

Prenons l'exemple suivant :

<?xml version='1.0' encoding='utf-8'?>
<truc1 
 xmlns="http://www.exemple.com/truc1/">
 <test1>XXX</test1>
  <truc2 
   xmlns="http://www.exemple.com/truc1/">
   <test2>XXX</test2>
  </truc2>
  <truc3 
    xmlns="http://www.exemple.com/truc1/">
    <test3>XXX</test3>
  </truc3>
</truc1>    

Maintenant si on souhaite obtenir ce document :

<?xml version='1.0' encoding='utf-8'?>
<truc1>
 <test1>XXX</test1>
  <truc2>
   <test2>XXX</test2>
  </truc2>
  <truc3>
    <test3>XXX</test3>
  </truc3>
</truc1>

Il suffit d'appliquer la feuille xsl suivante. Celle-ci se chargera de supprimer les "namespaces".


<?xml version="1.0"?>
<xsl:stylesheet 
 version="1.0" 
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output 
   omit-xml-declaration="yes" 
   method="xml" 
   indent="no"/>
  <xsl:template match="*">
    <xsl:element name="{name()}">
      <xsl:apply-templates select="@*"/>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>
  <xsl:template match="@*">
    <xsl:if test="local-name() = name()">
      <xsl:copy/>
    </xsl:if>
  </xsl:template>
  <xsl:template match="text()">
    <xsl:copy>
      <xsl:apply-templates/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match="comment()"/>
</xsl:stylesheet>

18 mars 2003

En ligne de commande, comment substituer une chaine par une autre dans plusieurs fichiers ?

Autant le dire tout de site, il n'existe pas de commande magique permettant de réaliser une substitution sur plusieurs fichiers de manière simplet et interactive.

Cela dit, rien n'est perdu pour autant, les commandes Unix/Linux sont suffisamment riches pour réaliser un petit script qui fera l'affaire.

En voici un parmi tant d'autres :

#!/bin/sh

echo "Repertoire:"
ead -r LECHEMIN
echo "Dans fichiers/types:"
read -r LESTYPES
echo "Rechercher:"
read -r SEARCH
echo "Remplacer avec:"
read -r REPLACE

if [[ ! -d ${LECHEMIN} ]]
    then
    echo "Repertoire [$LECHEMIN] incorrect"
    exit 1
fi
if [[ -z ${LESTYPES} ]]
    then
    echo "Fichiers/Types vide"
    exit 2
fi
if [[ -z ${SEARCH} ]]
    then
    echo "Masque de Recherche vide"
    exit 3
fi
if [[ -z ${SEARCH} ]]
    then
    echo "Masque de Remplacement vide"
    exit 4
fi

lesfichiers=`find ${LECHEMIN} -name "${LESTYPES}"`
for fichier in $lesfichiers;
  do
  cat $fichier | sed s/${SEARCH}/${REPLACE}/g > $fichier.s
  if [[ ${?} -eq 0 ]]
      then
      mv $fichier.s $fichier
      echo "Replace in $fichier"
  fi
done;

exit 0;

17 mars 2003

Comment gérer plusieurs langues en XSL ?

Biensûr il existe plusieurs méthodes pour répondre à cette question. Pour en avoir tester plusieurs, je vais vous présenter celle qui me semble la plus élégente.

Tout d'abord, nous allons isoler dans un fichier tous les termes devant être traduits. Nous appellerons ce fichier "messages.xml"


<?xml version="1.0" encoding="ISO-8859-1"?>
<messages>
     <message name="a" xml:lang="fr">Bonjour</message>
     <message name="a" xml:lang="en">Hello</message>
</messages>

Ensuite il nous faut déclarer le fichier contenant les traductions:


<xsl:variable name="messages" select="document('messages.xml')/messages"/>

Il faut, également, déclarer un template permettant d'utiliser le fichier de termes.


<xsl:param name="lang">fr</xsl:param>

<xsl:template match="message">
     <xsl:if test="lang($lang)">
          <xsl:value-of select="."/>
     </xsl:if>
</xsl:template>

Enfin il ne reste plus qu'à remplacer chaque terme par un appel au template précédent pour avoir une feuille XSL multi-langue.


<xsl:apply-templates select="$messages/message[@name='a']"/>