IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java EE Discussion :

[camel] Convertir CSV->XML avec bindy jaxb


Sujet :

Java EE

  1. #1
    Expert éminent
    Avatar de sekaijin
    Homme Profil pro
    Urbaniste
    Inscrit en
    Juillet 2004
    Messages
    4 205
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 60
    Localisation : France, Yvelines (Île de France)

    Informations professionnelles :
    Activité : Urbaniste
    Secteur : Santé

    Informations forums :
    Inscription : Juillet 2004
    Messages : 4 205
    Points : 9 127
    Points
    9 127
    Par défaut [camel] Convertir CSV->XML avec bindy jaxb
    Bonjour.

    Une route camel pour convertir du CSV en XML avec Camel bindy et jaxb.

    Créez un projet camel (j'utilise maven pour cela)
    Ajoutez camel-bindy et camel-jaxb dans les dépendances (2.8.0 pour moi)

    Le but est de transformer des données CSV comme
    Code csv : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    4;12235;CHIR;5802;10000446;30;14078;SPE;1
    4;19999;CHIR;5888;10000446;30;14078;SPE;1
    En XML
    Code xml : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <reservation xmlns="urn:org.sekaijin.csv.to.xml.metier">
        <poste>
            <ph1>4</ph1>
            <ph2>12235</ph2>
            <ph3>CHIR</ph3>
            <ph4>5802</ph4>
            <ph5>10000446</ph5>
            <ph6>30</ph6>
            <ph7>14078</ph7>
            <ph8>SPE</ph8>
            <ph9>1</ph9>
        </poste>
        <poste>
            <ph1>4</ph1>
            <ph2>19999</ph2>
            <ph3>CHIR</ph3>
            <ph4>5888</ph4>
            <ph5>10000446</ph5>
            <ph6>30</ph6>
            <ph7>14078</ph7>
            <ph8>SPE</ph8>
            <ph9>1</ph9>
        </poste>
    </reservation>
    Vous pouvez partir d'un Schéma XSD pour générer les classes avec Jaxb mais il faut les modifier.

    Je préfère donc partir directement du code Java
    package-info.java: ce fichier sert à définir le namespace du schéma. sans changement s'il a été généré
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    @XmlSchema( 
       namespace = "urn:org.sekaijin.csv.to.xml.metier", 
       elementFormDefault = XmlNsForm.QUALIFIED
       )
    package org.sekaijin.cvs.to.xml;
    import javax.xml.bind.annotation.XmlNsForm;
    import javax.xml.bind.annotation.XmlSchema;
    Il en va de même pour ObjectFactory.java
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    package org.sekaijin.cvs.to.xml;
     
    import javax.xml.bind.annotation.XmlRegistry;
     
    @XmlRegistry
    public class ObjectFactory {
       public ObjectFactory() {
       }
     
       public Reservation createReservation() {
          return new Reservation();
       }
       public Poste createPoste() {
          return new Poste();
       }
    }
    Reservation.java contient la définition d'une réservation. Par facilité, j'ai ajouté une méthode setPoste qui ajoute un poste. La classe générée par Jaxb nécessite de setter tous les postes d'un coup.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    package org.sekaijin.cvs.to.xml;
     
    import java.util.ArrayList;
    import java.util.List;
     
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlType;
     
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {"postes"})
    @XmlRootElement(name = "reservation")
    public class Reservation {
        @XmlElement(required = false, name = "poste")
        protected List<Poste> postes;
     
        public List<Poste> getPostes() {
            if (postes == null) {
                postes = new ArrayList<Poste>();
            }
            return this.postes;
        }
     
       public Reservation(){
       }
     
       public void setPoste(Poste poste){
          this.getPostes().add(poste);
       }
    }
    Poste.js c’est ici que se passe l'opération la plus intéressante par rapport au code généré par Jaxb j'ai ajouté toutes les annotations nécessaires à Bindy pour lire le CSV
    ainsi chaque champ est annoté pour jaxb et pour Bindy
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    package org.sekaijin.cvs.to.xml;
     
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlType;
     
    import org.apache.camel.dataformat.bindy.annotation.CsvRecord;
    import org.apache.camel.dataformat.bindy.annotation.DataField;
     
     
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "Poste", propOrder = {
       "ph1",
       "ph2",
       "ph3",
       "ph4",
       "ph5",
       "ph6",
       "ph7",
       "ph8",
       "ph9"
    })
    @CsvRecord(separator = ";", crlf = "UNIX", skipFirstLine = false)
    public class Poste {
     
       @DataField(pos = 1)
       @XmlElement(required = true)
       protected String ph1;
       @DataField(pos = 2)
       @XmlElement(required = true)
       protected String ph2;
       @DataField(pos = 3)
       @XmlElement(required = true)
       protected String ph3;
       @DataField(pos = 4)
       @XmlElement(required = true)
       protected String ph4;
       @XmlElement(required = true)
       @DataField(pos = 5)
       protected String ph5;
       @DataField(pos = 6)
       @XmlElement(required = true)
       protected String ph6;
       @DataField(pos = 7)
       @XmlElement(required = true)
       protected String ph7;
       @DataField(pos = 8)
       @XmlElement(required = true)
       protected String ph8;
       @DataField(pos = 9)
       @XmlElement(required = true)
       protected String ph9;
     
       public String getPh1() {
          return ph1;
       }
     
       public void setPh1(String value) {
          this.ph1 = value;
       }
     
      // je vous laisse ajouter tous les autres getters et setters
    }
    Transform.java cette classe sert à partir de la map de Poste à construire un objet Réservation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    package org.sekaijin.cvs.to.xml;
     
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
     
    import org.apache.camel.Exchange;
    import org.apache.camel.Message;
     
    public class Transform {
     
       public void process(Exchange exchange) throws Exception {
          Message msg = exchange.getIn();
     
          @SuppressWarnings("unchecked")
          List<Map<String, Poste>> orders = (List<Map<String, Poste>>) msg.getBody();
     
          ObjectFactory objectFactory = new ObjectFactory();
     
          Reservation resa = objectFactory.createReservation();
     
     
          Iterator<Map<String, Poste>> orderIterator = orders.iterator();
          while (orderIterator.hasNext()) {
             Map<String, Poste> n = orderIterator.next();
     
             resa.setPoste(n.get(Poste.class.getName()));
          }
          exchange.getIn().setBody(resa);
       }
     
    }

    Il reste à définir la route
    from ce que vous voulez -> bindy qui donne une Map de "Poste" -> Transform qui créé un Réservation et y place la liste des Poste -> jaxb qui en fait un XML -> to ce que vous voulez
    J'ai ajouté des log pour y voir clair
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package org.sekaijin.cvs.to.xml;
     
    import org.apache.camel.builder.RouteBuilder;
    import org.apache.camel.converter.jaxb.JaxbDataFormat;
    import org.apache.camel.model.dataformat.BindyType;
     
    public class MyRouteBuilder extends RouteBuilder {
     
        public void configure() {
           JaxbDataFormat jaxbDataFormat = new JaxbDataFormat(Reservation.class.getPackage().getName());
           jaxbDataFormat.setPrettyPrint(true);
     
           from("direct:start")
               .to("log: IN ==>")
               .unmarshal().bindy(BindyType.Csv, Poste.class.getPackage().getName())
               .bean(Transform.class)
               .marshal(jaxbDataFormat)
               .to("log: OUT ==>")
               .to("mock:result")
               ;
     
        }
    }
    et c'est tout j'ai utilisé direct et mock pour faire des tests, mais file http ou tout autre protocole fonctionne de la même façon.
    Une petite classe de test pour vérifier le tout: RouteTest (ajouter camel-test au dépendances)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    package org.sekaijin.cvs.to.xml;
     
     
    import org.apache.camel.builder.RouteBuilder;
    import org.apache.camel.test.junit4.CamelTestSupport;
    import org.junit.Test;
     
     
    public class RouteTest extends CamelTestSupport {
     
     
       @Override
       public String isMockEndpoints() {
          // override this method and return the pattern for which endpoints to
          // mock.
          // use * to indicate all
          return "*";
       }
     
       @Test
       public void testRoute() throws Exception {
     
          String CamelFileName = "sample.csv";
          String inMsg = "4;12235;CHIR;5802;10000446;30;14078;SPE;1" + "\n"
             + "4;19999;CHIR;5888;10000446;30;14078;SPE;1";
     
          String ouMsg = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
                "<reservation xmlns=\"urn:org.sekaijin.csv.to.xml.metier\">\n" +
                      "    <poste>\n" +
                      "        <ph1>4</ph1>\n" +
                      "        <ph2>12235</ph2>\n" +
                      "        <ph3>CHIR</ph3>\n" +
                      "        <ph4>5802</ph4>\n" +
                      "        <ph5>10000446</ph5>\n" +
                      "        <ph6>30</ph6>\n" +
                      "        <ph7>14078</ph7>\n" +
                      "        <ph8>SPE</ph8>\n" +
                      "        <ph9>1</ph9>\n" +
                      "    </poste>\n" +
                      "    <poste>\n" +
                      "        <ph1>4</ph1>\n" +
                      "        <ph2>19999</ph2>\n" +
                      "        <ph3>CHIR</ph3>\n" +
                      "        <ph4>5888</ph4>\n" +
                      "        <ph5>10000446</ph5>\n" +
                      "        <ph6>30</ph6>\n" +
                      "        <ph7>14078</ph7>\n" +
                      "        <ph8>SPE</ph8>\n" +
                      "        <ph9>1</ph9>\n" +
                      "    </poste>\n" +
                      "</reservation>\n";
     
          getMockEndpoint("mock:direct:start").expectedBodiesReceived(inMsg);
     
          getMockEndpoint("mock:result").expectedBodiesReceived(ouMsg);
     
          template.sendBodyAndHeader("direct:start", inMsg, "CamelFileName", CamelFileName);
     
          assertMockEndpointsSatisfied();
     
       }
     
       @Override
       protected RouteBuilder createRouteBuilder() throws Exception {
          return new MyRouteBuilder();
       }
    }
    Et voilà l'affaire et dans le sac.
    En partant de Jaxb et en ajoutant les annotations, le travail est plutôt facile. Mais il ne faut par régénérer les classes.

    La "difficulté" vient du fait que Bindy fournit une liste d'objet alors que Jaxb attend un objet unique. ça se règle avec la classe Transform

    "l'astuce" consiste à utiliser la même classe (Poste) comme modèle du CSV et XML(Poste)

    A+JYT
    Fichiers attachés Fichiers attachés

Discussions similaires

  1. convertir des csv en xml
    Par bastiensoleil dans le forum XML/XSL et SOAP
    Réponses: 2
    Dernier message: 27/04/2010, 09h48
  2. [Perl] Convertir csv en xml
    Par chills dans le forum Modules
    Réponses: 0
    Dernier message: 19/03/2010, 16h02
  3. [CXF et JAXB] Parser un fichier XML avec des namespaces
    Par cowa dans le forum Services Web
    Réponses: 0
    Dernier message: 26/02/2009, 15h30
  4. [JAXB] Problème parsing XML avec XSD validant
    Par vano dans le forum Persistance des données
    Réponses: 2
    Dernier message: 26/08/2008, 10h59
  5. [XML] convertir fichier CSV en XML
    Par Yudala dans le forum XML/XSL et SOAP
    Réponses: 1
    Dernier message: 16/02/2007, 11h05

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo