[ C++ ] Parser & Writer XML avec Xerces-C++ et DOM

Par Deimos le 11-11-2005



parser du XML en C++ avec la puissante librarie Xerces-C++



Pour tous ceux qui essayeront de parser du XML en C++ avec la puissante librarie Xerces-C++, afin qu'ils ne se suicident pas sur la documentation anglaise et quelque peu confuse d'Apache, étant donné qu'aucun article français n'existe
encore sur le parser DOM et Xerces-c++ ...


Introduction

Le XML ( Extensible Markup Language ) a été proposé par le W3C (World Wide Web Consortium) en 1998. Il constitue
un langage très souple, ceci étant du à la possibilité de créer ses propres balises et attributs. De plus,
le XML a de nombreux avantages comme la structure et la hiérarchie des données qui peut être définie
de manière stricte dans des fichiers DTD ( Document Type Definition ).
Cette organisation des données en arborescence est à la fois utile
et efficace : elle permet de lister de manière typée des données mais également une lecture facile de ces données
par un programme. Ainsi le XML peut être un langage de base pour d'autres langages, comme le XHTML, que l'on
peut voir en tant que l'évolution du HTML.




Rappels relatifs au XML

Tout document XML doit obligatoirement commencé par la ligne :

 

Code:
<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>



Les attributs "encoding" et "standalone" sont cependant facultatifs. "encoding" permet de définir le jeu de caractères
( charset ) utilisé ( UTF-8, ISO-8859-1, etc ) et "standalone" permet de définir si le fichier .xml est accompagné d'un
fichier .dtd contenant les types des données de la structure XML.

On peut définir ces types soit dans un fichier.dtd à part, avec dans .xml ... :

 

Code:

<?xml version="1.0" encoding="ISO-8859-1" standalone="no" ?>
<!DOCTYPE arborescence SYSTEM "types.dtd">

<arborescence>

   <entity type = "file" name = "New Text Document.txt"
         size = "21 835 bytes"
         date_creation = "vendredi 28 octobre 2005 14:08:26"
         date_modif = "vendredi 28 octobre 2005 14:37:39"
         date_access = "vendredi 4 novembre 2005 18:53:41" >
   </entity>


</arborescence>
 




et dans le .dtd ... :

 

Code:

