Les webservices REST ou SOAP avec lesquels les applications doivent très souvent communiquer attentent couramment des données formatées en JSON.
Une application a généralement des données structurées en mémoire dans des variables :
Le principe de sérialisation permet de simplement transférer des données structurées en mémoire, en chaîne au format JSON ou XML. Exemple avec une structure :
stExemple est une structure sIdentifiant est une chaîne sInfo est une chaîne FIN UnExemple est un stExemple = ["Id123", "Mon info"] unExempleJSON est un Buffer Sérialise(UnExemple, unExempleJSON,psdJSON) Trace(unExempleJSON)
Une difficulté apparaît lorsque la structure en mémoire contient des données pour lesquelles on doit distinguer si une variable chaîne a été :
- affectée avec du texte,
- affectée avec aucun contenu,
- ou au contraire on souhaite savoir qu'il n'y a pas encore eu d'affectation du tout.
Dans ce cas précis, le JSON va exiger pour la variable d'avoir l'information (texte ou vide), ou alors Null pour distinguer le fait qu'il n'y a pas encore eu d'affectation. En WLangage, le type chaîne n'est pas "nullable". On ne peut donc pas affecter une variable avec Null, et obtenir après une sérialisation en JSON un Null.
En continuant avec le meme exemple :
UnExemple.sIdentifiant = "Id123" UnExemple.sInfo = Null Sérialise(UnExemple,unExempleJSON,psdJSON) Trace("On a un zéro et pas Null car null inapplicable au type chaine ...") Trace("JSON n'a pas Null >> " + unExempleJSON) Trace("Comparaison Null impossible >> "+ (UnExemple.sInfo = Null))
Dans ce cas deux solutions sont couramment utilisées afin d'obtenir le JSON attendu.
Point de départ commun : on ajoute au projet une constante chaîne qui aura une valeur qui représentera l'état non renseigné, et qui sera donc affectée aux variables :
CONSTANT NON_RENSEIGNÉ_NULL = "##Null##"
UnExemple.sInfo = NON_RENSEIGNÉ_NULL
Solution 1 : on conserve une sérialisation vers un buffer JSON. On remplace ensuite basiquement la valeur qui représente le "non renseigné" par le Null attendu dans le JSON.
Sérialise(UnExemple,unExempleJSON,psdJSON) unExempleJSON = Remplace(unExempleJSON,""""+NON_RENSEIGNÉ_NULL+"""", "Null") Trace(RC+"SOLUTION 1" + unExempleJSON)
Solution 2 : via la fonction RécupèreDéfinition on construit une variable JSON à l'identique de la structure mémoire. Le Null est accepté dans ce cas, et permettra d'avoir immédiatement le JSON attendu :
MaDéfinition est une Definition = RécupèreDéfinition(UnExemple) MonFluxJson est un JSON POUR TOUT NomMembre de MaDéfinition..Variable SI {"UnExemple."+NomMembre..Nom, indVariable} = NON_RENSEIGNÉ_NULL {"MonFluxJson."+NomMembre..Nom, indVariable} = Null SINON {"MonFluxJson."+NomMembre..Nom, indVariable} = {"UnExemple."+NomMembre..Nom, indVariable} FIN FIN Trace("SOLUTION 2" + JSONVersChaîne(MonFluxJson))
Cette solution sera à privilégier si des traitements spécifiques sont à faire en fonction de chaque membre, ou du type des membres. Le type WLangage définition permet en effet de connaître toutes les caractéristiques d'une variable lors de l'exécution. Dans le cas d'une classe, le traitement peut être dans une méthode dédiée à l'export en JSON.
Ndlr : un titre alternatif pour ce billet aurait pu être : "récupérer la définition d'une variable structurée pour effectuer un traitement générique sur ses membres". Car il est également courant d'avoir à faire un traitement sur toute une structure ou classe en mémoire (contrôle de valeurs affectées, mise à jour de contenu...).
|