IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

4D, XML et Word 2003 Windows

Nous allons montrer dans ce document comment 4D 2004 peut exporter des données en XML qui pourront directement être utilisées par MS Word 2003 afin de construire des documents dynamiques. Nous verrons également des exemples de code VBA, de scripts VBScript et une application des possibilités de la nouvelle commande TRAITER BALISES HTML. ♪

Article lu   fois.

L'auteur

Site personnel

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

I. Introduction

Les ouvertures apportées par MS Office 2003 dans la coopération avec 4D ont déjà fait l’objet de différentes notes techniques :

  • Intégration de 4D et Office 2003, par Julien FEASSON, 4D Inc., Note technique 4D-200402-05-FR ;
  • Interaction entre 4D 2003 et Microsoft Excel (Services Web), par Matthieu Chevrier, 4D Inc., Note technique 4D-200302-06-FR.

Nous allons montrer dans ce document comment 4D 2004 peut exporter des données en XML qui pourront directement être utilisées par MS Word 2003 afin de construire des documents dynamiques. Nous verrons également des exemples de code VBA, de scripts VBScript et une application des possibilités de la nouvelle commande TRAITER BALISES HTML.

Note : Cette technique ne fonctionne pas sur Macintosh et n’est disponible que dans la version stand-alone de MS Word 2003 Windows ou dans la version « MS Office Professionnal ».

II. Le cahier des charges

Soit un cabinet médical devant rédiger des lettres à destination du cabinet d’un confrère. Le modèle des lettres est défini et des champs variables relatifs aux informations du patient et du confrère destinataire de la lettre sont recensés.

Voici un exemple de lettre :

Pictures 0531x0562
Figure 1 - exemple de compte-rendu

Voici la structure extrêmement simplifiée de la base de données correspondante :

Pictures 0378x0218
Figure 2 - structure de la base de données des actes

Organisation de l’exemple

Nous ne traitons pas ici de la création des enregistrements côté 4D, supposons simplement qu’à un acte chirurgical corresponde un enregistrement dans la table [ACTE] qui nous permet de retrouver les données associées. Nous nous focalisons ici exclusivement sur la liaison avec Word.

Quand un utilisateur visualisant un enregistrement ACTE clique sur le bouton 'Compte_Rendu', le logiciel doit présenter une liste de modèles de documents Word. L’utilisateur choisit un modèle, clique sur un bouton 'Editer' et se retrouve dans Word qui affiche un document généré à partir du modèle sélectionné et présentant les données relatives à l’acte en cours de consultation.

Liaison avec les données

Il existe plusieurs moyens dans Word pour référencer les items d’un document en relation avec des données variables. Dans cet exemple, notre choix se porte sur l’insertion de champ de type INCLUDETEXT décrivant un chemin d’accès vers le contenu d’un élément XML dans un fichier externe.

Cette possibilité de liaison avec une donnée XML est apparue avec la version 2003 d’Office, même si les champs de type INCLUDETEXT existaient déjà dans les versions précédentes. Cependant, cette fonctionnalité :

  • n’existe pas dans les versions Macintosh d’Office ;
  • n’est pas activée dans les versions autres que stand-alone ou « Office Professional » de Word Windows 2003.

Nous verrons dans une prochaine note une autre manière de référencer des données externes qui sera utilisable sur Office 2004 Mac.

III. Export des données XML

Le modèle Word se réfère donc aux champs dynamiques présents dans un document externe.

Deux possibilités s’offrent à nous pour construire ce document :

  • générer complètement le document XML à chaque demande ;
  • utiliser un modèle (template) où nous modifions seulement les valeurs à chaque demande et pas la structure, c’est-à-dire les noms et organisations des balises XML.

