Le composant XML_Utilities

David ADAMS

- Titre : Le composant XML_Utilities

- Auteur : David ADAMS

- Parution : 1 juillet 2004

- Licence : 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.

Sommaire

- I. Résumé ♪

- II. Description de la méthode

- III. Les paramètres attendus

- IV. Échantillon XML

- V. À propos des arbres XML et de l’ordre des éléments

- Une note sur la récursivité

- VI. Bases exemples

I - Résumé ♪

Les commandes XML de 4e Dimension 2003 permettent d’analyser et valider du XML, de naviguer dans les arbres XML et d’extraire les valeurs des éléments XML et de leurs attributs. Cette note technique décrit un composant qui ajoute quelques utilitaires pratiques aux commandes natives de 4D 2003.

II - Description de la méthode

- xutil_CountOccurrences compte combien de fois est présent un élément ;

- xutil_ElementExists retourne Vrai si un élément existe ;

- xutil_GetValue retourne la valeur d’un élément simple en texte ;

- xutil_StripWhitespace Retire les caractères blancs, comme défini par XML, d’un bloc de texte.

Outre la fourniture de fonctionnalités utiles, le code du composant XML Utilities procure des exemples sur la manière de travailler avec les commandes XML de 4e Dimension 2003. Les méthodes sont incluses à la fois dans une base de données en code source ouvert pour une lecture directe et sous forme de composant installable avec 4D Insider. Cette note technique explique d’abord l’approche utilisée par le code et fournit ensuite des exemples et une documentation de chaque fonction.

III - Les paramètres attendus

La plupart des fonctions du composant XML_Utilities attendent des références et des noms d’éléments en paramètres. Voici quelques règles et rappels sur ces types d’arguments :

- les références d’éléments XML sont des chaînes de 16 caractères retournées par le parseur XML de 4e Dimension et les commandes de navigation. Appelez Analyser source XML ou Analyser variable XML pour analyser l’XML et passez la référence retournée par 4e Dimension aux fonctions d’XML_Utilities ;

- afin de libérer la mémoire, chaque appel Analyser source XML ou Analyser variable XML devrait se terminer par un appel à la commande FERMER XML une fois que l’arbre XML construit n’est plus nécessaire. Les fonctions du composant XML_Utilities n’appellent pas FERMER XML ;

- à la différence des noms 4e Dimension, les noms XML sont sensibles à la casse. En conséquence, les noms suivants sont différents : Nom_famille et Nom_Famille. Le composant XML_Utilities effectue des comparaisons sur les noms en tenant compte de la casse ;

- les fonctions du composant XML_Utilities ne supportent pas les jokers dans les noms XML. En conséquence, les deux noms suivants ne sont pas identiques : nom_famille et nom_fam@.

IV - Échantillon XML

L’échantillon XML listé ci-dessous est utilisé dans les exemples présentés dans cette note technique :

<?xml version="1.0" encoding="ISO-8859-1"?>
<Root>W
<Descendant_1>A
<Descendant_2>L</Descendant_2>
<Descendant_2>K</Descendant_2>
<Descendant_2>I
<Descendant_3>N</Descendant_3>
</Descendant_2>
</Descendant_1>
<Descendant_1>G</Descendant_1>
</Root>

La table ci-dessous résume les résultats de l’application des fonctions du composant XML_Utilities à la structure XML précédente :

Element

Nombre d’occurrences

Numéro de l’occurrence

Existe

Valeur nettoyée de la première occurrence

Root

1

1

Vrai

W

Descendant_1

2

1

Vrai

A

Descendant_1

2

2

Vrai

G

Descendant_2

3

1

Vrai

L

Descendant_2

3

2

Vrai

K

Descendant_2

3

3

Vrai

I

Descendant_3

1

1

Vrai

N

Descendant_4

0

1

Faux

Chaîne vide

V - À propos des arbres XML et de l’ordre des éléments

Les commandes XML de 4D 2003 analysent le XML sous forme d’arbres. Il existe plusieurs chemins et directions pour se déplacer dans les arbres XML : haut-vers-le-bas, bas-vers-le-haut, et par niveau, ou bien de gauche à droite ou de droite à gauche.

Les méthodes du composant XML_Utilities, comme presque tous les exemples de 4e Dimension, parcourent l’arbre XML du haut vers le bas, en utilisant la direction de gauche à droite. Ce style de parcours d’arbre est habituellement appelé « preorder traversal » dans les livres d’algorithme. Cette stratégie est plus facile à visualiser en utilisant une illustration simplifiée de l’arbre XML produit par l’analyse de l’échantillon XML présenté plus haut :

