Plan du tutoriel :
Intro
objectifs
Développement
test import/export
Conclusion
Introduction
En informatique, le format XML n’est qu’une représentation des données ! Comment fait-on pour séparer les données de leur représentation et éventuellement passer de l’un à l’autre. En java, de nombreux APIs permettent la transformation des objets java en XML. Ces APIs sont plus ou moins performantes ; en tout cas, ils sont verbeux et très compliquées à utiliser. C’est probablement cette raison qui a conduit à la création du framework JAXB. Java Architecture for XML Binding (JAXB) est un package standard de Java 1.6+ qui définit la manière dont les objets sont transformés en XML et vice-versa. En Java, ces opérations sont appelées en sérialisation/de-sérialisations ou marshaling/unmarshaling.
Que souhaitons –nous développer?
Nous souhaitons exporter les données de Prestashop en utilisant les services web ; dans un deuxième temps, nous souhaitons choisir le format d’export. Ce n’est pas le format qui nous intéresse en tant que tel, donc nous choisissons un moyen qui nous permette de faire abstraction du XML et de manipuler des objets directement. Puis, dans un deuxième temps, nous souhaitons choisir le format d’export que ce soit du CSV, du JSON, du texte simple, un document Word, un document Excel natif ou encore un flux RSS. Tout ceci sera possible avec un minimum de lignes de code.
Avantages de JAXB
Les librairies SAX ou DOM sont couramment utilisées pour manipuler des données au format XML. JAXB permet de simplifier l’utilisation de documents XML et fournissant un niveau d’abstraction plus élevé. Sa puissance est telle qu’on arrive à manipuler du XML sans connaître les techniques de traitement et sans lire le document nœud après nœud. La librairie JAXB permet la génération de code et des classes POJOs.
Dans cet article nous allons manipuler les clients (Customers) de Prestashop. Le schéma nous est imposé. Donc nous ne montrerons pas comment générer les classes java à partir d’un fichier schéma XSD ou d’un modele XML.
Technologies utilisées dans cet article :
- Java JDK 1.6+
- JAXB 2.0
Si vous avez une version de java inférieure à 1.5, le code de ce tutoriel ne marchera pas.
Description du tutoriel
Dans ce premier tutoriel, nous allons voir comment sérialiser/dé-sérialiser des objets ‘Customers’ de sorte à générer une réponse à un appel aux services web de Prestashop (1.4+). Pour cela, nous allons créer la classe java appropriée avec les annotations JAXB pour faire la correspondance entre les variables java et les propriétés d’une représentation en XML.
JAXB Annotation.
JAXB utilise des annotations pour faire la liaison entre les propriétés des objets et les nœuds du fichier XML.
XmlElement (name =’Customer’) : définit l’élément XML qui va être utilisé. Il n’est pas indispensable. Par contre il faut impérativement le préciser si le nom de la classe est différent du nom du nœud XML auquel il correspond.
XmlType (propOrder ={….}) : C’est une annotation magique qui permet de définir et de contrôler l’ordre d’écriture et d’apparition des nœuds dans le document XML sérialisé.
La classe Customer est la suivante :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 |
package com.onasus.xml.jaxb.models; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlType; @XmlRootElement @XmlType(name ="customer", propOrder = { "id", "id_default_group", "newsletter_date_add", "ip_registration_newsletter", "last_passwd_gen", "secure_key", "deleted", "passwd", "lastname", "firstname", "email", "note", "id_gender", "birthday", "newsletter", "optin", "active", "is_guest", "date_add", "date_upd" }) public class Customer { public String toString(){ String result = ""; result = "Customer: " + id + " " + firstname + " " + lastname + " " + email + " "; return result; } private String id; private IdDefaultGroup id_default_group; private String newsletter_date_add; private String ip_registration_newsletter; private String last_passwd_gen; private String secure_key; private int deleted; private String passwd; private String lastname; private String firstname; private String email; private String note; private int id_gender; private String birthday; private int newsletter; private int optin; private int active; private int is_guest; private String date_add; private String date_upd; public String getId() { return id; } public void setId(String id) { this.id = id; } public IdDefaultGroup getId_default_group() { return id_default_group; } public void setId_default_group(IdDefaultGroup id_default_group) { this.id_default_group = id_default_group; } public String getNewsletter_date_add() { return newsletter_date_add; } public void setNewsletter_date_add(String newsletterDateAdd) { newsletter_date_add = newsletterDateAdd; } public String getIp_registration_newsletter() { return ip_registration_newsletter; } public void setIp_registration_newsletter(String ipRegistrationNewsletter) { ip_registration_newsletter = ipRegistrationNewsletter; } public String getLast_passwd_gen() { return last_passwd_gen; } public void setLast_passwd_gen(String lastPasswdGen) { last_passwd_gen = lastPasswdGen; } public String getSecure_key() { return secure_key; } public void setSecure_key(String secureKey) { secure_key = secureKey; } public int getDeleted() { return deleted; } public void setDeleted(int deleted) { this.deleted = deleted; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getNote() { return note; } public void setNote(String note) { this.note = note; } public int getId_gender() { return id_gender; } public void setId_gender(int idGender) { id_gender = idGender; } public String getBirthday() { return birthday; } public void setBirthday(String birthday) { this.birthday = birthday; } public int getNewsletter() { return newsletter; } public void setNewsletter(int newsletter) { this.newsletter = newsletter; } public int getOptin() { return optin; } public void setOptin(int optin) { this.optin = optin; } public int getActive() { return active; } public void setActive(int active) { this.active = active; } public int getIs_guest() { return is_guest; } public void setIs_guest(int isGuest) { is_guest = isGuest; } public String getDate_add() { return date_add; } public void setDate_add(String dateAdd) { date_add = dateAdd; } public String getDate_upd() { return date_upd; } public void setDate_upd(String dateUpd) { date_upd = dateUpd; } } |
Sérialisation/ de- sérialisation
Exporter les clients en XML (génération d’un nouveau document à partir d’objets java)
Créons maintenant la classe de test.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
package com.onasus; import java.io.File; import java.io.FileNotFoundException; import java.io.FileReader; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBElement; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import com.onasus.xml.jaxb.models.Customer; import com.onasus.xml.jaxb.models.ObjectFactory; public class TestCustomerJAXB { public boolean unmarshallCustomer() throws JAXBException, FileNotFoundException{ try{ JAXBContext context = JAXBContext.newInstance(Customer.class); Unmarshaller unmarshaller = context.createUnmarshaller(); File customerFile = new File("customer.xml"); Source mySource = new StreamSource(customerFile); JAXBElement<Customer> unmarshal = (JAXBElement<Customer>) unmarshaller.unmarshal(mySource, Customer.class); JAXBElement<Customer> customerElement = unmarshal; Customer myCustomer = customerElement.getValue(); System.out.println("-- Unmarshalling --"); System.out.println("First name: " + myCustomer.getFirstname()); System.out.println("Last name: " + myCustomer.getLastname()); System.out.println("id_customer: " + myCustomer.getId()); System.out.println("Email: " + myCustomer.getEmail()); return true; } finally{ } } public void marshalCustomer() throws JAXBException{ JAXBContext context = JAXBContext.newInstance(Customer.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Customer currentCustomer = new Customer(); currentCustomer.setId("7"); currentCustomer.setActive(1); currentCustomer.setFirstname("Jane"); currentCustomer.setLastname("Doe"); currentCustomer.setEmail("jane.doe@gmail.com"); currentCustomer.setPasswd("complex!Password12"); marshaller.marshal(currentCustomer, System.out); } /** * @param args */ public static void main(String[] args) { try { new TestCustomerJAXB().marshalCustomer(); new TestCustomerJAXB().unmarshallCustomer(); } catch (JAXBException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } |
Quel résultat obtenons-nous ?
La premiere instruction (methode marshalCustomer) prend un objet java Customer et nous retourne la representaion XML suivante :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <customer> <id>7</id> <deleted>0</deleted> <passwd>complex!Password12</passwd> <lastname>Doe</lastname> <firstname>Jane</firstname> <email>jane.doe@gmail.com</email> <id_gender>0</id_gender> <newsletter>0</newsletter> <optin>0</optin> <active>1</active> <is_guest>0</is_guest> </customer> |
Ce résultat peut être stocké directement dans un fichier. C’est d’ailleurs ce que nous faisons pour la suite de l’exercice.
La seconde méthode prend un fichier XML en paramètre et nous permet d’afficher l’objet Customer.
Conclusion
De nombreuses variantes montrent comment traiter une liste d’objet stocké dans un fichier XML avec JAXB. Dans notre cas, allons pas à pas, ce fera l’objet d’un autre article si le besoin se fait ressentir.
Nous avons réussi à manipuler des données au format XML sans jamais manipuler du XML. Nous avons utilisé cette astuce à plusieurs reprises pour importer/exporter des clients avec Prestashop.
Au passage, Easy Retail Manager propose un module Prestashop gratuit pour gérer les clients et les groupes.
A suivre
Nous allons utiliser ce code plusieurs dans le prochain, d’abord pour exporter les clients de Prestashop, puis ensuite pour importer les clients en XML.
The company main business is further process the petrochemical production, with 8 production lines of ten-thousand-ton capacity for C9 and C10 separators, thermal
Bonjour,
Merci pour votre article, JAXB semble etre une très bonne option par rapport aux hashmap / DOM, malheureusement il m’est impossible de generer les classes avec l’outil JAXB de netbeans:
Un générateur online (http://www.xmlforasp.net/CodeBank/System_Xml_Schema/BuildSchema/BuildXMLSchema.aspx) a été utilisé pour obtenir un .xsd a partir du XML provenant de ../api/products?schema=synopsis, le .xsd est reconnu par netnbeans mais la generation des classes ne fonctionne pas, beaucoup d’erreurs du type
[ERROR] s4s-att-invalid-value : Valeur d’attribut non valide pour ‘name’ dans l’élément ‘attribute’. Raison enregistrée : cvc-datatype-valid.1.2.1 : ‘xlink:href’ n’est pas une valeur valide pour ‘NCName’.
ligne 353 sur file:/Users/imac/NetBeansProjects/Prestashop_Java/xml-resources/jaxb/test2/products.xsd
J’ai du rater quelquechose, mais a priori les classes peuvent etre generées automatiquement comme celle visible dans votre article, sauriez vous me pointer vers une methode fonctionnelle afin que je puisse generer les classes depuis les schemas XML et tester votre methode avec JAXB?
En vous remerciant par avance.
Hoel
Bonjour,
Merci beaucoup de l’intérêt que vous portez a notre article. Il est possible de generer le XSD en utilisant directement sur votre PC en utilisant la commande C# XSD.exe . On trouve cette commande avec Visual Studio. Il semble que Windows est fourni avec cette commande.
Au moment d’écrire cet article il y a quelques années déjà, j’ai essayé cette commande et le résultat n’est pas très concluant.
Donc mon conseil est simple, ne vous embarquez pas dans cette voie. Pour la ressource client, il faut aller à la mano. Dans un premier temps pour écrire les attributs. Puis, vous pouvez utiliser le générateur de getter et setter pour gagner du temps.
Vu l’engouement pour mon article, je prévois de mettre le code sur Github en Janvier après l’avoir nettoyé et mis à jour pour Prestashop 1.5 et Prestasho 1.6 .
Cordialement,