Dans les deux cas, nous souhaitons obtenir un document semblable à celui-ci :

 
Sélectionnez
   <root>
      <Medecin>
         <Prenom>Louis</Prenom>
         <Nom>Knock</Nom>
      </Medecin>
      <Chirurgien>
         <Prenom>Arthur</Prenom>
         <Nom>Delascie</Nom>
      </Chirurgien>
      <Patient>
         <Prenom>Honoré</Prenom>
         <Nom>Duchemin</Nom>
         <Titre>Monsieur</Titre>
         <NoSecu>1234567890</NoSecu>
         <Telephone>01 45 67 38 90</Telephone>
         <Adresse>2 place des actes</Adresse>
         <Adresse_suite/>
         <CP>92000</CP>
         <Ville>Nanterre</Ville>
      </Patient>
   </root>

Génération du document XML

Nous choisissons de générer un document « acte4D.xml » en utilisant les commandes DOM de 4D 2004. Celles-ci nous permettent de construire un arbre DOM en mémoire puis d’enregistrer (séraliser) cet arbre dans une variable ou un fichier disque.

Voici le code de génération du document :

 
Sélectionnez
C_BOOLEEN($0)


  `--- Racine et espace de nom
C_TEXTE($_vt_root)
$_vt_root:="root"
C_TEXTE($_vt_ns)
$_vt_ns:="schema.xsd"

C_TEXTE($_vt_Ref_XML)
$_vt_Ref_XML:=DOM Creer ref XML($_vt_root;$_vt_ns)

DOM_SetEncoding ($_vt_Ref_XML;"UTF-8")  `encodage en utf-8

demo_get_Medecin_XML ($_vt_Ref_XML)
demo_get_Chirurgien_XML ($_vt_Ref_XML)
demo_get_Patient_XML ($_vt_Ref_XML)

  `--- Le doc est-il bien formé ?
  `pour le vérifier, on l’exporte vers une variable
  `que l’on réanalyse sous forme d’arbre DOM
  `(on pourrait aussi le valider/DTD)
C_BLOB($_vx_XML)
DOM EXPORTER VERS VARIABLE($_vt_Ref_XML;$_vx_XML)

C_TEXTE($_vt_Ref_XML_Analyse)
$_vt_Ref_XML_Analyse:=DOM Analyser variable XML($_vx_XML)

Si (ok=1) & (DOM_ifNoError ($_vt_Ref_XML_Analyse))
    $0:=Vrai
      `aucun contrôle n’est fait par 4D au moment de l’écriture
    DOM EXPORTER VERS FICHIER($_vt_Ref_XML;<>DEMO_vt_docXML_path)
Sinon
    $0:=Faux
      `une erreur est survenue
      `on recopie l’arbre DOM ds le presse-papiers pour débogage
    EFFACER PRESSE PAPIERS
    AJOUTER A PRESSE PAPIERS("TEXT";$_vx_XML)
    ALERTE("L’arbre XML DOM a été copié dans les presse-papiers")
Fin de si

DOM FERMER XML($_vt_Ref_XML_Analyse)   `l’arbre analysé pour vérification

DOM FERMER XML($_vt_Ref_XML)   `l’arbre DOM généré pour export

Notez que nous utilisons DOM EXPORTER VERS VARIABLE, puis DOM Analyser variable XML pour réanalyser le document construit afin de vérifier qu’il est bien formé.

Les méthodes d’exports spécifiques à une table sont très simples, par exemple demo_get_Patient_XML :

 
Sélectionnez
C_TEXTE($1;$_vt_Ref_XML)

$_vt_Ref_XML:=$1

C_TEXTE($_vt_RefMedecin)
$_vt_RefMedecin:=DOM Creer element XML($_vt_Ref_XML;"Patient")

DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_RefMedecin;"Prenom";[PATIENT]Prenom)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_RefMedecin;"Nom";[PATIENT]Nom)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_RefMedecin;"Titre";[PATIENT]Titre)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_RefMedecin;"NoSecu";[PATIENT]NoSecu)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_RefMedecin;"Telephone";[PATIENT]Telephone)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_RefMedecin;"Adresse";[PATIENT]adresse)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_RefMedecin;"Adresse_suite";[PATIENT]adresse_suite)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_RefMedecin;"CP";[PATIENT]code_postal)
DOM_AJOUTER_ELEMENT_SIMPLE ($_vt_RefMedecin;"Ville";[PATIENT]ville)

Cette méthode utilise la routine DOM_AJOUTER_ELEMENT_SIMPLE afin de créer et d’écrire la valeur d’un élément XML en un seul appel :

 
Sélectionnez
C_TEXTE($1)

C_TEXTE($_vt_RefParen)
$_vt_RefParen:=$1

C_TEXTE($2)
C_TEXTE($_vt_NomElement)
$_vt_NomElement:=$2

C_TEXTE($3)
C_TEXTE($_vt_ValeurElement)
    $_vt_ValeurElement:=$3

C_TEXTE($_vt_RefElement)

`Ajout d’un élément et de sa valeur
$_vt_RefElement:=DOM Creer element XML($_vt_RefParen;$_vt_NomElement)

