Compléter les paramètres d'un document type (.docx) quelconque à l'aide d'un formulaire Access

Claude Leloup

Les techniques suivantes seront abordées :

- récupérer dans un fichier .docx toutes les chaînes de caractères comprises entre deux balises (ex. : |*un symbole*|) et les loger dans une table Access.
Nous examinerons deux méthodes : l'une en recourant aux expressions régulières (regex), l'autre en exploitant la fonction Split() ;

- à l'aide d'un formulaire Access, associer une valeur à chacun des symboles d'un document type et déclencher la confection d'un nouveau document Word dans lequel les symboles sont remplacés par leur valeur.

Si vous voulez réagir au contenu de cet article, un espace de discussion est ouvert sur le forum. Commentez .

- Titre : Compléter les paramètres d'un document type (.docx) quelconque à l'aide d'un formulaire Access

- Auteur : Claude Leloup

- Parution : 11 juillet 2017

- Public visé :

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2017 Claude Leloup. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. L'idée

- II. Une fonction pour trouver les symboles contenus dans un fichier Word (utilisation des expressions régulières)

- II-A. getTagInContent() - une fonction pour trouver les tags dans un contenu texte quelconque

- II-B. Une fonction pour appeler getTagInContent() avec un document Word

- II-C. Un exemple d'utilisation

- III. fParamètres, le formulaire qui permet de piloter la manœuvre

- IV. Une variante pour la recherche des symboles : Split() au lieu des regex

- V. Téléchargement

- VI. Remerciements

I - L'idée

On confectionne d'abord un document type dans lequel les portions variables à personnaliser sont représentées par des symboles précédés de « |* » et suivi de « *| », comme ceci :

D'autre part, on a le formulaire fParametres qui permet de rechercher ce document type :

Quand l'utilisateur a choisi, le formulaire se présente ainsi :

L'utilisateur complète chaque champ orange avec la valeur correspondant au symbole, par exemple :

et un clic sur le bouton ouvre ce document :

L'utilisateur reçoit alors la main sur Word pour apporter les retouches éventuelles.

II - Une fonction pour trouver les symboles contenus dans un fichier Word (utilisation des expressions régulières)

Ces fonctions ont été écrites par Arkham46.

Note d'Arkham46

J'ai tout mis en late binding (Object et createObject au lieu de typer les variables et d'ajouter les références), ça évite bien des soucis lors de l'exécution sur d'autres PC.

II-A - getTagInContent() - une fonction pour trouver les tags dans un contenu texte quelconque

Recherche de tags dans un contenu texte

1. Public Function getTagInContent(pContent As String)

2. Dim oReg As Object ' VBScript_RegExp_55.RegExp

3. Dim oResult As Object ' IMatchCollection

4. Dim oTag As Object

5. Dim sTag As String

6. Dim lRetColl As Collection

7. Set lRetColl = New Collection

8. Set oReg = CreateObject("VBScript.RegExp")

9. oReg.Pattern = "\|\*(.+?)\*\|"

10. oReg.MultiLine = True

11. oReg.Global = True

12. If oReg.Test(pContent) Then

13. Set oResult = oReg.Execute(pContent)

14. For Each oTag In oResult

15. sTag = oTag.subMatches(0)

16. On Error Resume Next

17. lRetColl.Add sTag, sTag

18. On Error GoTo 0

19. Next oTag

20. Else

21. MsgBox "Il n'y a pas de correspondance dans le document"

22. End If

23. Set oReg = Nothing

24. ' Et on retourne la collection

25. Set getTagInContent = lRetColl

26. End Function

N° d'instruction

Commentaires du code

9

