Le blog de Lodel démanage sur Hypothèses

Le blog de Lodel déménage sur la plateforme Hypothèses.

Sa nouvelle adresse : http://lodel.hypotheses.org

Publication de Lodel 1.0 et OTX 1.0 !

Nous annonçons enfin la publication de Lodel 1.0 qui était en préparation à OpenEdition depuis plus de 2 ans !

Le changement majeur de Lodel 1.0 est l’utilisation du format XML TEI <http://www.tei-c.org> à la place du XML “R2R” non standard utilisé jusque-là. Ce changement de format XML va de paire avec le remplacement de l’application de conversion ServOO par OTX. Comme ServOO, OTX convertit des documents de traitement de texte stylés, mais le format de sortie est TEI. Ce passage à un standard XML permet l’import direct de XML dans Lodel, ce qui ouvre la porte à une utilisation du logiciel dans un environnement d’édition basé sur le Single Source Publishing.

Vous trouverez plus de détails sur les nouveautés dans les paragraphes suivants.

Lodel 1.0

Passage à GitHub

A l’occasion de la publication de Lodel 1.0, nous avons choisi de rejoindre GitHub pour la publication de Lodel. Nous pensons que cette plateforme, devenue incontournable, permettra un élargissement de la communauté des utilisateurs et contributeurs de Lodel.

La branche “master” du dépôt svn de sourcesup est synchronisée avec la branche “master” du dépôt GitHub et restera donc à jour. Les prochaines releases seront par contre disponibles uniquement sur GitHub.

Lodel 1.0 est donc disponible à l’adresse suivante : https://github.com/OpenEdition/lodel

La dernière version de Lodel est la version 1.0.1 que vous pouvez obtenir sur GitHub à cette adresse : https://github.com/OpenEdition/lodel/tree/v1.0.1 ou dans les pages GitHub du projet Lodel : http://openedition.github.io/lodel/ en téléchargement.

Nouveautés de Lodel 1.0

  • utilisation du format XML TEI comme format XML d’import au lieu de format XML R2R utilisé jusque là. Le logiciel de conversion qui remplace ServOO est OTX. Il produit donc des fichiers XML TEI compatibles avec Lodel. Il est également possible d’importer directement des documents au format XML.
  • réécriture de la gestion du cache.
  • ajout d’un système de hook qui permet d’exécuter une fonction à la validation d’un formulaire d’édition.
  • index mutualisés : permet de partager un index d’un site Lodel avec les autres sites de la même installation de Lodel.
  • qualification des relations entre entité et entrée d’index sur le modèle de ce qui existait précédemment entre entité et index de personnes.
  • sécurité d’édition concurrente : évite les pertes de données en cas d’édition d’un objet depuis plusieurs endroits simultanément.
  • nouveaux types de champs : MLdate, MLlongtext
  • réécriture de certains filtres.
  • ajout d’un mode debug pour afficher le code php résultat du parsing Lodelscript (paramètre showphp=true passé en get dans l’url)
  • ajout de fonctions de manipulation du modèle éditorial (dans lodel/install/scripts) : permet de scripter des modifications de modèle éditorial
  • ajout d’un script de nettoyage des sources non liées à une entité (dans lodel/install/scripts).
  • réécriture de la fonction de détection de la langue
  • abandon de pclzip et unzip au profit de ziparchive
  • abandon de MagPie RSS au profit de SimplePie
  • compatibilité php 5.3 et 5.4

Procédure de mise à jour de Lodel 0.9 à Lodel 1.0

Pour la mise à jour de 0.9 en 1.0, après avoir mis à jour le code de Lodel copier le fichier lodel/install/upgrade/1.0.0.php à la racine du site et accéder à ce fichier par le navigateur : http://mondomaine.com/monsite/1.0.0.php, suivre les instructions et vérifier que les requêtes ne sont pas erronées, puis valider l’exécution des requêtes en bas de page.

Une fois cette étape réalisée, il faut supprimer le fichier 1.0.0.php de la racine du site. Une fois cette étape faite pour chaque site, se rendre à la racine de l’installation de lodel, et exécuter tous les scripts présents dans le répertoire lodel/install/upgrade/ dans l’ordre sauf 1.0.0.php :
monserver:/var/www/lodel# php lodel/install/upgrade/1.0.1.php
monserver:/var/www/lodel# php lodel/install/upgrade/1.0.2.php
Lors de prochaines mises à jour, les scripts 1.0.* seront à exécuter de la même manière.

TEI OpenEdition

Le modèle éditorial publié avec Lodel 1.0 (me-revorg) est compatible avec le schéma TEI OpenEdition.

La documentation sur le format TEI est disponible sur le site de Lodel : http://www.lodel.org/701.

Le schéma XML W3C pour l’encodage TEI Openedition est disponible à l’adresse http://www.lodel.org/ns/. La documentation technique du schéma est consultable à l’adresse http://www.lodel.org/715.

Dans le cas d’une utilisation de Lodel avec import de documents stylés via OTX, les utilisateurs n’ont pas besoin d’aborder ces questions d’XML. OTX assure la conversion et l’interface avec Lodel.

OTX et Service de conversion

OTX

OTX est le logiciel de conversion doc/odt vers XML TEI utilisé par Lodel pour importer des documents de traitement de texte stylés. Il est diffusé sous licence GPL2, comme Lodel.

Il est disponible sur GitHub à l’adresse suivante : https://github.com/OpenEdition/OTX

La version actuelle est la version 1.0.1 : https://github.com/OpenEdition/OTX/tree/v1.0.1

L’installation est assez simple et bien documentée.

Une fois l’installation terminée, le script install/create_user.php permet la création d’un utilisateur OTX qu’il faut ensuite reporter dans la section OTX du fichier de configuration de Lodel lodelconfig.php

Limite connue

Le projet d’écriture de l’application OTX prévoyait une totale adaptabilité d’OTX au modèle éditorial de Lodel. En spécifiant des informations sous forme de XPath dans le modèle éditorial du site Lodel, OTX devrait être capable de convertir le document de traitement de texte stylé en XML TEI sur la base de ce XPath.

