MGD Software
Messages postés186Date d'inscriptionvendredi 1 septembre 2006StatutMembreDernière intervention23 avril 2022
-
30 oct. 2020 à 16:33
@karamel
Messages postés1838Date d'inscriptionvendredi 9 mai 2008StatutModérateurDernière intervention19 août 2023
-
31 oct. 2020 à 22:35
Bonjour,
Je développe une application Android et je cherche à désérialiser une chaine XML représentant une arborescence de classes, et à reconstituer ces classes et leur contenu.
J'ai eu beau chercher sur le net, j'ai trouvé beaucoup de choses sur la sérialisation (ce qui m'a permis de construire la chaine source), mais rien sur la dé-sérialisation qui corresponde à mon besoin. A chaque recherche je tombe sur du code C# (que je maitrise assez bien) ou sur du Java qui ne fonctionne pas dans Android Studio.
Mes classes s'appellent ModbusFrames, ModbusFrame et ModbusVar et constituent une arborescence :
- La classe ModbusFrames contient une ArrayList<ModbusFrame>
- La classe ModbusFrame contient une ArrayList<ModbusVar>
Dans la chaine XML, chaque classe ModbusFrame ou ModbusVar est représentée par un noeud portant le nom de la classe. Les attributs de chaque nœud représentent les valeurs des membres de la classe associée.
Voici un exemple de chaine à analyser, générée par un XML.Serializer :
Quelqu'un saurait-il me fournir un bout de code pour parser cette chaine ?
(Au moins lire les nœuds et leurs attributs, la gestion des classes ne devrait pas me poser de problème)
MGD Software
Messages postés186Date d'inscriptionvendredi 1 septembre 2006StatutMembreDernière intervention23 avril 20222 31 oct. 2020 à 18:32
Ne cherchez plus !
En attendant une réponse (qui n'est pas venue), j'ai continué à fouiller dans les bibliothèques d'Android Studio. En tapant "New XML...", j'ai parcouru la liste des objets proposés par Intellisense.
Et là, j'ai été interpellé par le mot XmlPullParser !
En parcourant ses propriétés et méthodes, j'ai découvert que c'était effectivement un objet capable de lire une chaine XML.
Et après quelques errements j'arrive maintenant parfaitement à décoder la chaine ci-avant. En désérialsant la chaine puis en le resérialisant, j'obtiens exactement le même code à l'arrivée qu'au départ, preuve que les deux fonctions sont bien symétriques. Et entre les deux, le debug a permis de vérifier que les classes étaient bien conformes à ce qui était attendu.
Et pour que ce post puisse servir à d'autres ayant le même problème, voici le code des fonctions de sérialisation et de désérialisation. Bien sûr, il est adapté à la structure de mes classes personnelles, mais je pense que l'adaptation à d'autres classes ne devrait pas être compliquée. A noter que ces deux procédures font partie de la classe de niveau supérieur (ModbusFrames en l'occurence), ce qui explique le remplacement de l'ArrayList à la fin de la désérialisation et non le renvoi d'une classe ModbusFrames.
public String Serialize() throws IllegalArgumentException, IllegalStateException, IOException {
StringWriter output = new StringWriter();
XmlSerializer XmlSer = Xml.newSerializer();
XmlSer.setOutput( output );
XmlSer.setFeature( "http://xmlpull.org/v1/doc/features.html#indent-output", true );
XmlSer.startDocument( "UTF-8", true );
String RootName = "ModbusFrames";
XmlSer.startTag( "", RootName );
for (ModbusFrame Frame : Frames) {
XmlSer.startTag( "", "ModbusFrame" );
int Type = Frame.getType().ordinal();
XmlSer.attribute( "", "Type", String.valueOf(Type) );
XmlSer.attribute( "", "Address", String.valueOf( Frame.getAdrs() ) );
XmlSer.attribute( "", "Label", Frame.getLabel() );
for (ModbusVar Var : Frame.getVars()) {
XmlSer.startTag( "", "ModbusVar" );
XmlSer.attribute( "", "Index", String.valueOf( Var.getIndex() ) );
XmlSer.attribute( "", "Label", Var.getLabel() );
XmlSer.attribute( "", "Format", Var.getFormat() );
XmlSer.endTag( "", "ModbusVar" );
}
XmlSer.endTag( "", "ModbusFrame" );
}
XmlSer.endTag( "", RootName );
XmlSer.endDocument();
String Result = output.toString();
return Result;
}
public void Unserialize(String xml) throws XmlPullParserException, IOException {
ArrayList<ModbusFrame> NewFrames = null;
ModbusFrame Frame = null;
ModbusVar Var = null;
StringReader input = new StringReader( xml );
XmlPullParser Parser = Xml.newPullParser();
Parser.setInput( input );
int eventType = Parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String TagName = Parser.getName();
switch (eventType) {
case XmlPullParser.START_TAG:
// Début de la liste de trames
if (TagName.equals( "ModbusFrames" ))
NewFrames = new ArrayList<ModbusFrame>();
// Nouvelle trame
else if (TagName.equals( "ModbusFrame" ) && NewFrames != null) {
Frame = new ModbusFrame();
for (int i = 0; i < Parser.getAttributeCount(); i++) {
String AttrName = Parser.getAttributeName( i );
String AttrValue = String.valueOf( Parser.getAttributeValue( i ) );
if (AttrName.equals( "Type" ))
Frame.setType( AttrValue );
else if (AttrName.equals( "Address" ))
Frame.setAdrs( AttrValue );
else if (AttrName.equals( "Label" ))
Frame.setLabel(AttrValue);
}
}
// Nouvelle variable dans la trame en cours
else if (TagName.equals( "ModbusVar" ) && NewFrames != null && Frame != null) {
Var = new ModbusVar(); // réation de la classe
// Recherche des attributs
for (int i = 0; i < Parser.getAttributeCount(); i++) {
String AttrName = Parser.getAttributeName( i );
String AttrValue = String.valueOf( Parser.getAttributeValue( i ) );
if(AttrName.equals("Index"))
Var.setIndex(AttrValue);
else if(AttrName.equals( "Label" ))
Var.setLabel(AttrValue);
else if(AttrName.equals( "Format" ))
Var.setFormat( AttrValue );
}
}
break;
// Balise de fermeture
case XmlPullParser.END_TAG:
if (TagName.equals( "ModbusVar" ) && NewFrames != null && Frame != null) {
Frame.AddVar( Var ); // Fin de la variable ModbusVar. On l'ajoute à la trame en cours
Var = null;
}
else if(TagName.equals( "ModbusFrame" ) && NewFrames != null ) {
NewFrames.add( Frame ); // Fin de la variable ModbusFrame. On l'ajoute à la liste des frames
Frame = null;
}
else if(TagName.equals( "ModbusFrames" ))
Frames = NewFrames; // Fin des frames : on remplace la liste de la classe en cours
break;
}
eventType = Parser.next();
}
}