Nous recherchons les chaînes de caractères de la forme |*Quelque chose*| qui se trouvent dans tout le texte.
Le pipe (« | ») et l'astérisque (« * ») sont des caractères réservés, il faut les précéder d'un antislash (« \ » pour exprimer leur valeur littérale :

« Quelque chose », dans les faits, c'est n'importe quel caractère en groupe de n'importe quelle longueur.
La syntaxe pour exprimer cela est :

- un point (« . »), pour dire « n'importe quel caractère » ;

- le signe plus (« + »), pour dire « répété une ou plusieurs fois ».

Exprimé ainsi, nous allons récupérer tout le texte compris entre le premier « |* » et le dernier « *| ». Pour dire :  arrêtez-vous chaque fois au premier « *| » rencontré, ou en d'autres mots, pour dire « relevez les plus petites correspondances », la syntaxe est d'ajouter un point d'interrogation (« ? »). Finalement :

10

Pour activer la recherche sur plusieurs lignes à la fois.

11

Pour préciser que la recherche porte sur toutes les occurrences.

12

On vérifie qu'il existe des correspondances.

13

Si oui, on déclenche la recherche.
oResult va contenir toutes les correspondances rencontrées.

14-19

On parcourt les résultats de la recherche.
Après l'exécution de l'instruction 12, oResult contient toutes les correspondances (balises « |* » et « *| » incluses), chacune dans un objet (ici oTag).
subMatches(0) est le premier bloc entre parenthèses du pattern => notre symbole.
On lance une boucle pour explorer chaque correspondance et loger celle-ci dans une collection (lRetColl).
Il se peut que le document type contienne plusieurs fois le même symbole donc plusieurs oTag.subMatches(0) identiques. Ce cas provoquerait une erreur à l'instruction 16, car dans une collection, les clés doivent être uniques. Les instructions 15 et 17 neutraliseront cette erreur éventuelle.

21

Message pour signaler qu'il n'y a pas de correspondance.

25

On affecte la collection des symboles à la fonction.

Si vous voulez presque tout savoir au sujet de l'utilisation des expressions régulières (regex) avec Access, voyez le tutoriel de cafeine : Les Expressions Rationnelles appliquées en VBA Access.

II-B - Une fonction pour appeler getTagInContent() avec un document Word

Public Function getTagInWord(poDoc As Object) ' Word.Document
Set getTagInWord = getTagInContent(poDoc.Content)
End Function

II-C - Un exemple d'utilisation

Public Function Test()
Dim oWord As Object ' Word.Application
Dim oDoc As Object ' Word.Document
Dim oTagColl As Collection
Dim vTag As Variant
Set oWord = CreateObject("Word.Application")
oWord.Visible = True
Set oDoc = oWord.Documents.Open(CurrentProject.Path & "\doc1.docx", , True) ' doc1.docx est ici logé dans le même répertoire que l'appli
Set oTagColl = getTagInWord(oDoc)
oWord.Quit False
Set oDoc = Nothing
Set oWord = Nothing
For Each vTag In oTagColl
Debug.Print vTag
Next vTag
End Function

III - fParamètres, le formulaire qui permet de piloter la manœuvre

À l'ouverture, il se présente comme ceci :

car il n'a pas de source et sa section Détail est invisible.

Quand l'utilisateur clique sur le bouton , le code suivant se déclenche :

1. Private Sub BtChoisir_Click()

2. Dim oWord As Object ' Word.Application

3. Dim oDoc As Object ' Word.Document

4. Dim oTagColl As Collection

5. Dim vTag As Variant

6. Set oWord = CreateObject("Word.Application")

7. Me.txtCheminType = ChoisirUnFichier(Me.hwnd, "Parcourir", 1, "Word", "docx")

8. Me.txtCheminPerso = Left(Me.txtCheminType, Len(Me.txtCheminType) - 5) & "_PERSO.docx"

9. Set oWord = CreateObject("Word.Application")

10. With oWord

11. .Visible = True

12. Set oDoc = .Documents.Open("""" & Me.txtCheminType & """", , True)

13. Set oTagColl = getTagInWord(oDoc)

14. .Quit

15. End With

16. Set oDoc = Nothing

17. Set oWord = Nothing

18. 'Vidanger et repeupler la table

19. DoCmd.SetWarnings False

20. DoCmd.RunSQL "Delete * from tParametres;"

21. For Each vTag In oTagColl

22. DoCmd.RunSQL "INSERT INTO tParametres ( Symbole ) SELECT """ & vTag & """ AS Expr1;"

23. Next

24. DoCmd.SetWarnings True

25. Me.RecordSource = "tParametres"

26. Me.Section("Détail").Visible = True

27. Me.txtCheminPerso.Visible = True

28. Me.etqCheminPerso.Visible = True

29. Me.txtNbreSymboles.Visible = True

30. End Sub

N° d'instruction

Commentaires du code

7

On déclenche l'ouverture d'une fenêtre de sélection de fichier et on loge le chemin dans le champ txtCheminType.

8

On construit le chemin qui sera affecté au document personnalisé (l'utilisateur pourra éventuellement le modifier).

9-12

Ouverture du .docx choisi à l'instruction 7.

13

Collecte des symboles contenus dans le document.

14-17

Fermeture de la session Word.

19-20

On vidange le contenu (éventuel) de la table tParametres.

21-24

On lance une boucle pour peupler la table tParametres : un enregistrement pour chaque tag trouvé dans le document.

25

On affecte tParametres comme source du formulaire.

26-29

On rend visibles les contrôles cachés à l'origine dans le formulaire.

Ce qui donne ceci pour notre exemple :

Au fur et à mesure que l'utilisateur saisira la valeur du symbole, le champ txtValeur passera au vert (mise en forme conditionnelle) :

Notez qu'il est possible d'encoder une valeur sur plusieurs lignes : il suffit de saisir <CTRL + ENTER> pour passer à la ligne :

Quand tout est complet, un clic sur le bouton déclenche ce code :

1. Private Sub btCreerDoc_Click()

2. Dim oWord As Object ' Word.Application

3. Dim sNomDoc As String

4. Dim rs As DAO.Recordset

5. On Error GoTo GestionErreurs

6. Me.Refresh

7. FileCopy Me.txtCheminType, Me.txtCheminPerso

8. 'Créer un RecordSet avec tParametres

9. Set rs = CurrentDb.OpenRecordset("tParametres")

10. rs.MoveFirst

11. 'Démarrer Word

12. Set oWord = CreateObject("Word.Application")

13. With oWord

14. .Visible = True

15. 'Ouvrir le document à personnaliser

16. .Documents.Open """" & Me.txtCheminPerso & """"

17. 'Remplacer le symbole par sa valeur

18. Do While Not rs.EOF

19. .Selection.Find.Execute FindText:="|*" & rs("Symbole") & "*|", _

20. ReplaceWith:=" " & rs("Valeur"), Replace:=2 '=wdReplaceAll

21. rs.MoveNext

22. Loop

23. 'Sauvegarder

24. .ActiveDocument.Save

25. 'Fermer et libérer les objets

26. .Quit

27. End With

28. Set oWord = Nothing

29. rs.Close

30. Set rs = Nothing

31. ' Ouvrir le doc perso

32. Call Ouvrir_fichier(Me.txtCheminPerso)

33. GestionErreurs:

34. Select Case err.Number

35. Case 0 ' pas d'erreur

36. Case Else

37. MsgBox "Erreur dans Sub btCreerDoc_Click" & Chr(13) & Chr(10) _

38. & "N° " & err.Number & " " & err.Description & "."

39. Set oWord = Nothing

40. rs.Close

41. Set rs = Nothing

42. End Select

43. End Sub

N° d'instruction

Commentaires du code

6

Pour s'assurer que la dernière intervention est enregistrée.

7

On prend une copie du document type original.

9-10

On crée un recordset de la table tParametres pour accéder à chacun des enregistrements.

12-16

On crée une session Word et on ouvre le document à personnaliser.

18-22

On lance une boucle pour lire chaque enregistrement du recordset et remplacer le symbole par sa valeur.
Remarquez l'espace inséré devant le symbole :

sinon les valeurs multilignes seront mal alignées (décalage d'une position vers la droite à partir de la deuxième ligne).

24-28

On sauvegarde le document personnalisé et on clôt la session Word.

29-30

On referme le recorset.

32

On affiche le document personnalisé.
La fonction Ouvrir_fichier(Chemin As String) permet d'ouvrir n'importe quel fichier avec le programme que l'utilisateur a associé à l'extension. Elle est proposée par Loufab dans cette discussion.

IV - Une variante pour la recherche des symboles : Split() au lieu des regex

Le code associé au clic de devient :

1. Private Sub BtChoisir_Click()

2. Dim oWord As Object ' Word.Application

3. Dim oDoc As Object ' Word.Document

4. Dim sDocType As String

5. Dim sTab() As String

6. Dim i As Integer

7. Dim iPos As Integer

8. Dim sTexteType As String

9. 'Choisir le fichier type

10. sDocType = ChoisirUnFichier(Application.hWndAccessApp, "Parcourir", 1, "Fichier Word", "docx")

11. 'Afficher dans le formulaire

12. Me.txtCheminType = sDocType

13. 'Proposer un chemin pour le fichier personnalisé

14. Me.txtCheminPerso = Left(Me.txtCheminType, Len(Me.txtCheminType) - 5) & "_PERSO.docx"

15. 'Ouvrir Word pour lire le document type

16. Set oWord = CreateObject("Word.Application")

17. oWord.Visible = True

18. Set oDoc = oWord.Documents.Open(sDocType, , True)

19. sTexteType = oDoc.content

20. 'Refermer Word

21. oWord.Quit False

22. Set oDoc = Nothing

23. Set oWord = Nothing

24. 'Isoler les parties du texte qui commencent par la balise de début |*

25. sTab = Split(sTexteType, "|*")

26. 'Vidanger la table tParametres

27. DoCmd.SetWarnings False

28. DoCmd.RunSQL "Delete * from tParametres;"

29. 'Repeupler la table tParametres

30. For i = 1 To UBound(sTab)

31. iPos = InStr(sTab(i), "*|")

32. DoCmd.RunSQL "INSERT INTO tParametres ( Symbole ) SELECT """ & Left(sTab(i), iPos - 1) & """ AS Expr1;"

33. Next i

34. DoCmd.SetWarnings True

35. 'Afficher le formulaire en entier

36. Me.RecordSource = "tParametres"

37. Me.Section("Détail").Visible = True

38. Me.txtCheminPerso.Visible = True

39. Me.etqCheminPerso.Visible = True

40. Me.txtNbreSymboles.Visible = True

41. End Sub

N° d'instruction

Commentaires du code

1-18

Ces instructions sont semblables à celles décrites au chapitre III.

19

On loge le contenu du .docx dans la variable sTexteType.

21-23

On ferme la session Word.

25

On applique la fonction Split() à sTexteType avec comme délimiteur la balise début « |* » du symbole.
À ce stade, le tableau sTab contient :
- dans sa première colonne [sTab(o)] : tout ce qui précède le 1er « |* » ;
- toutes les autres colonnes commenceront par un symbole suivi de « *| » et du texte.
Donc ce qui nous intéresse, nos symboles, c'est, à partir de la deuxième colonne de sTab, le début du contenu : ce qui précède « *| ».

30-33

On lance une boucle pour lire à partir de la deuxième colonne [stab(1)] jusqu'à la dernière.
En 32, on crée un enregistrement dans tParametres pour chaque symbole.
N.B. Les doublons éventuels seront éliminés puisque Symbole est la clé :

34-Fin

Ces instructions sont semblables à celles décrites au chapitre III.

V - Téléchargement

Deux bases (version regex et version Split) peuvent être téléchargées ici.

N.B. Le code a été adapté pour le rendre compatible avec les versions 64 bits. Voyez le tutoriel d'Arkham46 à ce sujet : Développer avec Office 64 bits.

VI - Remerciements

Merci à Arkham46, chrtophe, Loufab et User pour leur contribution à la réalisation de cet article.

Merci à jacques_jean pour la relecture orthographique.