Le code du composant XML_Utilities visite les nœuds suivant la séquence décrite dans la table ci-dessous :

Nom du nœud

Valeur nettoyée

Numéro d’occurrence

Root

W

1

Descendant_1

A

1

Descendant_2

L

1

Descendant_2

K

2

Descendant_2

I

3

Descendant_3

N

1

Descendant_1

G

2

xutil_CountOccurrences

xutil_CountOccurrences (elementRef;nomCible{;premierAppel}) -> Entier long

Paramètre

Type

Description

elementRef

Alpha (16)

-> référence d’un élément XML à utiliser comme point de départ

nomCible

Texte

-> Nom de l’élément à retrouver

premierAppel

Booléen

-> Est-ce le premier appel à la méthode ?

nombre

Entier Long

<- Nombre d’éléments correspondants

La fonction xutil_CountOccurrences compte combien de fois un élément du nom spécifié apparaît dans un arbre XML. Le résultat de l’exemple d’appel ci-dessous appliqué à la structure XML listée plus haut est 3 :

1. C_ALPHA(16;$xmlref)

3. $xmlref:=Analyser variable XML($sample_xml)

4. C_ENTIER LONG($count)

5. $count:=xutil_CountOccurrences ($xmlref;"Descendant_2")

7. FERMER XML($xmlref)

L’argument premierAppel est utilisé automatiquement en interne pour gérer le code récursif. Normalement, il n’y a aucune raison de passer ce paramètre lors d’un appel à xutil_CountOccurrences.

1. C_ENTIER LONG($0;$count)

3. C_ALPHA(16;$1;$xmlref)

4. C_TEXTE($2;$targetName_t)

5. C_BOOLEEN($3;$isFirstCallInChain_b)

6. $xmlref:=$1

7. $targetName_t:=$2

8. $isFirstCallInChain_b:=Vrai

9. Si (Nombre de parametres>2)

10. $isFirstCallInChain_b:=$3

11. Fin de si

12. $count:=0

13. Si ($isFirstCallInChain_b)

14. C_ENTIER LONG(OK)

15. OK:=1 ` fixe la valeur de la variable de contrôle avant d’entrer

16. `dans la boucle pour la première fois

17. Sinon

18. $xmlref:=Lire premier element XML ($xmlref)

19. Fin de si

20. Repeter

21. Tant que (OK=1)

22. C_TEXTE($currentName_t)

23. $currentName_t:=""

24. LIRE NOM ELEMENT XML ($xmlref;$currentName_t)

25. Si (xutilStringsAreEqual ($currentName_t;$targetName_t))

26. $count:=$count+1

27. $xmlref:=Lire element XML suivant ($xmlref)

28. Sinon

29. $count:=$count+xutil_CountOccurrences ($xmlref;$targetName_t;Faux)

30. $xmlref:=Lire element XML suivant ($xmlref)

31. Fin de si

32. Fin tant que

33. Jusque (OK=0)

35. $0:=$count

Une note sur la récursivité

La fonction xutil_CountOccurrences s’appelle elle-même de manière récursive pour inspecter chaque branche de l’arbre XML parcouru. Si la récursivité est l’approche la plus répandue dans ce type de navigation, elle n’est pas la seule possibilité. En interne, la récursivité fonctionne en créant une pile des appels de méthode, chacune avec ses arguments distincts (valeurs de paramètres). Le même jeu de nœuds peut être visité à l’aide de boucles et d’une pile maintenue à la main, typiquement en recourant à un tableau 4e Dimension.

xutil_ElementExists

Description

xutil_ElementExists (elementRef ;nomCible) -> Booleen

Paramètre

Type

Description

elementRef

Alpha (16)

-> référence de l’élément XML à utiliser comme point de départ

nomCible

Texte

-> nom de l’élément à rechercher

siExiste

Booleen

Vrai si l’élément existe, Faux sinon

La fonction xutil_ElementExists teste si un élément du nom spécifié apparaît dans un arbre XML. Le résultat du code exemple ci-dessous est Faux si on l’applique à l’extrait XML cité plus haut :

1. C_ALPHA(16;$xmlref)

3. $xmlref:=Analyser variable XML($sample_xml)

4. C_ENTIER LONG($count)