DOM ECRIRE VALEUR ELEMENT XML($_vt_RefElement;$_vt_ValeurElement)

IV. Liaison avec les données XML

Ouvrons notre document Word et sélectionnons le menu 'Insertion/Champ…' puis le type de champ 'InclureTexte', le dialogue suivant s’affiche :

Pictures 0455x0258

Dans la zone 'Propriétés du champ/Nom de fichier ou URL' nous saisissons l’emplacement du fichier XML exporté par 4D sur disque ou l’URL d’où recevoir le document. Dans notre exemple nous renseignons : « C:\\ acte4D.xml ».

La zone 'Options du champ' nous propose des paramétrages supplémentaires, mais la saisie y est malaisée en raison de la petite taille des champs de saisie, une maladresse d’interface récurrente chez Microsoft. C’est pourquoi nous basculons en mode de saisie directe par un clic sur le bouton en bas à gauche 'Codes de champ'. Nous obtenons le dialogue suivant :

Pictures 0455x0258

Le bouton 'Masquer les codes' joue le rôle inverse pour revenir à la vue précédente.

Voici la chaîne de paramétrage complète à saisir sous 'Codes de champ :' pour lier le champ avec l’information nom du patient présente dans le document XML :

INCLUDETEXT « C:\\acte4D.xml » \* FirstCap \c xml \n xmlns:ns1='schema.xsd' \x /ns1:root/ns1:Patient/ns1:Nom

Le rôle de chaque paramètre de la chaîne (appelé commutateur dans Word) est décrit dans le dialogue qui s’obtient en cliquant sur le bouton 'Options…'. Le premier onglet fixe des options de mise en forme, comme la première lettre en majuscule, représentée par FirstCap dans notre chaîne. Le second onglet donne accès aux commutateurs spéciaux, ici ceux de la liaison avec une source XML :

Pictures 0288x0216

Voici le rôle de chacun des commutateurs :

  • \! Empêche la mise à jour des champs faisant partie du fichier inclus ;
  • \c Nom du convertisseur de texte requis pour le format du fichier inclus, ici « \c xml » ;
  • \n Mappages des espaces de noms pour les requêtes XPath, ici « \n ; xmlns:ns1=’schema.xsd' » ;
  • \t Emplacement de la transformation XML à utiliser, ici nous n’en utilisons pas (il s’agit d’une transformation XSL-T) ;
  • \x XPath pour la section souhaitée du fichier XML, ici « \x /ns1:root/ns1:Patient/ns1:Nom » Une expression XPath permet de désigner très précisément un élément au sein d’un document XML. Elle s’exprime dans sa forme la plus simple comme un chemin d’accès hiérarchique donnant les étapes pour atteindre l’élément souhaité : 'Nom' fils de 'Patient' fils de 'root' dans l’espace de nom 'ns1', soit ici 'schema.xsd'.

Une fois le champ paramétré, il s’affiche sur fond gris dans le document Word :

Pictures 0518x0113