<!ELEMENT entity (#PCDATA) >
<!ATTLIST entity type          CDATA #REQUIRED >
<!ATTLIST entity name          CDATA #REQUIRED >
<!ATTLIST entity size          CDATA #IMPLIED >
<!ATTLIST entity date_creation      CDATA #IMPLIED >
<!ATTLIST entity date_modif      CDATA #IMPLIED >
<!ATTLIST entity date_access      CDATA #IMPLIED >
 




... soit en déclarant les types de données dans le .xml lui-même :

 

Code:

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>

<!DOCTYPE arborescence [
   <!ELEMENT entity (#PCDATA) >
   <!ATTLIST entity type          CDATA #REQUIRED >
   <!ATTLIST entity name          CDATA #REQUIRED >
   <!ATTLIST entity size          CDATA #IMPLIED >
   <!ATTLIST entity date_creation      CDATA #IMPLIED >
   <!ATTLIST entity date_modif      CDATA #IMPLIED >
   <!ATTLIST entity date_access      CDATA #IMPLIED >
] >

<arborescence>

   <entity type = "file" name = "New Text Document.txt"
         size = "21 835 bytes"
         date_creation = "vendredi 28 octobre 2005 14:08:26"
         date_modif = "vendredi 28 octobre 2005 14:37:39"
         date_access = "vendredi 4 novembre 2005 18:53:41" >
   </entity>

</arborescence>
 




Le code XML lui-même n'est pas complexe : on créé un noeud principal, ici "arborescence", suivi d'autres balises que
l'utilisateur définit ( ici "entity" ), et des attributs peuvent être également déclarés ( type, name, etc ).
Pour le DTD, on déclare :
- un élément avec <!ELEMENT nom (type) >
- un atribut avec <!ATTLIST nom_element nom_attribute type options >

Il existe de nombreux types, ici j'utilise #PCDATE pour pouvoir inclure la quasi-totalité des caractères. Pour une liste
exhaustive des types de données en XML, reportez vous à un tutorial entièrement consacré au XML.
En ce qui concerne les options des attributs, #REQUIRED marque l'attribut comme obligatoire et #IMPLIED comme facultatif.
A nouveau, il en existe d'autres, que vous trouverez dans de la documentation relative a XML.

Passons aux choses sérieuses en C++ Wink




Coder un Parser DOM avec Xerces-c++

Xerces-c++ est une librairie portée en C++ permettant d'écrire et de parser des documents XML. Cette librarire, actuellementà sa version 2.7.0 est développée par Apache. Site officiel : http://xml.apache.org/xerces-c/.
Vous y trouverez la liste des classes / méthodes et quelques exemples, mais rien de très détaillé.

Xerces-c++ a mis au point deux parsers : SAX ( Simple API for XML ) basé sur un mode évènementiel et DOM ( Document Object Model ) basé sur la hiérarchie des éléments du document XML. DOM permet ainsi une navigation plus simplifié dans le document XML et ceci est la raison pour laquelle j'ai choisi ce dernier pour parser et écrire des données XML.

Nous allons parser le document XML suivant avec Xerces-C++ et le parser DOM ( il représente l'arborescence d'un dossier de disque dur, qu'importe les éléments et les attributs, ceci est uniquement pour l'exemple Wink :

 

Code:

<?xml version="1.0" encoding="ISO-8859-1" standalone="yes" ?>

<!DOCTYPE arborescence [
   <!ELEMENT entity (entity) >
   <!ATTLIST entity type          CDATA #REQUIRED >
   <!ATTLIST entity name          CDATA #REQUIRED >
   <!ATTLIST entity size          CDATA #IMPLIED >
   <!ATTLIST entity date_creation      CDATA #IMPLIED >
   <!ATTLIST entity date_modif      CDATA #IMPLIED >
   <!ATTLIST entity date_access      CDATA #IMPLIED >
   <!ELEMENT entity (#PCDATA) >
] >

<arborescence>

   <entity type = "file" name = "New Text Document.txt"
         size = "21 835 bytes"
         date_creation = "vendredi 28 octobre 2005 14:08:26"
         date_modif = "vendredi 28 octobre 2005 14:37:39"
         date_access = "vendredi 4 novembre 2005 18:53:41" >
   </entity>

   <entity type = "directory" name = "EasyPHP1-8"
         size = "97 902 592 bytes"
         date_creation = "dimanche 9 octobre 2005 00:29:44" >
         
         <entity type = "file" name = "EasyPHP.log"
               size = "4 096 bytes"
               date_creation = "mercredi 2 novembre 2005 19:56:39"
               date_modif = "mercredi 2 novembre 2005 19:56:18"
               date_access = "dimanche 6 novembre 2005 13:36:50" >
         </entity>
         
         <entity type = "file" name = "EasyPHP.exe"
               size = "172 032 bytes"
               date_creation = "mercredi 2 novembre 2005 19:56:39"
               date_modif = "jeudi 3 novembre 2005 19:30:10"
               date_access = "dimanche 6 novembre 2005 13:36:18" >
         </entity>

         <entity type = "directory" name = "mysql"
               size = "30 064 640 bytes"
               date_creation = "mercredi 2 novembre 2005 19:56:42" >

            <entity type = "file" name = "my-large"
                  size = "4 096 bytes"
                  date_creation = "mercredi 2 novembre 2005 19:56:42"
                  date_modif = "mardi 9 septembre 2003 13:07:32"
                  date_access = "dimanche 6 novembre 2005 13:46:22" >
            </entity>
            
         </entity>
         
   </entity>

</arborescence>
 




Voici un bref descriptif des méthodes utilisées dans le code du parser. Cependant, attention : de nombreuses méthodes sont présentes dans plusieurs classes différents et prennent donc des arguments différents, etc. Vous devez donc toujours vérifier les arguments et ce que renvoi une méthode avec la documentation : http://xml.apache.org/xerces-c/apiDocs/functions.html


XMLPlatformUtils::Initialize()
Indispensable pour pouvoir utiliser un des parsers ( DOM ou SAX ) de Xerces-c++ : cette méthode initialise Xerces-C++.
Afin de l'utiliser, il est obligatoire d'inclure <src/xercesc/util/PlatformUtils.hpp> sous Linux, ou juste
<xercesc/util/PlatformUtils.hpp> sous Windows, où xercesc est le répertoire ou Xerces-c++ est décompressée.

XMLPlatformUtils::Terminate()
Cette méthode doit être la dernière appelée afin de marqué l'arrête de l'utilisation de Xerces-C++.

XMLString::transcode(const char *const)
Permet de transcrire un string en caractère compatible avec les parsers (XMLCh *).
La chaîne retournée est alloué dynamiquement, ainsi, pour libérer cet espace mémoire, il est important d'appeler la méthode
XMLString::release() après avoir appelé transcode().

XercesDOMParser::XercesDOMParser(...)
Constructeur de la classe XercesDOMParser. Dans notre exemmple, nous utilisons un parser XercesDOMParser, cependant nous pouvons tout à fait parser notre fichier avec DOMBuilder. L'utilisation de certaines méthodes diffèrent selon de la classe
utilisée.

XercesDOMParser::setErrorHandler(ErrorHandler *const handler)
Permet de lier un handle d'erreur ErrorHandler au parser.

AbstractDOMParser::parse(const char *const systemId)
Permet de parser le fichier XML donné en paramètre.

XMLPlatformUtils::getCurrentMillis()
Renvoie le temps système en milliseconde. Cette fonction permet, avec une simple soustraction, d'obtenir le temps qu'a mis
le programme pour parser le fichier XML, ou effectuer toute autre action.

DOMNode::getNodeType()
Renvoie le type de noeud ( [http://xml.apache.org/xerces-c/apiDocs/classDOMNode.html#z227_0 pour tous les types de noeud )

DOMNode::getNodeName()
Renvoie le nom d'un noeud

DOMNode::hasAttributes()
Retourne true si le noeud à un ou des attributs, sinon false.

DOMNode::getAttributes()
Renvoie un pointeur DOMNamedNodeMap contenant la liste des attributs du noeud.

DOMNamedNodeMap::getNamedItem(const XMLCh *name)
Renvoie un pointeur DOMNode/DOMAttr vers le noeud/attribut spécifié.

DOMAttr::getValue()
Renvoie la valeur d'un attribut (cette fonction, liée aux deux précédentes permet d'obtenir rapidement la valeur d'un attribut
d'un élément).


A présent, vous pouvez sans problème comprendre le code suivant Wink


parser.cpp

 

Code:

#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/parsers/AbstractDOMParser.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>

#include <string>
#include <iostream>

#include "ErrReporter.hpp"

XERCES_CPP_NAMESPACE_USE
using namespace std;


// Fonction permettant de concaténer X fois
// une chaine str

string strcatX(string str,unsigned int x) {
   for(unsigned int y = 0; y <= x; y++)
      str += str;

   return str;
}


// Fonction displayElements :
// fonction récursive qui affiche tous les noeuds ayant pour valeur
// "directory" ou "file" en attribut "type"

static int displayElements(DOMNode *n, unsigned int nbr_child) {
   DOMNode *child;

   // Compte les éléments
   unsigned int count = 0;

   // Compte le nombre d'appels à la fonction (récursive)
   // afin de pouvoir établir une tabulation au texte de sortie
   // de l'exécutable. Un appel = un répertoire
   static unsigned count_call = 0;

   // Rajoute un nombre nbr_child de tabulations afin de faciliter
   // la lisibilité de l'arborescence
   string xTab = strcatX("  ",nbr_child);

   if(n) {
      if(n->getNodeType() == DOMNode::ELEMENT_NODE) {
         if(n->hasAttributes()) {
            // Initialise un pointeur DOMNamedNodeMap sur les attributs du noeud courant
            DOMNamedNodeMap *pAttribus = n->getAttributes();
            
            // Initialise un pointeur DOMNode sur l'attribut "type" du noeud
            XMLCh *nameAttr = XMLString::transcode("type");
            DOMAttr *attr = (DOMAttr *) pAttribus->getNamedItem(nameAttr);
            XMLString::release(&nameAttr);

            // Récupère la valeur de l'attribut "type"
            char *Type = XMLString::transcode(attr->getValue());

            if(!(strncmp(Type,"directory",10))) {
               // Récupère la valeur de l'attribut "name" pour afficher
               // le nom du répertoire
               nameAttr = XMLString::transcode("name");
               attr = (DOMAttr *) pAttribus->getNamedItem(nameAttr);
               XMLString::release(&nameAttr);

               char *value = XMLString::transcode(attr->getValue());
               cout << xTab << "----------------------\n" << endl;
               cout << xTab << "<DIR> " << value << "\n" << endl;
               XMLString::release(&value);


               // Appel la fonction afin de lister les fichiers du répertoire courant
               ++count_call;

               for (child = n->getFirstChild(); child != 0; child=child->getNextSibling())
                  count += displayElements(child,count_call);

               --count_call;

               ++count;
            }

            else if(!(strncmp(Type,"file",10))) {
               // Récupère la valeur de l'attribut "name" pour afficher
               // le nom du fichier
               nameAttr = XMLString::transcode("name");
               attr = (DOMAttr *) pAttribus->getNamedItem(nameAttr);
               XMLString::release(&nameAttr);

               char *value = XMLString::transcode(attr->getValue());
               cout << xTab << "<FILE> " << value << "\n" << endl;
               XMLString::release(&value);

               ++count;
            }

            XMLString::release(&Type);
         }

         else {   
            for (child = n->getFirstChild(); child != 0; child=child->getNextSibling())
               count += displayElements(child,count_call);
         }
      }
   }

   return count;
}


// Fonction Main

int main(int argC, char* argV[])
{
   bool erreur = false;

   // Vérifie le bon nombre d'arguments
   if(argC < 2) {
      cout << "Usage : " << argV[0] << " filetoparse.xml" << endl;

      return 1;
   }

   // Initialisation du parser
   try {
       XMLPlatformUtils::Initialize();
   }

   catch (const XMLException& err) {
       cerr << "Erreur pendant l'initialisation de Xerces-C++ :\n"
           << XMLString::transcode(err.getMessage())
           << endl;

       return 2;
   }

   // Faire en sorte que le parser DOM renvoie tous les codes d'erreurs
   AbstractDOMParser::ValSchemes valScheme = AbstractDOMParser::Val_Auto;


   // Instancie le parser DOM
   XercesDOMParser *parser = new XercesDOMParser;

   // Instancie un ErrorHandler et le lie au parser
   ErrReporter *errHandler = new ErrReporter();
   parser->setErrorHandler(errHandler);

   DOMDocument *doc;
   unsigned int duration;

   // Parse le fichier XML et récupère le temps mis pour le parsing
   try {
      parser->resetDocumentPool();

      const unsigned long startMillis = XMLPlatformUtils::getCurrentMillis();

      parser->parse(argV[1]);
      doc = parser->getDocument();

      cout << "======== Parsing " << argV[1] << " ========\n" << endl;

      const unsigned long endMillis = XMLPlatformUtils::getCurrentMillis();
      duration = endMillis - startMillis;
   }

   // Gestion des exceptions possibles pendant le parsing

   // Exception XML
   catch (const XMLException& err) {
      cerr << "Erreur XML pendant le parsing du fichier : " << argV[1] << "\n"
          << "Exception XML : \n"
          << XMLString::transcode(err.getMessage()) << "\n" <<  endl;

      erreur = true;
   }

   // Exception DOM
   catch (const DOMException& err) {
      const unsigned int maxChars = 2047;
      XMLCh errText[maxChars + 1];

      cerr << "Erreur DOM pendant le parsing du fichier : " << argV[1] << "\n"
          << "Code d'erreur DOM : " << err.code << "\n" << endl;

      if (DOMImplementation::loadDOMExceptionMsg(err.code, errText, maxChars))
         cerr << "Exception DOM : " << XMLString::transcode(errText) << "\n" <<  endl;

      erreur = true;
   }

   // Autre exception
   catch (...) {
      cerr << "Erreur inattendue durant le parsing du fichier : "
          << argV[1] << "\n" << endl;

      erreur = true;
   }

   unsigned int compteur;

   if(doc && !errHandler->fSawErrors) {
      // Affiche les éléments du fichier XML
      compteur = displayElements((DOMNode*)doc->getDocumentElement(),0);
   }

   // Affiche le nombre d'éléments du fichier XML
   cout << "Nombre d'élements du fichier " << argV[1] << " : "
       << compteur << "\n" << endl;

   // Affiche le temps mis pour le parsing
   cout << "Temps de parsing du fichier " << argV[1] << " : "
       << duration << " ms" << endl;
   
   // Supprime le handle d'erreur
   delete errHandler;

   // Supprime le parser
   delete parser;

   // Appel à la méthode Terminate
   XMLPlatformUtils::Terminate();

   if(erreur == true)
      return 3;

   else
      return 0;
}
 





ErrReporter.cpp

 

Code:

#include <xercesc/sax/SAXParseException.hpp>
#include <iostream>
#include <string>

#include "ErrReporter.hpp"

using namespace std;

void ErrReporter::warning(const SAXParseException&) {
   // Ignore les avertissements
   // On peut cependant très bien afficher les messages
   // d'avertissements en codant cette fonction
   // comme l'une des suivantes
}

void ErrReporter::error(const SAXParseException& mess) {
   fSawErrors = true;
   cerr << "Erreur dans le fichier \"" << XMLString::transcode(mess.getSystemId())
       << "\", ligne " << mess.getLineNumber()
       << ", colonne " << mess.getColumnNumber()
         << "\nMessage d'erreur : " << XMLString::transcode(mess.getMessage()) << endl;
}

void ErrReporter::fatalError(const SAXParseException& mess) {
   fSawErrors = true;
   cerr << "Erreur fatale dans le fichier \"" << XMLString::transcode(mess.getSystemId())
       << "\", ligne " << mess.getLineNumber()
       << ", colonne " << mess.getColumnNumber()
         << "\nMessage d'erreur : " << XMLString::transcode(mess.getMessage()) << endl;
}

void ErrReporter::resetErrors() {
   fSawErrors = false;
}
 





ErrReporter.hpp

 

Code:

#include <xercesc/util/XercesDefs.hpp>
#include <xercesc/sax/ErrorHandler.hpp>
#include <iostream>

XERCES_CPP_NAMESPACE_USE


class ErrReporter : public ErrorHandler {
public:
   ErrReporter() : fSawErrors(false) {
    }

   ~ErrReporter() {
    }


    // Méthodes d'implémentation de ErrorHandler
    void warning(const SAXParseException& mess);
    void error(const SAXParseException& mess);
    void fatalError(const SAXParseException& mess);
    void resetErrors();

   // Méthode Get
    bool getSawErrors() const;

    // Donnée privée permettant de savoir si des erreurs
    // ont eu lieu avec getSawErrors() et de remettre le
    // compteur d'erreurs à zéro
    bool fSawErrors;
};

inline bool ErrReporter::getSawErrors() const {
    return fSawErrors;
}
 




En exécutant le programme, on obtient à l'écran l'arborescence complète du fichier XML :

 

Code:

======== Parsing fichier.xml ========

    <FILE> New Text Document.txt

    ----------------------

    <DIR> EasyPHP1-8

        <FILE> EasyPHP.log

        <FILE> EasyPHP.exe

        ----------------------

        <DIR> mysql

                <FILE> my-large

Nombre d'Úlements du fichier fichier.xml : 6

Temps de parsing du fichier fichier.xml : 15 ms
 




A présent le parser DOM codé, attaquons-nous au DOMWriter !





Créer ses documents XML en codant un DOMWriter

Avoir le pouvoir d'écrire des données XML facilement est également un atout qu'apporter la librairie Xerces-C++. Afin de
présenter ces fonctionnalités, j'ai codé un petit exemple regroupant l'essentiel : création d'un document XML, avec un
noeud racine, un élément avec un attribut et une valeur.
Ainsi il suffira de reproduire plusieurs fois ce qui est fait dans ce code ( coder des fonctions, etc ) pour créer
tout un fichier XML avec des centaines d'éléments imbriqués, des attributs, etc.

Descriptif des méthodes utilisées pour le DOMWriter (en supplément des méthodes utilisés pour le parser) :

DOMImplementation::createDocument(...)
Créé un document XML vide et renvoie un pointeur DOMDocument* vers ce document.

DOMDocument::getDocumentElement()
Renvoie un pointeur DOMElement* vers l'élément racine du document.

DOMDocument::createElement(const XMLCh* tagName)
Créé un élément ayant le nom tagName dans le document XML et renvoie un pointeur DOMElement* vers celui-ci.

DOMDocument::createAttribute(const XMLCh* name)
Créé un attribut ayant le nom name et renvoie un pointeur DOMAttr vers-celui-ci. Pour que l'attribut ai une valeur, il faut
utiliser DOMAttr::setValue et pour le lier à un élément, utiliser DOMElement::setAttributeNode()

DOMAttr::setValue(const XMLCh* value)
Paramètre la valeur de l'attribut à value.

DOMElement::setAttributeNode(DOMAttr* newAttr)
Rajoute/lie un attribut à un élément du document XML ( DOMElement* ).

DOMDocument::createTextNode(const XMLCh* data)
Ecrit une valeur et la renvoie dans un pointeur DOMText*. On peut lier cette valeur à un élément avec DOMNode::appendChild()

DOMNode::appendChild(DOMNode* newchild)
Rajoute/lie une valeur ( DOMText* ) à un noeud XML.

XMLUni::fgDOMWRTFormatPrettyPrint
Permet d'avoir en sortie des données XML lisibles facilement par un être humain ( tabulations, retours chariot, etc )

LocalFileFormatTarget::LocalFileFormatTarget(...)
Constructeur de la classe LocalFileFormatTarget, il permet de spécifier le chemin du fichier XML dans lequel on enregistre
le DOMDocument* et renvoie un pointeur XMLFormatTarget* contenant ce chemin. On peut utiliser StdOutFormatTarget::StdOutFormatTarget() afin d'afficher le document XML à l'écran au lieu de l'enregistrer dans un fichier.

DOMWriter::writeNode(XMLFormatTarget *const destination, const DOMNode &nodeToWrite)
Enregistre le document XML au chemin destination.



DOMWriter.cpp

 

Code:

#include <xercesc/util/PlatformUtils.hpp>
#include <xercesc/util/XMLString.hpp>
#include <xercesc/parsers/AbstractDOMParser.hpp>
#include <xercesc/dom/DOM.hpp>
#include <xercesc/parsers/XercesDOMParser.hpp>
#include <xercesc/framework/LocalFileFormatTarget.hpp>
#include <xercesc/framework/StdOutFormatTarget.hpp>

#include <string>
#include <iostream>

XERCES_CPP_NAMESPACE_USE
using namespace std;

int main(int argC, char* argV[])
{
   bool erreur = false;

   // Vérifie le bon nombre d'arguments
   if(argC < 2) {
      cout << "Usage : " << argV[0] << " file.xml" << endl;

      return 1;
   }

   // Initialisation du parser
   try {
       XMLPlatformUtils::Initialize();
   }

   catch (const XMLException& err) {
       cerr << "Erreur pendant l'initialisation de Xerces-c++ :\n"
           << XMLString::transcode(err.getMessage())
           << endl;

       return 2;
   }

   XMLCh* value = XMLString::transcode("LS");
   DOMImplementation* dom_impl = DOMImplementationRegistry::getDOMImplementation(value);
   XMLString::release(&value);

   DOMDocument* doc;

   try {
      // Création du document XML vide avec comme
      // noeud racine "arborescence"
      value = XMLString::transcode("arborescence");
      doc = dom_impl->createDocument(NULL,value,NULL);
      XMLString::release(&value);
   }

   catch(const DOMException& err) {
       cerr << "Erreur pendant la creation du document XML ( DOM Exception ) :\n"
           << XMLString::transcode(err.getMessage())
           << endl;

       return 3;
   }

   // Récupère un pointeur DOMElement vers le noeud racine
   DOMElement* root = doc->getDocumentElement();

   DOMElement* elementDir;
   DOMAttr* attrDir;
   DOMText* File;

   try {
      // Créer un élément
      value = XMLString::transcode("directory");
      elementDir = doc->createElement(value);
      XMLString::release(&value);

      // Créer un attribut
      value = XMLString::transcode("type");
      attrDir = doc->createAttribute(value);
      XMLString::release(&value);

      // Configuration de la valeur de l'attribut
      value = XMLString::transcode("directory");
      attrDir->setValue(value);
      XMLString::release(&value);

      // Créer une valeur texte
      value = XMLString::transcode("php.exe");
      File = doc->createTextNode(value);
      XMLString::release(&value);
   }

   catch(const DOMException& err) {
       cerr << "Erreur pendant la creation des noeuds ( DOM Exception ) :\n"
           << XMLString::transcode(err.getMessage())
           << endl;

       return 3;
   }

   try {
      // Lie la valeur au noeud
      elementDir->appendChild(File);

      // Lieu l'attribut au noeud
      elementDir->setAttributeNode(attrDir);

      // Lie le noeud à la racine du document
      root->appendChild(elementDir);
   }

   catch(const DOMException& err) {
       cerr << "Erreur pendant la création ddes liens entre les noeuds ( DOM Exception ) :\n"
           << XMLString::transcode(err.getMessage())
           << endl;

       return 3;
   }

   DOMWriter *domWriter = ((DOMImplementationLS*)dom_impl)->createDOMWriter();

   if (domWriter->canSetFeature(XMLUni::fgDOMWRTSplitCdataSections, true))
       domWriter->setFeature(XMLUni::fgDOMWRTSplitCdataSections, true);

   if (domWriter->canSetFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true))
    domWriter->setFeature(XMLUni::fgDOMWRTFormatPrettyPrint, true);
   
   value = XMLString::transcode(argV[1]);

   // OU XMLFormatTarget *fileTarget = new StdOutFormatTarget();
   XMLFormatTarget *fileTarget = new LocalFileFormatTarget(value);
   XMLString::release(&value);

   domWriter->writeNode(fileTarget, *doc);

   delete fileTarget;
   delete domWriter;
   delete doc;

   XMLPlatformUtils::Terminate();
   
   return 0;
}
 





Nous obtenons comme fichier XML :

 

Code:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<arborescence>

  <directory type="php">php.exe</directory>

</arborescence>
 





Voilà, on a à présent deux programmes fonctionnels permettant de créer & parser des données XML ... Il ne reste plus qu'à mettre tout ça en pratique pour vos futurs exécutables utilisant XML, comme base de données, ou autre.

Bon coding,

Deimos