Concrètement, OTX n’est que partiellement dynamique. Certaines spécifications de XPath dans le modèle éditorial de Lodel sont prises en compte par OTX, d’autres non. La liste des cas non-reconnus n’est pas documentée. Nous avons choisi de publier Lodel 1.0 et OTX 1.0 malgré cette limite.

Nous prévoyons des améliorations mais sans calendrier pour le moment. OTX étant un logiciel libre, toute contribution est bienvenue.

Service de conversion

Parallèlement à la publication du code d’OTX, nous allons prochainement proposer le service web qui permettra de convertir vos fichiers de traitement de texte stylés. Ce service évite l’installation et la maintenance d’OTX sur votre serveur. Il pourra utiliser plusieurs serveurs de conversion en fonction des besoins pour une meilleure disponibilité.

Il sera gratuit pour un usage limité (publication d’une seule revue) et sera payant pour une utilisation plus importante. Cette contribution nous aidera à améliorer le logiciel et la fiabilité du service.

Autres points

Modèles de documents

Les modèles de documents pour Word et pour LibreOffice sont eux aussi versionnés dans le projet Lodel de GitHub.

Les dernières versions sont également téléchargeables sur le site de Lodel sur GitHub : http://openedition.github.io/lodel/

Documentation de Lodel

Nous prévoyons de reprendre la documentation de Lodel (actuellement dispersée : http://lodel.org, http://wiki.lodel.org, http://blog.lodel.org, SourceSup, GitHub) de manière plus concentrée sur le wiki de GitHub dans les prochaines semaines. Ce wiki pourra bien-sûr être enrichi par les utilisateurs. Nous vous tiendrons informés sur cette liste des prochaines évolutions.

Configuration pour l’utilisation de ServOO

Lodel (jusqu’à la version 0.9) utilise un serveur basé sur les technologies d’OpenOffice.org et Writer2LaTeX, appelé ServOO, qui lui permet de convertir des documents .DOC, .RTF et .SXW en XML. Ces documents peuvent contenir des images et des tableaux. La conversion de fichiers issus de traitements de texte grâce à ServOO permet d’éditer ses textes dans Word ou OpenOffice et de conserver ainsi un environnement de travail élaboré. L’ensemble des mises en forme (italiques, gras) et de la structuration du document (titres, citations, tableaux, notes de bas de page…) est récupéré, après nettoyage, par Lodel. Pour mettre à jour un document, il suffit de le corriger dans votre traitement de texte puis de le recharger via Lodel. Lodel s’appuie donc sur les compétences déjà acquises en traitements de textes.

Le service ServOO que nous mettons à disposition est disponible à l’url suivante : http://servoodevel.revues.org/

Vous devez créer un nouveau compte à l’aide du formulaire de création de compte accessible ici : http://servoodevel.revues.org/register.php

Vous devrez ensuite mettre à jour les paramètres ServOO (url, login, mot de passe) sur votre site Lodel. Ces paramètres se trouvent :

- soit dans l’onglet Administration->Options du site de votre site Lodel

- soit dans le fichier lodelconfig.php qui se trouve à la racine du répertoire d’installation de Lodel. Les paramètres à mettre à jour sont les suivants :

  • $cfg['servoourl']=”http://servoodevel.revues.org”;
  • $cfg['servoousername']=”";
  • $cfg['servoopasswd']=”";

en utilisant pour servoousername et servoopasswd les identifiants que vous aurez reçus après avoir créé votre compte ServOO.

 

Migration Lodel 0.9 vers Lodel 1.0

Contexte

L’installation multi-sites de Lodel 0.9 se trouve dans le répertoire /www/09 . Nous disposons également d’une installation multi-sites de Lodel 1.0 dans le répertoire /www/10 . Le nom des bases de données associées à cette version est préfixé par lodel10_ .

Il s’agit de migrer le site ASGB de la version 0.9 à la version 1.0 : le répertoire associé est /www/09/asgb, lodel09_asgb est la base de données associée.

Nous utilisons un espace de développement dont la structure est identique à celle de l’espace de production. Ceci nous semble indispensable, surtout si le nom des bases de données n’est pas préfixé par une chaîne de caractères liée au numéro de version.

Création du site sous Lodel 1.0

Elle commence par le blocage du site en production depuis l’interface Lodel 0.9. Puis nous vous conseillons de sauvegarder la base de données : mysqldump  lodel09_asgb  >  /data/tmp/lodel09_asgb.sql

Il faut ensuite sauvegarder les données 0.9 dans l’interface Lodel 0.9 et les copier sur l’espace de développement en 1.0 .

Le site est créé sur l’espace de développement : les fichiers sont situés dans /www/10/asgb et la base de données est lodel10_asgb . Une sauvegarde est souhaitable à ce niveau : mysqldump  lodel10_asgb  >  /data/tmp/asgb1.sql

Si le site a été migré depuis une version 0.7, il faut vérifier que les fichiers contenus dans le répertoire docannexe du site en production ont bien été copiés avec les données, en particulier le répertoire fichier.

Migration

Nous disposons donc sur l’espace développement de données en Lodel 0.9 sur une installation en Lodel 1.0.

Il faut copier le script de migration 1.0.0.php livré avec Lodel 1.0 (dans le répertoire lodel/scripts) dans le répertoire d’installation du site : cp  /www/10/lodel/install/upgrade/1.0.0.php   /www/10/asgb
L’exécution se fait dans le navigateur (en mode authentifié) : http://develserver.revues.org/10/asgb/1.0.0.php . A cette étape, le script affiche les commandes qu’il va lancer mais ne les exécute pas ; après vérification des requêtes proposées, il faut rechercher en bas de page le lien cliquable pour lancer l’exécution des requêtes.
Supprimer le fichier /www/10/asgb/1.0.0.php

Les données sont sauvegardées : mysqldump  lodel10_asgb  >  /data/tmp/asgb2.sql

Il reste à lancer les autres scripts 1.*.php  dans /www/10/lodel/install/upgrade en se plaçant dans le répertoire d’installation multi-sites dans notre cas /www/10 : php  lodel/install/upgrade/1.0.1.php puis php  lodel/install/upgrade/1.0.2.php

 

Migration lodel 0.7 vers 0.9 : un cas concret

Contexte

Dans le cadre d’un partenariat, nous avons eu pour mission de migrer un site de lodel 0.7 vers lodel 0.9, appelons le asgb. Nous avons reçu les données du site sous la forme d’un fichier compressé comprenant une sauvegarde des données réalisée dans l’interface lodel et l’arborescence du site. A cause de l’existence d’incompatibilités entre les versions récentes de php et la version 0.7 de lodel, nous réservons une machine aux projets de migration, appelons la oldserver, sous debian 5.0.10 sur laquelle est installée la version 5.2.1 de php et la version 5.0.51 de MySql, les bases étant créées par défaut en utf8. Le répertoire /www/lodel07 contient la racine de notre installation lodel 0.7 .

Création du site en lodel 0.7

Dans un contexte réel, nous ne le redirons jamais assez, il est impératif de sauvegarder les données (base de données, fichiers annexes, maquettes, …). Le plus simple, en situation de production, nous semble être de recréer un site à l’identique en suivant notre procédure, à partir d’une sauvegarde de votre site.

Sur oldserver, nous créons un répertoire réservé aux fichiers produits pendant les différentes étapes de la migration, cela permet de minimiser les retours en arrière en cas de problème, soit /www/asgb. Nous y plaçons la sauvegarde de la base de données faite sous lodel, fichier asgb.sql . Ce fichier est encodé en utf8 (commande file asgb.sql). Un affichage du contenu de ce fichier montre que les tables lodel étaient préfixées par lodel_ , ce qui est incompatible avec notre installation.

CREATE TABLE IF NOT EXISTS `lodel_champs` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `nom` varchar(64) NOT NULL DEFAULT ”,
  `idgroupe` int(10) unsigned NOT NULL DEFAULT ’0′,

Nous devons donc éditer ce fichier pour supprimer ce préfixe lodel_, le résultat est enregistré dans  asgb2.sql .

Le site ASGB est créé dans l’interface lodel 0.7 avec le nom court asgb, les fichiers lodel sont copiés dans /www/lodel07/asgb .
Dans notre installation, les bases sont préfixées par le préfixe lodel07_ . La base de données a donc pour nom lodel07_asgb. Elle a été créée en utf8 selon la configuration de notre serveur. Si votre serveur et vos bases sont configurés en latin1, il est inutile de faire le traitement spécial indiqué ci-dessous ; vous pouvez importer vos données (mysql  lodel07_asgb <  /www/asgb/asgb2.sql) et passer à  l’étape “Export 0.7 vers 0.8″.

Traitement spécial latin1 -> utf8

Le fichier /www/asgb/asgb2.sql est un fichier utf8 contenant des données encodées en latin1. Il faut que la base lodel07_asgb qui contiendra les données importées soit également en latin1. Avant d’importer les données, il faut donc détruire la base créée en utf8 et créer une base latin1

DROP  database  lodel07_asgb ;
CREATE  DATABASE  lodel07_asgb  DEFAULT  CHARACTER  SET  ‘latin1′  COLLATE  latin1_general_ci;

Les données sont ensuite importées dans cette nouvelle base :

mysql  –default-character-set=latin1  lodel07_asgb  <  /www/asgb/asgb2.sql

Le charset est modifié et les données sauvegardées dans le fichier /www/asgb/asgb3.sql :

mysqldump  lodel07_asgb –default-character-set=latin1  |  sed  s/CHARSET=latin1/CHARSET=utf8/g | sed  s/’SET NAMES latin1′/’SET NAMES utf8′/g  >  /www/asgb/asgb3.sql

Visualisez rapidement le fichier  /www/asgb/asgb3.sql pour vérifier que l’encodage est correct.

Une dernière étape consiste à modifier l’encodage du charset de la base pour le passer en utf8 :

ALTER  DATABASE  `lodel07_asgb`  DEFAULT  CHARACTER  SET  ‘utf8′  COLLATE  utf8_general_ci ;

Il ne reste qu’à importer les données utf8 dans la base utf8 et à sauvegarder :

mysql  –default-character-set=utf8  lodel07_asgb  <  /www/asgb/asgb3.sql
mysqldump  lodel07_asgb  >  /www/asgb/asgb4.sql

Export 0.7 vers 0.8

A cette étape, le site est créé en lodel 0.7, l’encodage est en utf8, les données sont sauvegardées dans /www/asgb/asgb4.sql s’il y a eu une transformation latin1-utf8 ou bien dans /www/asgb/asgb2.sql sinon. Un parcours depuis l’interface lodel permet de vérifier que les documents sont valides mais le site est inaccessible car il manque en général des templates (dans notre cas http://oldserver.revues.org/lodel07/asgb/lodel/admin/index.php).

Les fichiers suivants sont nécessaires à l’exportation :

  • export_to_08.php  à la racine du site à exporter /www/lodel07/asgb
  • 07to08.php  dans lodel/scripts de l’installation multisite de Lodel soit /www/lodel07
  • index_migration.html  dans le répertoire tpl du site /www/lodel07/asgb/tpl
  • macros_technique.html  dans le répertoire tpl du site /www/lodel07/asgb/tpl
  • Il faut que répertoire tpl soit accessible en lecture pour l’utilisateur apache
  • init-site.sql  à la racine du site /www/lodel07/asgb

Vérifiez que les fichiers du répertoire tpl sont accessibles à l’utilisateur apache et connectez-vous dans l’interface d’administration du site pour lancer le script d’export export_to_08.php (dans notre cas http://oldserver.revues.org/lodel07/asgb/export_to_08.php). Décochez la case Sauvegarde et cliquez sur Valider. Si l’export a été fait avec succès, il faut maintenant supprimer les entités dont le statut d’import est “non terminé”.

mysql lodel07_asgb
> delete from documents  where identity in (select id from entities e where e.status=-64);
> delete  from  relations  where  id2  in  (select id from entities e where e.status=-64);
> delete  from  entities  where  status=-64;

Une sauvegarde est nécessaire à cette étape avant l’importation sous lodel 0.9 :
mysqldump  lodel07_asgb  >  /www/asgb/asgb5.sql

 

Migration sous lodel 0.9

Création du site et importation des données

Notre serveur de développement develserver.revues.org contient une installation de lodel 0.9 multisites dans le répertoire /www/lodel09 . Les noms des bases sont préfixés avec le préfixe lodel09_ . Nous créons maintenant un site lodel ASGB sur cet espace, son répertoire racine sera /www/lodel09/asgb . La base correspondante est lodel09_asgb en utf8. Il faut ensuite détruire puis recréer la base avant d’importer les données exportées de 0.8 :

mysql
> drop  database  lodel09_asgb ;
> create database  lodel09_asgb ;
> quit ;
mysql  lodel09_asgb  <  /www/asgb/asgb5.sql

 Quelques commandes doivent être effectuées pour être compatibles avec la version 0.9 :

mysql  lodel09_asgb
>
alter  table  tablefields  add  mask  text  not  null;
> alter  table  entrytypes  add  `externalallowed`  tinyint(4)  NOT  NULL  default  ’0′ ;
> CREATE TABLE `plugins` (
  `id` int(10) unsigned NOT NULL DEFAULT ’0′,
  `name` varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL,
  `upd` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `status` tinyint(4) NOT NULL DEFAULT ’0′,
  `config` longtext NOT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;
> CREATE TABLE `relations_ext` (
  `idrelation` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id1` int(10) unsigned NOT NULL DEFAULT ’0′,
  `id2` int(10) unsigned NOT NULL DEFAULT ’0′,
  `nature` varchar(32) NOT NULL DEFAULT ‘E’,
  `degree` tinyint(4) DEFAULT NULL,
  `site` varchar(64) NOT NULL,
  PRIMARY KEY (`idrelation`),
  UNIQUE KEY `id1` (`id1`,`id2`,`degree`,`nature`),
  KEY `index_id1` (`id1`),
  KEY `index_id2` (`id2`),
  KEY `index_nature` (`nature`),
  KEY `index_site` (`site`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 ;

> CREATE TABLE `history` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`nature` varchar(32) NOT NULL,
`context` text,
`upd` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ;

Il est très très important de sauvegarder les données avant l’étape délicate de l’importation du modèle éditorial au format XML.

A ce stade, nous disposons d’un site Lodel fonctionnel sous Lodel 0.9. Le modèle éditorial utilisé dans ce site est celui qui a été défini dans le site sous Lodel 0.7.

Importation du modèle éditorial

Nous souhaitons maintenant mettre à jour le modèle éditorial de notre site pour qu’il soit conforme au modèle éditorial actuellement utilisé dans Lodel 0.9. Nous allons utiliser une fonctionnalité définie dans Lodel 0.9 qui nous permet d’importer un modèle éditorial (que nous appellerons cible) dans un site contenant déjà un modèle éditorial (que nous appellerons source). Au cours des différentes étapes de l’import, nous allons devoir faire correspondre l’ensemble des éléments qui diffèrent entre les modèles source et cible.

Dans l’interface Lodel 0.9, accédez au site migré et sélectionnez le menu Administration / Modèle éditorial / Importer un modèle au format XML . Nous utilisons le fichier modelxml-migration-260109.zip (téléchargement modelxml-migration-260109). Le système va vous proposer une succession de correspondances entre les champs de l’ancien site et les champs sous Lodel 0.9 . Il s’agit de reporter tous les chiffres du premier tableau dans le deuxième tableau en respectant le champ et la classe. Il ne faut pas utiliser la touche Entrée pour valider vos choix, mais cliquer sur le bouton Envoyer.

  • la table documents devient la table textes
  • pour la table tablefieldgroups, la correspondance est évidente
    migration-lodel-1
  • table options
    • servoourl devient url, servoousername devient username, servoopass devient passwd
    • signaler_mail n’existe pas en 09
  • tables orphelines : la table documents devient textes
  • classe publications :
    • erratum : champ vide et groupe des addenda
  • classe textes
    • notesbaspage devient notebaspage dans le groupe Texte
    • historique, fichiersassocies, fichiersource, importversion dans Gestion du document
    • droitsauteur vide et dans le groupe Metadonnées
    • lien dans le groupe Texte
    • URLessai dans Titres
      migration-lodel-2
  • classe types
    • regroupement = sous-partie
    • presentation = informations
    • articlepdf = article
    • regroupement-documentsannexes = vide
    • documentannexe-lienfichier = fichierannexe
    • documentannexe-lienfacsimile = fichierannexe
    • documentannexe-liendocument, documentannexe-lienpublication, documentannexe-lienexterne = lienannexe
    • articlevide = article
    • objetdelarecension = vide
    • recension = compterendu
    • volume, colloque = rubrique
    • breve = billet
    • periode = chrono
    • motcle = motsclesfr
  • textes devient textessimples (lien=url, datepubli=date)
  • correspondance des types
    migration-lodel-3
  • correspondance types textes vers liens

migration-lodel-4

Finitions

  • sauvegarder la base (fichier asgb7.sql)
  • rendre les documents cliquables : update  textes  set  documentcliquable=1;
  • copier le fichier complete.php à la racine du site migré et terminer la migration en lançant le script dans l’interface lodel (http://develserver.revues.org/lodel09/asgb/complete.php)
  • effacer le fichier complete.php
  • copier les documents annexes fournis avec l’ancien site ainsi que les fichiers sources ; rendre les répertoires docannexe et lodel/sources accessibles en écriture à l’utilisateur apache.

 

 

 

 

 

 

 

 

 

Changement d’URL de ServOO pour Lodel 0.8 et 0.9 ; Fin de ServOO pour Lodel 0.7 le 28/02/2014

Voici deux informations importantes pour les utilisateurs de ServOO pour Lodel 0.7 à 0.9

Changement d’URL du service ServOO pour Lodel 0.8 et 0.9

Le 5 novembre 2013, nous avons déplacé le service ServOO pour Lodel 0.8 et 0.9 sur un nouveau serveur. L’URL de ServOO a changé à cette occasion. La nouvelle URL est la suivante : http://servoodevel.revues.org

Les comptes utilisés sur la précédente installation de ServOO n’ont pu être conservés lors du déplacement du service. Il vous est donc nécessaire de recréer un compte en utilisant le formulaire suivant : http://servoodevel.revues.org/register.php

Vous devez ensuite renseigner URL, identifiant et mot de passe dans votre site Lodel, soit au niveau des options du site dans l’interface d’administration de Lodel, soit dans le fichier lodelconfig.php qui se trouve à la racine du répertoire d’installation de Lodel.

Fin du service ServOO pour Lodel 0.7 fin février 2014

Nous maintenons depuis 2004 le service ServOO 0.7 pour la conversion des documents doc et sxw pour Lodel 0.7.

Ce logiciel a vieilli. Les technologies sur lesquels il est basé sont aujourd’hui obsolètes et nous ne sommes plus en mesure de maintenir ce service.

Nous allons devoir le fermer dans les prochaines semaines. Le 28/02/2014, ServOO 0.7 s’arrêtera définitivement.

Nous invitons donc les utilisateurs de ServOO 0.7 à migrer leurs sites vers la version 0.9 de Lodel.

Des informations pratiques pour l’installation de Lodel 0.9 et pour la migration de Lodel 0.7 vers Lodel 0.9 sont disponibles sur ce blog :

http://blog.lodel.org/97 et http://blog.lodel.org/116

Ces 2 billets pourront également vous aider à migrer votre site depuis Lodel 0.7 vers Lodel 0.9 ou 1.0 :

Lodel + Solr

Lodel + Solr

Few months ago, we started a complete rewrite of the new version of Calenda powered by Lodel. The biggest part of the public side of Calenda—programaticaly speaking—is its search engine: this engine is used everywhere, not only on the result pages, but also on the front page and the event page.

Our search engine choice is Lucene/Solr, we already use it to index and provide faceted search on all the contents from Revues.org, Hypotheses.org and the actual Calenda. Solr is fast, powerful, easy to use and to maintain, and supported by a strong community. It also provides a very interesting functionnality: dynamic fields.

Dynamic fields

Here is a detailed explanation about dynamic fields.

Solr configuration file is a simple, almost flat, XML file. Is is called schema.xml.

<?xml version="1.0" encoding="UTF-8" ?>
<schema name="example" version="1.4">

    <types>

        <fieldType name="int" class="solr.TrieIntField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
        <fieldType name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>

        <fieldType name="text" class="solr.TextField" positionIncrementGap="100">
            <analyzer type="index">
                <tokenizer class="solr.StandardTokenizerFactory"/>
                <filter class="solr.LowerCaseFilterFactory"/>
            </analyzer>
            <analyzer type="query">
                <tokenizer class="solr.StandardTokenizerFactory"/>
                <filter class="solr.LowerCaseFilterFactory"/>
            </analyzer>
        </fieldType>

    </types>

    <fields>

        <field name="id" type="string" indexed="true" stored="true" required="true"/>
        <field name="nature" type="string" indexed="true" stored="true" required="true"/>
        <field name="class" type="string" indexed="true" stored="true" required="true"/>
        <field name="type" type="string" indexed="true" stored="true" required="true"/>
        <field name="idtype" type="int" indexed="true" stored="true"/>
        <field name="idparent" type="int" indexed="true" stored="true"/>
        <field name="status" type="int" indexed="true" stored="true"/>
        <field name="text" type="text" indexed="true" stored="false" multiValued="true"/>

    </fields>

    <uniqueKey>id</uniqueKey>

    <defaultSearchField>text</defaultSearchField>

    <solrQueryParser defaultOperator="OR"/>

    <copyField source="*" dest="text"/>

</schema>

It allows you define field names and types describing your data. For example, the unique ID, the title, subtitle, etc. This is OK to solve simple problems, but sometimes, we don’t know what our data will be composed of. This is what dynamic fields are for: they make you schema.xml less hard-coded.
As you may already know, Lodel main feature is its customizable Editorial Model: you can define your database structure directly from the back office. Thanks to the dynamic fields, we wrote a schema.xml able to handle any data from Lodel, whatever your Editorial Model looks like!
This means that our work with Solr can be useful for any Lodel users, so we plan to distribute it in the next release.

Our schema.xml

Here is the schema.xml so far:

<?xml version="1.0" encoding="UTF-8" ?>
<schema name="example" version="1.4">

    <types>

        <fieldType name="int" class="solr.TrieIntField" precisionStep="0" omitNorms="true" positionIncrementGap="0"/>
        <fieldType name="string" class="solr.StrField" sortMissingLast="true" omitNorms="true"/>

        <fieldType name="text" class="solr.TextField" positionIncrementGap="100">
            <analyzer type="index">
                <tokenizer class="solr.StandardTokenizerFactory"/>
                <filter class="solr.LowerCaseFilterFactory"/>
            </analyzer>
            <analyzer type="query">
                <tokenizer class="solr.StandardTokenizerFactory"/>
                <filter class="solr.LowerCaseFilterFactory"/>
            </analyzer>
        </fieldType>

    </types>

    <fields>

        <field name="id" type="string" indexed="true" stored="true" required="true"/>
        <field name="nature" type="string" indexed="true" stored="true" required="true"/>
        <field name="class" type="string" indexed="true" stored="true" required="true"/>
        <field name="type" type="string" indexed="true" stored="true" required="true"/>
        <field name="idtype" type="int" indexed="true" stored="true"/>
        <field name="idparent" type="int" indexed="true" stored="true"/>
        <field name="status" type="int" indexed="true" stored="true"/>
        <field name="text" type="text" indexed="true" stored="false" multiValued="true"/>

        <dynamicField name="*_int" type="int" indexed="true" stored="true"/>
        <dynamicField name="*_entries" type="int" indexed="true" stored="true"/>
        <dynamicField name="*_persons" type="int" indexed="true" stored="true"/>
        <dynamicField name="*_file" type="int" indexed="true" stored="true"/>
        <dynamicField name="*_boolean" type="int" indexed="true" stored="true"/>
        <dynamicField name="*_tinytext" type="string" indexed="true" stored="true"/>
        <dynamicField name="*_email" type="string" indexed="true" stored="true"/>
        <dynamicField name="*_date" type="string" indexed="true" stored="true"/>
        <dynamicField name="*_url" type="string" indexed="true" stored="true"/>
        <dynamicField name="*_text" type="text" indexed="true" stored="true"/>
        <dynamicField name="*_mltext" type="text" indexed="true" stored="true"/>

        <dynamicField name="*_int_m" type="int" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_entries_m" type="int" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_persons_m" type="int" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_file_m" type="int" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_boolean_m" type="int" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_tinytext_m" type="string" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_email_m" type="string" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_date_m" type="string" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_url_m" type="string" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_text_m" type="text" indexed="true" stored="true" multiValued="true"/>
        <dynamicField name="*_mltext_m" type="text" indexed="true" stored="true" multiValued="true"/>

    </fields>

    <uniqueKey>id</uniqueKey>

    <defaultSearchField>text</defaultSearchField>

    <solrQueryParser defaultOperator="OR"/>

    <copyField source="*" dest="text"/>

</schema>

Indexing content

So I started to write a simple PHP script to index content from Lodel SQL database.

Solr provides a web service to receive the data through POST requests. You can generate XML and use CURL to send it to Solr and get your content indexed, but the easiest way is to use a library which take care of the boring part. The best library I found for PHP is called Solarium. It is full featured, well documented, and similar to other Solr libraries in Python and Perl.

The script is only few lines of PHP and is pretty safe explanatory:

<?php

require('Solarium/Autoloader.php');
Solarium_Autoloader::register();

$client = new Solarium_Client();

$adapter = $client->getAdapter();
$adapter->setPort(8989);

// Delete all documents
$update = $client->createUpdate();
$update->addDeleteQuery('*:*');
$update->addCommit();
$result = $client->update($update);

// Connect the db
$dbh = new PDO('mysql:host=localhost;dbname=xxxx', 'xxxx', 'xxxx', array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8") );

$docs = array();

function update($client, &$docs) {
    $update = $client->createUpdate();
    $update->addDocuments($docs);
    $update->addCommit();
    $result = $client->update($update);
    $docs = array();
    echo ".";
}

$objects = $dbh->prepare("SELECT * FROM objects WHERE class IN ('entities')");
$objects->execute();
while ( $object = $objects->fetch() ) {

    $doc = new Solarium_Document_ReadWrite();
    $doc->id = $object[id];
    $doc->nature = $object['class'];

    switch ($object['class']) {
        case 'entities':
            $entities = $dbh->prepare("SELECT e.*, t.type, t.class FROM entities e, types t WHERE e.id = ? AND e.idtype = t.id");
            $entities->execute(array($object[id]));
            $entity = $entities->fetch();

            foreach (array('idtype','type','class','idparent','status') as $k) {
                $doc->addField($k, $entity[$k]);
            }

            $things = $dbh->prepare("SELECT * FROM $entity[class] WHERE identity = $object[id]");
            $things->execute();
            $thing = $things->fetch();

            $tablefields = $dbh->prepare("SELECT * FROM tablefields WHERE class = '$entity[class]'");
            $tablefields->execute();
            while ($f = $tablefields->fetch()) {
                $v = preg_replace('/[\p{Cc}]/', '', $thing[$f[name]]);
                if ($v)
                    $doc->addField($f[name].'_'.$f[type], $v);
            }

            $relations = $dbh->prepare("SELECT r.id2, r.nature, et.type FROM relations r, entries e, entrytypes et WHERE id1 = $object[id] AND r.id2 = e.id AND e.idtype = et.id");
            $relations->execute();
            while ($r = $relations->fetch()) {
                $doc->addField('R_'.$r[nature].'_'.$r[type].'_int_m', $r[id2]);
            }

            break;
    }

    $docs[] = $doc;
    if ( count($docs) == 1000 )
        update($client, $docs, $total);
}

update($client, $docs, $total);

?>

There is only one big loop, on the ‘object’ table. An object can be an entity, an entry or a person. For now, it can only index entities, but we plan to support entries and persons in the next move.
The most interesting part is (simplified) here:

while ($f = $tablefields->fetch()) {
    $doc->addField($f[name].'_'.$f[type], $thing[$f[name]]);
}

As you can see, the name of the added Solr field results from the concatenation of its name and type in Lodel. If you defined a multilingual field named ‘title’ in your editorial model, the script will send it to Solr under the name ‘title_mltext’, and Solr will store it using the dynamic field ‘*_mltext’.

To better understand how Solr store our documents, here is the result of a select query:

<response>
    <lst name="responseHeader">
        <int name="status">0</int>
        <int name="QTime">0</int>
        <lst name="params">
            <str name="q">*:*</str>
        </lst>
    </lst>
    <result name="response" numFound="19573" start="0">
        <doc>...</doc>
        <doc>...</doc>
        <doc>...</doc>
        <doc>...</doc>
        <doc>
            <str name="nature">entities</str>
            <str name="class">event</str>
            <str name="type">event</str>
            <str name="dates_date">2010-12-08</str>
            <str name="id">619209</str>
            <int name="idparent">0</int>
            <int name="idtype">57</int>
            <int name="status">-1</int>
            <str name="title_mltext">
                <r2r:ml lang="fr">Les compagnons de l'Espace</r2r:ml>
            </str>
            <str name="subtitle_mltext">
                <r2r:ml lang="fr">Une exposition de l'Observatoire de l'Espace du CNES</r2r:ml>
            </str>
            <str name="summary_mltext"/>
            <str name="content_mltext">
                <r2r:ml lang="fr"><p>A l'occasion de la 28e &eacute;dition des Journ&eacute;es europ&eacute;ennes du patrimoine, organis&eacute;e par le minist&egrave;re de la Culture et de la communication sur le th&egrave;me<i> Le voyage du patrimoine,</i> l'Observatoire de l'Espace invite le public au si&egrave;ge parisien du CNES, le samedi 17 et le dimanche 18 septembre 2011 de 11h &agrave; 19h pour l'exposition <i>L<b>es compagnons de l'Espace</b>.</i> Chacun&nbsp;pourra&nbsp;venir y&nbsp;d&eacute;couvrir des pi&egrave;ces&nbsp;&eacute;tonnantes issues du patimoine culturel de l'Espace et rencontrer les t&eacute;moins et acteurs de l'aventure spatiale. Cette&nbsp;&eacute;v&egrave;nement in&eacute;dit&nbsp;r&eacute;v&egrave;lera la multiplicit&eacute; des liens que l'Homme tisse avec l'Espace, &agrave; travers les compagnons qui le pr&eacute;c&egrave;dent, l'assistent et le r&eacute;confortent; qu'ils soient fictifs ou r&eacute;els, animaux ou robots, ils sont les partenaires de son exploration.</p><p>Entr&eacute;e libre et gratuite</p><p>Centre National d'Etudes Spatiales&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2, place Maurice Quentin Paris 1er</p><p>M&eacute;tro Chatelet-Les halles/sortie place carr&eacute;e</p><p>Renseignements : 01 44 76 76 18&nbsp; / <a href="mailto:observatoire.espace@cnes.fr">observatoire.espace@cnes.fr</a></p></r2r:ml>
            </str>
            <arr name="R_E_partners_int_m">
                <int>1387273</int>
            </arr>
            <arr name="R_E_places_int_m">
                <int>1434398</int>
            </arr>
            <arr name="R_E_subjects_int_m">
                <int>1387363</int>
            </arr>
            <arr name="R_E_type_int_m">
                <int>1387268</int>
            </arr>
            <arr name="R_E_websites_int_m">
                <int>1396551</int>
            </arr>
        </doc>
        <doc>...</doc>
        <doc>...</doc>
        <doc>...</doc>
        <doc>...</doc>
        <doc>...</doc>
    </result>
</response>

Querying Solr from Lodel

Now that our data is indexed, we want to query Solr from inside Lodel. To ease the process, I started to code a very simple LodelScript loop, and placed it in the dedicated file loops_local.php:

<?php

function loop_solr($context, $funcname, $arguments) {

    $localcontext = $context;

    if (function_exists("code_before_$funcname"))
        call_user_func("code_before_$funcname", $localcontext);

    $client = new Solarium_Client();

    $adapter = $client->getAdapter();
    if (isset($arguments[port]))
        $adapter->setPort($arguments[port]);

    $query = $client->createSelect();
    if (isset($arguments[query]))
        $query->setQuery($arguments[query]);

    $resultset = $client->select($query);

    $context[nbresults] = $resultset->getNumFound();

    $count = 0;
    foreach ($resultset as $document) {

        $localcontext = $context;
        $localcontext[count] = ++$count;

        foreach($document AS $field => $value) {
            $localcontext[$field] = $value;
        }

        call_user_func("code_do_$funcname", $localcontext);
    }

    if (function_exists("code_after_$funcname"))
        call_user_func("code_after_$funcname", $localcontext);
}

?>

This loop is very similar to the SQL loop and can be used like this:

<h1>À la une</h1>
<LOOP NAME="solr" PORT="8989" QUERY="class:event AND status:1 AND frontpage_boolean:1">
    <BEFORE><ul></BEFORE>
    <DO>
        <li><a href="/[#ID]">[#TITLE_MLTEXT]</a></li>
    </DO>
    <AFTER></ul></AFTER>
</LOOP>

More Like This

Solr provide another nice feature called MoreLikeThis queries. Enable MLT during a query and each Solr result will be filled with similar contents. The similarity is based on the fields you want, and you can even weight them.
So I developed another LodelScript sub-loop, similar to the RSS loop, to support MLT:

<LOOP NAME="solr" PORT="8989" QUERY="id:[#ID]" MLT="1" MLTFL="class,status,title_mltext,body_mltext" COUNT="10">
    <BEFORE><ul></BEFORE>
    <DO>
        <LOOP NAME="morelikethis">
            <BEFORE><ul></BEFORE>
            <DO><li><a href="[#ID]">[#TITLE_MLTEXT]</a></li></DO>
            <AFTER></ul></AFTER>
        </LOOP>
    </DO>
    <AFTER></ul></AFTER>
</LOOP>

This code will list the 10 most similar documents for the current ID, based on the class, status, title_mltext and body_mltext fields.

What next?

This code is still a proof of concept, it needs refactoring, polishing, documentation and integration.

Putting in a separate function the code that indexes a document, in order to call them from an edition hook: this way, any updated object will be re-indexed on the fly.

We also plan to clone the hook system for the indexation function. This would allow us to per-site customize the building of a Solr document before it is sent to Solr without forking the script. A good example of such a hook would be querying GeoNames web service at indexing time to geolocalize your content.

Solr also provides an XLST processor. Writing some simple sheets to transform Solr results into another formats would be a very neat way to add plenty of web services to Lodel.

Modèle de document pour Word v3.0 : nouvelles macros d’automatisation

Nous venons de diffuser sur sourcesup la version 3.0 du modèle de document pour Word  https://sourcesup.cru.fr/frs/?group_id=193.

Le version 3.0 est constituée d’une archive zip qui contient :

  • le modèle revuesorg_fr.dot, qui contient les styles déclarés dans le modèle éditorial de Revues.org distribué avec Lodel (modèle à utiliser par défaut) ;
  • le modèle revuesorg_complet.dot, qui contient un plus grand nombre de styles (résumés dans des langues supplémentaires, index supplémentaires, etc.). L’utilisation de ce modèle de document nécessite la modification du modèle éditorial dans Lodel ;
  • les modèles macros_revuesorg_win.dot et macros_revuesorg_mac.dot. Ces deux modèles contiennent des macros qui permettent d’automatiser certaines corrections de stylage et d’erreurs typographiques (une version pour Windows et une version pour MacOS).
  • documentation_modele_revuesorg_3.0.doc : la documentation d’installation et d’utilisation des macros

Cette version du modèle de document introduit des macros Word qui permettent d’automatiser la correction et le nettoyage des textes. Ces macros permettent de gagner beaucoup de temps dans la préparation des textes. Les macros disponibles à ce jour (20/07/2011) sont les suivantes  :

  • Macros de corrections de stylage
    • Supprimer les mises en forme et les styles de caractères locaux dans le corps de texte
    • Trier les métadonnées
    • Vérifier les paragraphes
    • Vérifier les niveaux de titre
    • Rendre les liens hypertextes actifs
  • Macros de corrections typographiques
    • Rétablir les espaces insécables dans le corps de texte
    • Remplacer les apostrophes verticales par des apostrophes typographiques
    • Supprimer les doubles sauts de paragraphe
    • Supprimer les points à la fin des titres
    • Remplacer les guillemets droits par des guillemets anglais / Remplacer les guillemets droits par des guillemets français
    • Effacer le surlignement
    • Inverser les italiques dans la sélection en cours / Inverser les italiques dans tout le document
  • Macros pour les notes de bas de page
    • Supprimer les mises en forme et les styles de caractères locaux dans les notes de bas de page
    • Supprimer les doubles sauts de paragraphe dans les notes de bas de page
    • Rétablir les espaces insécables dans les notes de bas de page
    • Renumérotation des notes
    • Supprimer les points après les numéros de notes
  • Traitements avancés
    • Traitement par lot
    • Transformer les équations Word en images

Vous trouverez plus de détail sur l’utilisation de ces macros dans la documentation diffusée avec les modèles.

Merci à Jean-Baptiste Bertrand qui a développé ces macros qui font gagner énormément de temps et améliore la qualité des données publiées dans Lodel !

 

Mise à jour du modèle de document pour OpenOffice

Nous avons déposé récemment sur sourcesup une nouvelle version du modèle de document pour Open/Libre Office : https://sourcesup.cru.fr/frs/?group_id=193 (Lodel modele revues.org (OOo) 1.0).
Cette version corrige quelques bugs mineurs, améliore la mise en forme des styles de paragraphe “titre illustration”, “legende illustration”, “credits illustration” et des styles de caractères liés aux auteurs “affiliation”, “courriel”…
Une documentation d’installation est incluse (readme.txt) dans l’archive zip.
Cette documentation est aussi disponible sur le wiki de Lodel : http://www.lodel.org/wiki/index.php/Mod%C3%A8le_de_document_pour_OpenOffice

Pas de nouvelles de Lodel?

Il n’y a pas eu de nouvelles concernant les nouveautés de Lodel depuis un moment, il est maintenant temps de faire un petit point sur ces derniers mois de développement, qui ont permis d’apporter un certain nombre d’améliorations et de préparer la sortie de Lodel 1.0.

Ce qui est indiqué ci-dessous, n’est présent que sur les branches de bugfixes, et le tronc de développement.

Gestion des RSS

Jusqu’à très récemment la gestion des flux RSS était faite par MagpieRSS, cette librairie n’est plus maintenue depuis 2005 si l’on croit ce que l’on voit sur le site du projet. De plus cette librairie utilise beaucoup de fonction de PHP qui sont dépréciés dans les nouvelles version de PHP, en particulier la version 5.3, qui est présent dans la dernière version stable de Debian.

À partir de ce constat, nous avons cherché une librairie de lecture de flux RSS, écrite pour PHP 5.3 et ultérieur, utilisant les concepts objet, et qui soit encore maintenu. Nous en avons trouvé plusieurs, mais la plupart avaient une lacune sur un des critères principaux: le projet n’était pas maintenu.

Nous avons eu la change de trouver une librairie très bien écrite, qui est toujours maintenue à l’heure actuelle, et qui fonctionne beaucoup mieux de MagpieRSS: SimplePie.

Le travail d’intégration de cette librairie n’a pas été bien compliqué, car elle est relativement compatible avec MagpieRSS.
Cette modification sera présente dans Lodel 1.0, et Lodel 0.9.1, qui devront bientôt voir le jour.

Gestion du Cache

Lodel existe depuis longtemps, les besoins ont beaucoup évolués depuis les premières utilisations, et les fonctionnalités sont apparues au fil des besoins. Aujourd’hui, Lodel est utilisé dans des architectures à haute disponibilité, ce qui fait de nouveau évoluer les besoins.

La structure du cache de lodel ne correspondait plus au besoin des architectures HA(High Availability), le cache doit pouvoir être totalement séparé du code; C’est pourquoi, nous avons réécrit la gestion de cache afin de pouvoir spécifier un répertoire spécifique qui contiendra tout le cache, et rien que le cache.

Cela permet de pouvoir stocker le cache sur un serveur distant, ou dans la ram, ou sur un système de fichier particulier afin d’obtenir de meilleures performances.

Cette fonctionnalité sera aussi disponible dans Lodel 1.0, 0.9.1, et sur la branche de bugfix de la version 0.8.

Lodel 1.0

Venons-en à la future version majeure de lodel, beaucoup de travail a été fait pour améliorer et faire évoluer lodel.

Tout d’abord, l’interface a été un peu revue, les couleurs ont changé, et certains processus, comme l’import de documents, ont étés revus.

La principale nouveauté dans Lodel 1.0 est l’abandon de ServOO à l’avantage de OpenText/OTX, qui permet la conversion des documents Office vers de la TEI, par conséquent Lodel sait maintenant importer de la TEI. Plusieurs revues utilisent déjà cette fonctionnalité, et stylent leurs documents directement en TEI (Discours, Journal of the Text Encoding Initiative). Il n’y a donc plus besoin d’un outil aussi lourd que Microsoft ou Open/Libre Office. Pour les plus aventureux un éditeur texte suffit, pour les moins téméraires il existe différents outils d’éditions XML, comme Oxygen ou bien XML Editor

Next Page »