Un clic droit sur l’un des champs permet d’accéder aux différentes actions :

  • mettre à jour les champs : rafraîchit la valeur du champ depuis le fichier lié ;
  • modification du champ… : rouvre le dialogue de paramétrage, la chaîne est ré analysé :
Pictures 0455x0258
  • basculer les codes de champ : bascule entre l’affichage de la valeur du champ et l’affichage de la chaîne d’options. Ce basculement s’effectue champ par champ, comme le montre la copie d’écran un peu plus haut où seul le champ Nom est présenté de cette manière. La saisie directe des commutateurs est alors possible, ce qui se révèle la méthode la plus efficace à l’usage.

Pour plus d’informations, consulter l’aide en ligne 'à propos des champs'.

Test de notre solution

Une fois notre document Word complètement paramétré, nous pouvons tester la solution en déclenchant l’export des données et l’ouverture du document depuis 4D. L’ouverture du document Word est réalisée par la routine ZDOC_Ouvre_Word :

 
Sélectionnez
  ` ----------------------------------------------------

  ` Nom utilisateur (OS) : christophe Keromen
  ` Date et heure : 08/05/04, 07:48:12
  ` ----------------------------------------------------
  ` Methode : ZDOC_Ouvre_Word
  ` Description
  ` Ouverture d’un document $1 ds IE
  `
  ` Parametres
  `$1:TEXTE:Chemin d’accès vers le DOC
  ` ----------------------------------------------------

C_TEXTE($1)
C_TEXTE($_vt_PathDoc)
$_vt_PathDoc:=$1

Si (ENV_si_Windows )
    CHANGER TYPE DOCUMENT($_vt_PathDoc;"DOC")
Sinon
    CHANGER TYPE DOCUMENT($_vt_PathDoc;"DOC")
    CHANGER CREATEUR DOCUMENT($_vt_PathDoc;"MSWD")
Fin de si

  `Déclenche l’ouverture du doc suivant son type et créateur
C_ENTIER($_ve_Error)
$_ve_Error:=AP ShellExecute ($_vt_PathDoc)