5. $count:=xutil_ElementExists ($xmlref;"first_name")

7. FERMER XML($xmlref)

Code source :

1. C_BOOLEEN($0;$elementExists_b)

3. C_ALPHA(16;$1;$xmlref)

4. C_TEXTE($2;$targetName_t)

5. $xmlref:=$1

6. $targetName_t:=$2

7. $elementExists_b:=Faux

8. C_ENTIER LONG$count)

9. $count:=xutil_CountOccurrences ($xmlref;$targetName_t)

10. Si ($count>0)

11. $elementExists_b:=Vrai

12. Sinon

13. $elementExists_b:=Faux

14. Fin de si

16. $0:=$elementExists_b

xutil_GetValue

Description

xutil_GetValue (elementRef;nomCible{;index{;nettoyer{;premierAppel}}}) -> Texte

Paramètre

Type

Description

ElementRef

Alpha (16)

-> référence de l’élément XML à utiliser comme point de départ

nomCible

Texte

-> Nom de l’élément à rechercher

index

Entier Long

-> ordre de l’occurrence de laquelle lire la valeur

nettoyer

Booleen

-> nettoyer les espaces blancs de la valeur de l’élément ?

premierAppel

Booleen

-> s’agit-il du premier appel à la méthode ?

valeur

Texte

<- valeur de l’élément correspondant ou chaîne vide

La fonction xutil_GetValue retourne la valeur de l’élément dont le nom est spécifié ou une chaîne vide si l’élément n’est pas présent.

Le paramètre optionnel index permet de demander à lire une occurrence précise d’un élément. Une valeur par défaut de 1 est utilisée lorsque l’argument optionnel n’est pas passé. Le résultat de l’exemple de code ci-dessous est la valeur « K » pour l’extrait XML cité plus haut :

1. C_ALPHA(16;$xmlref)

3. $xmlref:=Analyser variable XML ($sample_xml)

4. C_ENTIER LONG($count)

5. $count:=xutil_GetValue ($xmlref;"Descendant_2";2)

7. FERMER XML($xmlref)

Le paramètre optionnel nettoyer contrôle l’élimination des espaces blancs encadrant la valeur de l’élément. Une valeur par défaut à Faux est utilisée si ce paramètre optionnel n’est pas précisé. Lorsque nettoyer est fixé à Vrai, les espaces blancs encadrant la valeur sont supprimés avant le retour de résultat ; lorsque nettoyer est fixé à Faux, les espaces blancs sont préservés. Reportez-vous xutil_StripWhitespace dans les pages suivantes pour plus d’information. L’argument premierAppel est utilisé automatiquement en interne pour gérer le code récursif. Normalement, il n’y a aucune raison de passer ce paramètre lors d’un appel à xutil_GetValue.

Code source :

1. C_TEXTE($0;$resultValue_t)

3. C_ALPHA(16;$1;$xmlref)

4. C_TEXTE($2;$targetName_t)

5. C_ENTIER LONG($elementToFind_index)

6. C_BOOLEEN($4;$cleanValue_b)

7. C_BOOLEEN($5;$isFirstCallInChain_b)

9. $xmlref:=$1

10. $targetName_t:=$2

12. C_ENTIER LONG($parameters_count)

13. $parameters_count:=Nombre de parametres

15. Au cas ou ` Remplit les paramètres optionnels avec les valeurs passées ou celles par défaut

16. : ($parameters_count<3)

17. $elementToFind_index:=1

18. $cleanValue_b:=Faux

19. $isFirstCallInChain_b:=Vrai

20. : ($parameters_count<4)

21. $elementToFind_index:=$3

22. $cleanValue_b:=Faux

23. $isFirstCallInChain_b:=Vrai

24. : ($parameters_count<5)

25. $elementToFind_index:=$3

26. $cleanValue_b:=$4

27. $isFirstCallInChain_b:=Vrai

28. : ($parameters_count<6)

29. $elementToFind_index:=$3

30. $cleanValue_b:=$4

31. $isFirstCallInChain_b:=$5

32. Fin de cas

34. $resultValue_t:=""

36. Si ($isFirstCallInChain_b)

37. C_BOOLEEN(xutil_GetValue_stop)

38. xutil_GetValue_stop:=Faux

39. C_ENTIER LONG(xutil_GetValueMatches_count)

40. xutil_GetValueMatches_count:=0

41. C_ENTIER LONG(OK)

42. OK:=1 ` fixe la valeur de la variable de contrôle avant d’entrer dans la boucle pour la première fois

43. Sinon

44. $xmlref:=Lire premier element XML ($xmlref)

45. Fin de si

47. Repeter

48. Tant que ((OK=1) & (xutil_GetValue_stop=Faux))

50. C_TEXTE($currentValue_t)

51. $currentName_t:=""

52. $currentValue_t:=""

54. LIRE NOM ELEMENT XML ($xmlref;$currentName_t)

55. LIRE VALEUR ELEMENT XML ($xmlref;$currentValue_t)

57. Si (xutilStringsAreEqual ($currentName_t;$targetName_t))

58. xutil_GetValueMatches_count:=xutil_GetValueMatches_count+1

60. Si (xutil_GetValueMatches_count=$elementToFind_index)

61. $resultValue_t:=$currentValue_t

62. xutil_GetValue_stop:=Vrai

63. OK:=0

64. Fin de si

66. $xmlref:=Lire element XML suivant ($xmlref)

68. Sinon

69. $resultValue_t:=xutil_GetValue

70. ($xmlref;$targetName_t;$elementToFind_index;$cleanValue_b;False)

71. $xmlref:=Lire element XML suivant ($xmlref)

72. Fin de si

74. Fin tant que

75. Jusque ((OK=0) | xutil_GetValue_stop)

77. Si ($cleanValue_b)

78. $resultValue_t:=xutil_StripWhitespace ($resultValue_t)

79. Fin de si

80. $0:=$resultValue_t

xutil_StripWhitespace

xutil_StripWhitespace (source) -> Texte

Paramètre

Type

Description

source

Texte

-> texte dont les espaces blancs doivent être retirés

Résultat

Texte

<- le texte initial dont les espaces blancs ont été retirés

XML définit quatre caractères comme espaces blancs, listés dans le tableau ci-dessous :

Nom

Code ascii

Hexa

Tab

9

09

Line feed (retour à la ligne)

10

0A

Carriage return (retour chariot)

13

0D

Espace

32

20

Les espaces blancs améliorent grandement la lisibilité des documents XML, mais sont souvent indésirables lors du travail avec les valeurs des éléments XML. Par exemple, la valeur de la première instance du Descendant_1 dans l’extrait XML cité plus haut est longue de 16 caractères. La voici avec les noms des espaces blancs mentionnés explicitement :

<b>A<retour_chariot></b>
<b><retour_chariot ></b>
<b><tab> <tab> <retour_chariot ></b>
<b><retour_chariot ></b>
<b><tab> <tab> <retour_chariot ></b>
<b><retour_chariot ></b>
<b><tab> <tab> <retour_chariot ></b>
<b><retour_chariot ></b>
<b><tab></b>

La valeur nettoyée de cet élément est le seul caractère « A ».

1. C_TEXTE($0;$result_t)

3. C_TEXTE($1;$source_t)

4. $source_t:=$1

5. $result_t:=""

7. ` -------------------------------------------------------------------------------------------------

8. ` Prépare un tableau de tous les caractères définis comme espaces blancs

9. ` -------------------------------------------------------------------------------------------------

10. TABLEAU ENTIER LONG($whitespace_al;4)

11. $whitespace_al{1}:=Tabulation

12. $whitespace_al{2}:=Retour à la ligne

13. $whitespace_al{3}:=Retour chariot

14. $whitespace_al{4}:=Espacement

16. C_ENTIER LONG($firstCharacter_index)

17. C_ENTIER LONG($lastCharacter_index)

18. $firstCharacter_index:=0

19. $lastCharacter_index:=0

21. ` ---------------------------------------------------------

22. ` Trouver le premier caractère non espace blanc

23. ` ---------------------------------------------------------

24. C_ENTIER LONG($length)

25. C_ ENTIER LONG($index)

26. C_ ENTIER LONG($element)

27. C_ ENTIER LONG($ascii)

28. $length:=Longueur($source_t)

29. $index:=0

30. $element:=0

31. $ascii:=0

32. C_BOOLEEN($done)

33. $done:=Faux

35. Repeter

36. $index:=$index+1

38. Si ($index>$length)

39. $done:=Vrai

40. Sinon

41. $ascii:=Code ascii($source_t=$index=)

42. $element:=Chercher dans tableau($whitespace_al;$ascii)

44. Si ($element<0)