Si ($_ve_Error#0)
    ALERTE(Chaine($_ve_Error))
    TRACE
Fin de si

Nous utilisons la commande AP ShellExecute du plugin 4D Pack, car elle nous permet de nous affranchir de la connaissance de l’emplacement de l’application Word sur le disque hôte. L’ouverture de l’application est réalisée par le système sur la base de l’application associée à l’extension du fichier à ouvrir, ici « .doc ».

Tout se passe bien… sauf en ce qui concerne les informations affichées : ce ne sont pas celles de notre enregistrement courant ! Pourtant le document XML exporté est correct, que se passe-t-il ?

Effectuons un clic droit sur l’un de nos champs et sélectionnons ' Mettre à jour les champs' : la valeur correcte s’affiche. Conclusion, Word ne met pas à jour les champs à l’ouverture d’un document. Problème !

Provoquer la mise à jour des champs

Il faut donc que nous puissions provoquer la mise à jour des champs. Comment faire ? Il suffit d’écrire le code VBA (VisualBasic For Application) suivant :

 
Sélectionnez
   Sub CK_MajChamps()
      '
      ' CK_MajChamps
      ' Mise à jour des champs
      '

         ' désactiver la mise à jour de l’écran
      ScreenUpdating = False

      ' màj les champs
   ActiveDocument.Fields.Update

      ' réactiver la mise à jour de l’écran
   ScreenUpdating = True
   Application.ScreenRefresh

   End Sub

Mais comment provoquer l’exécution de ce code ?

Une première solution consiste à déclencher l’exécution de cette fonction à l’ouverture du document, de manière systématique. Pour cela, il suffit d’utiliser une macro AutoOpen :

 
Sélectionnez
   Sub AutoOpen()
      ' à l’ouverture du document : màj les champs
      ' CK_MajChamps
   End Sub

Les macros nommées AutoOpen s’exécutent systématiquement à l’ouverture d’un document.

Nous pouvons également recourir à une méthode événementielle, nommée « Document_ » suivi du nom de l’événement déclenchant la méthode :

 
Sélectionnez
   Private Sub Document_Open()
         'à l’ouverture du document : màj les champs
      CK_MajChamps
   End Sub

Cela fonctionne, mais la mise à jour sera effectuée à chaque ouverture du document par rapport aux valeurs du dernier fichier exporté depuis 4D! Autrement dit, les valeurs initiales du document seront écrasées à chaque mise à jour.

Deux approches permettent de résoudre ce problème :

  1. Figer les références une fois la mise à jour effectuée ;
  2. Déclencher la mise à jour par programmation de manière non systématique.

Figer les références

Encore une fois, nous exploitons la richesse de VBA, la petite fonction ci-dessous s’acquitte de cette tâche :

 
Sélectionnez
   Sub CK_FigerValeur()
         ' pour chaque champ du document   
      For Each aField In ActiveDocument.Fields
            ' s’il s’agit d’un champ de type IncludeText
         If (aField.Type = wdFieldIncludeText) Then
            aField.Update ' mettre à jour le champ
            aField.Unlink ' supprimer le lien en conservant la valeur
         End If
      Next aField
   End Sub

Déclencher la mise à jour

Cette solution s’avère plus délicate, car elle demande à pouvoir programmer Word depuis l’extérieur, objectif pour lequel VBA trouve ses limites. La seule manière de programmer Word depuis 4D consiste à recourir à un plugin apportant à 4D le support d’OLE Automation. Cette technologie consiste justement à piloter une application compatible depuis une autre application. Mais nous souhaitons éviter le recours à un plugin.

Heureusement, Windows Host Scripting (WHS) va venir à notre secours… Cette technologie présente au cœur du système Windows ne permet pas seulement aux virus d’effacer le contenu des disques durs, elle autorise également l’instanciation et le pilotage des ActiveX par programmation, dont ceux des applications Office.

V. La couche finale : scripting de Word depuis 4D

En réalité ce n’est pas réellement 4D qui va piloter Word. 4D va traiter un script écrit en VBScript (la déclinaison de Visual Basic pour le scripting) et demander à WHS d’exécuter ce script.

Voici le script que nous utiliserons, notez que les parties variables du script sont implémentées sous la forme d’appels à des variables 4D par des balises propriétaires, celles utilisées par le serveur Web, par exemple <!--#4DVAR <>DEMO_vt_docWord_path--> :

 
Sélectionnez
      'Creation d’un Objet de type Word
   Dim WordObj
   Set WordObj=CreateObject("Word.application")
   WordObj.Visible = false ' Exécution en arrière-plan
      ' ouverture du document Word contenant les champs à mettre à jour
   Dim objWordDoc 
   Set objWordDoc=WordObj.Documents.open("<!--#4DVAR <>DEMO_vt_docWord_path--> ")
      ' Mise à jour des champs
      '
      ' désactiver la mise à jour de l’écran 
   ScreenUpdating = False
    
      ' màj les champs
   objWordDoc.Fields.Update

      ' réactiver la mise à jour de l’écran    
   ScreenUpdating = True
   WordObj.ScreenRefresh
      ' enregistrer le résultat    
   objWordDoc.SaveAs "<!--#4DVAR DEMO_vt_docWordResult_path--> "
      ' quitter Word
   WordObj.Quit
      ' Nettoyer la mémoire
   Set objWordDoc = nothing
   Set WordObj = nothing

Il nous suffit maintenant de rajouter dans notre méthode 4D le traitement de ce script et son exécution depuis 4D :

Méthode demo_VBS_prepare
Sélectionnez
  `chargement du script en BLOB
C_BLOB($_vx_script)
DOCUMENT VERS BLOB(<>DEMO_vt_script_path;$_vx_script)

  `traitement des balises 4D contenues ds le script
TRAITER BALISES HTML($_vx_script;$_vx_script)
`ECRIRE TEXTE DANS PRESSE PAPIERS(BLOB vers texte($_vx_script;Texte sans longueur ))

  `enregistrement du nouveau script
C_TEXTE($_vt_script_path)
$_vt_script_path:=Dossier temporaire+"updateFields.vbs"
BLOB VERS DOCUMENT($_vt_script_path;$_vx_script)

  `exécution du script
C_ENTIER($_ve_Error)
$_ve_Error:=AP ShellExecute ($_vt_script_path)
Si ($_ve_Error#0)
    ALERTE(Chaine($_ve_Error))
    TRACE
Fin de si

  `on attend que le document soit généré
Repeter
    ENDORMIR PROCESS(Numero du process courant;10)
Jusque (Tester chemin acces(DEMO_vt_docWordResult_path)=Est un document )

Notez l’utilisation de la commande 4D 2004 TRAITER BALISES HTML qui permet de remplacer les balises 4D présentes dans le document par les valeurs des variables 4D.

Les possibilités de cette commande sont décrites dans la note « Quelques utilisations de la commande TRAITER BALISES HTML… » par Julien FEASSON, 4D Inc., note technique 4D-200504-12-FR.

Attention : la commande TRAITER BALISES HTML encode les caractères étendus en appels de caractères : « è » devient « &#232 ». La technique utilisée ici trouve ainsi ses limites. Si vous devez utiliser, par exemple, des chemins d’accès comportant des accents, il faudra passer par un traitement direct des chaînes dans un BLOB.

Nous exploitons au travers d’un appel à AP ShellExecute le fait que le système appelle automatiquement WHS lors d’une demande d’ouverture de tout document d’extension « .vbs ».

La méthode complète d’export

 
Sélectionnez
  ` ----------------------------------------------------

  ` Nom utilisateur (OS) : christophe Keromen
  ` Date et heure : 24/05/04, 16:27:54
  ` ----------------------------------------------------
  ` Methode : demo_Acte_Exporter_XML
  ` Description
  ` ex. de génération d’un document XML servant à une lettre Word 2003
  `
  ` Parametres
  ` ----------------------------------------------------

XML_AppelerSurErreur_Start    `sert à détecter une erreur capturée par XML_AppelerSurErreur

  `Chemin d’accès en dur au template XML
Si (Tester chemin acces(<>DEMO_vt_docXML_path)=Est un document )
    SUPPRIMER DOCUMENT(<>DEMO_vt_docXML_path)
Fin de si

C_HEURE($_vh_refDoc)
$_vh_refDoc:=XML_Creer_Document (<>DEMO_vt_docXML_path)   `crée le doc XML sur disque
FERMER DOCUMENT($_vh_refDoc)

Si (ok=1)

    Si (demo_XML_genere )   `génération du doc XML OK

          `suppression du document Word pouvant déjà exister
        C_TEXTE(DEMO_vt_docWordResult_path)
        DEMO_vt_docWordResult_path:=<>DEMO_vt_docWordResult_path+[PATIENT]Nom+".doc"
        Si (Tester chemin acces(DEMO_vt_docWordResult_path)=Est un document )
            SUPPRIMER DOCUMENT(DEMO_vt_docWordResult_path)
        Fin de si

        APPELER SUR ERREUR("")

          `--- exécution d’un VBScript pour rafraichir les champs de données avant présentation à l’utilisateur
        demo_VBS_prepare

          `--- ouverture du document dans Word
        ZDOC_Ouvre_Word (DEMO_vt_docWordResult_path)

    Fin de si

Fin de si

VI. Conclusion

Le support croissant de XML par les applications ouvre de nouvelles perspectives d’échanges. Couplé avec un peu de scripting rendu dynamique grâce la commande TRAITER BALISES HTML, cela nous permet de réaliser dans un document Word une fusion de données avec des informations issues de 4D. Le tout de manière pleinement automatisée et sans devoir recourir à un plug-in spécialisé.

VII. Base exemple

Téléchargez la base exemple : base exemple

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

Ce document est issu de https://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.