45. ` Le caractère testé n’est pas un espace blanc : c’est ce que nous cherchions

46. $firstCharacter_index:=$index

47. $done:=Vrai

48. Fin de si

50. Fin de si

52. Jusque ($done)

54. ` ---------------------------------------------------------

55. ` Trouver le dernier caractère non espace blanc

56. ` ---------------------------------------------------------

57. C_ENTIER LONG($index)

58. C_ENTIER LONG($element)

59. $index:=Longueur($source_t)+1

60. $element:=0

61. C_BOOLEEN($done)

62. $done:=Faux

64. Repeter ` marche arrière à travers la chaîne à la recherche du dernier caractère non espace blanc

65. $index:=$index-1

67. Si ($index=0)

68. $done:=Vrai

69. Sinon

70. $ascii:=Ascii($source_t=$index=)

71. $element:=Chercher dans tableau($whitespace_al;$ascii)

73. Si ($element<0)

74. ` Le caractère testé n’est pas un espace blanc : c’est ce que nous cherchions

75. $lastCharacter_index:=$index

76. $done:=True

77. Fin de si

79. Fin de si

81. Jusque ($done)

83. ` ---------------------------------------------------------

84. ` Nettoye la chaîne source.

85. ` ---------------------------------------------------------

86. C_ENTIER LONG($result_length)

87. $result_length:=$lastCharacter_index-$firstCharacter_index+1

89. Au cas ou

90. : ($lastCharacter_index=0)

91. $result_t:=""

92. : ($firstCharacter_index=0)

93. $result_t:=""

94. : ($result_length<1)

95. $result_t:=""

96. Sinon

97. $result_t:=Sous chaine($source_t;$firstCharacter_index;$result_length)

98. Fin de cas

100. $0:=$result_t

xutilStringsAreEqual

Le composant inclut également une méthode privée qui compare l’égalité de deux chaînes. Ce code est nécessaire car le système de comparaison de chaîne natif à 4e Dimension, dépendant des réglages de langue, ignore les différences de casse et les caractères diacritiques. Les chaînes XML sont toujours sensibles à la casse. Le tableau ci-dessous compare la manière dont 4e Dimension et XML considèrent l’équivalence de quelques échantillons de chaînes :

Chaîne exemple

Chaîne de comparaison

Égalité dans 4D

Égalité en XML

a-b-c-d-e

a-b-c-d-e

Oui

Oui

a-b-c-d-e

a-b-c-d-E

Oui

Non

a-b-c-d-e

a-b-c-d-é

Oui

Non

a-b-c-d-e

A-B-C-D-E

Oui

Non

La méthode xutilStringsAreEqual compare des chaînes caractère par caractère en se fondant sur le code ascii pour retourner un résultat compatible avec les règles des noms XML.

1. C_BOOLEEN($0;$StringsAreEqual_b)

3. C_TEXTE($1;$baseString_t)

4. C_TEXTE($2;$comparisonString_t)

6. $baseString_t:=$1

7. $comparisonString_t:=$2

8. $StringsAreEqual_b:=Faux

10. Au cas ou

11. : ($baseString_t#$comparisonString_t) ` Echec dans la comparaison native par 4D

12. $StringsAreEqual_b:=Faux

14. : ($baseString_t="") ` Les deux chaînes sont vides

15. $StringsAreEqual_b:=Vrai

17. Sinon

18. ` Effectue une comparaison octet par octet

19. C_ENTIER LONG($length)

20. C_ENTIER LONG($index)

21. C_BOOLEEN($continue)

23. $length:=Longueur($baseString_t)

24. $index:=1 ` les chaines ne sont pas valides

26. C_ENTIER LONG($base_ascii)

27. C_ENTIER LONG($comparison_ascii)

29. $continue:=Vrai

30. $StringsAreEqual_b:=Vrai

32. Tant que ($continue)

33. $base_ascii:=Code ascii($baseString_t=$index=)

34. $comparison_ascii:=Code ascii($comparisonString_t=$index=)

36. Au cas ou

37. : ($base_ascii=$comparison_ascii)

38. $index:=$index+1

40. : ($base_ascii#$comparison_ascii)

41. $StringsAreEqual_b:=Faux

42. $continue:=Faux

43. Fin de cas

45. Si ($index>$length)

46. $continue:=Faux

47. Fin de si

49. Fin tant que

51. Fin de cas

53. $0:=$StringsAreEqual_b

VI - Bases exemples

Téléchargez les bases exemples :

base exemple Mac

base exemple Win