2012-03-14 7 views
8

Jestem nowy dla Apache Camel i próbnego testowania, więc tutaj jest ...Jak utworzyć trasę wielbłądzową, która pobiera XML i wiąże niektóre dane do JPG z adnotacjami?

Mam XML bez schematu XSD, na który nie mam wpływu. Elementy potomne tego pliku XML przechowują dane, które chcę powiązać z moim biznesem pojo. To POJO (WeatherCurrent) jest już oznaczone adnotacją JPA i myślałem o dodaniu adnotacji JAXB, aby podzielony XML mógł zostać zmapowany do mojego POJO.

Ponieważ ten plik XML ma element główny, a ja chcę tylko jego childs (metData), mam problem z adnotacją mojego POJO, ponieważ nie mogę użyć @XmlRootElement.

To jest częściowo opisane tutaj: http://camel.apache.org/splitter.html o Przesyłanie strumieniowe dużych danych XML za pomocą języka Tokenizer rozdział. Moje POJO jest jak zamówienie element xml w tym przykładzie. Potrzebuję tylko kilku elementów z elementu xml metData do mapowania do moich pól POJO.

Jest też rozdział Częściowa marshalling/unmarshalling na http://camel.apache.org/jaxb.html ale nie jest przykładem JAVA DSL (obowiązkowa), ani jak opisanie POJO do pracy z fragmentów XML.

tej pory mam ten kod testowy:

import java.io.File; 

import org.apache.camel.EndpointInject; 
import org.apache.camel.Exchange; 
import org.apache.camel.ProducerTemplate; 
import org.apache.camel.builder.RouteBuilder; 
import org.apache.camel.component.mock.MockEndpoint; 
import org.apache.camel.converter.jaxb.JaxbDataFormat; 
import org.apache.camel.spi.DataFormat; 
import org.apache.camel.test.junit4.CamelTestSupport; 
import org.junit.Test; 

public class WeatherCurrentTest extends CamelTestSupport { 

    @EndpointInject(uri = "file:src/test/resources") 
    private ProducerTemplate inbox; 

    @Override 
    protected RouteBuilder createRouteBuilder() throws Exception { 
     return new RouteBuilder() { 
      @Override 
      public void configure() throws Exception { 
       DataFormat jaxbDataFormat = new JaxbDataFormat("com.mycompany.model.entities.weather");// WARNING two packages for JaxbDataFormat 

       from("file:src/test/resources/?fileName=observation_si_latest.xml&noop=true&idempotent=false") 
       .split() 
       .tokenizeXML("metData") 
       .unmarshal(jaxbDataFormat) 
       .to("mock:meteo");   
      } 
     }; 
    } 

    @Test 
    public void testMetData() throws Exception { 
     MockEndpoint mock = getMockEndpoint("mock:meteo"); 
     mock.expectedMessageCount(9); 

     File meteo = new File("src/test/resources/observation_si_latest.xml"); 
     String content = context.getTypeConverter().convertTo(String.class, meteo); 
     inbox.sendBodyAndHeader(content, Exchange.FILE_NAME, "src/test/resources/observation_si_latest.xml"); 

     mock.assertIsSatisfied(); 
    } 

} 

XML (observation_si_latest.xml) dostarczana jest w tej postaci:

<?xml version="1.0" encoding="UTF-8"?> 
<data id="MeteoSI_WebMet_observation_xml"> 
    <language>sl</language> 
    <metData> 
     <domain_altitude>55</domain_altitude> 
     <domain_title>NOVA GORICA</domain_title> 
     <domain_shortTitle>BILJE</domain_shortTitle> 
     <tsValid_issued>09.03.2012 15:00 CET</tsValid_issued> 
     <t_degreesC>15</t_degreesC> 
    </metData> 
    <metData> 
     <domain_meteosiId>KREDA-ICA_</domain_meteosiId> 

Pominąłem wiele elementów elementów metData dla zwięzłości . Chcę zmapować (między innymi) domain_title do mojego stanowiska JPA przypisanego do pola stacji, a następnie zapisać bazę danych, mam nadzieję, że wszystko w jednym inteligentnym i krótkim torze Camel.

POJO (brak adnotacji JAXB jeszcze):

@Entity 
@Table(name="weather_current") 
public class WeatherCurrent implements Serializable { 

    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private int id; 

    private String station; 

    @Temporal(TemporalType.TIMESTAMP) 
    @Column(name="successfully_updated") 
    private Date successfullyUpdated; 

    private short temperature; 

    @Column(name="wind_direction") 
    private String windDirection; 

} 

ja też pominąć wiele pól i metod.

Chodzi więc o odwzorowanie wartości pola * domain_title * na pole WeatherCurrent POJO o numerze i wykonanie tego dla każdego elementu metData i zapisanie listy obiektów WeatherCurrent w bazie danych.

Wszelkie rady dotyczące najlepszego sposobu realizacji tego są mile widziane.

+0

pierwsze podzielone przyjmuje parametr. Po drugie, jak o xpath lub xlst, aby usunąć dane z XML? Możesz Marszałkowi XML lub uzyskać dostęp do danych za pomocą xpath lub xlst. Co działa najlepiej? – chrislovecnm

Odpowiedz

2

Okazuje się, że miałem jedno błędne założenie, że nie mogę korzystać z @XmlRootElement. Trasa i test kończą się sukcesem po tym, jak dodałem adnotację do POJO i dodałem plik jaxb.index obok niego. Opublikuję rozwiązanie później lub jutro, ponieważ jestem teraz w pociągu.

godzin później ...

W JAXB adnotacji na POJO (na górze te WZP):

@Entity 
@Table(name="weather_current") 
@XmlRootElement(name = "metData") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class WeatherCurrent implements Serializable { 
    private static final long serialVersionUID = 1L; 

    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY) 
    private int id; 

    @XmlElement(name = "nn_shortText") 
    private String conditions; 

    @XmlElement(name = "rh") 
    private short humidity; 

    @XmlElement(name = "msl") 
    private short pressure; 

    @Column(name="pressure_tendency") 
    @XmlElement(name = "pa_shortText") 
    private String pressureTendency; 

    @Temporal(TemporalType.TIMESTAMP) 
    @XmlElement(name = "tsValid_issued") 
    private Date published; 

    @XmlElement(name = "domain_longTitle") 
    private String station; 

pozwoliło mi uzyskać listę obiektów WeatherCurrent exchage.I właśnie do badania kierowane do każdego z moich EchoBean wydrukować jedną właściwość:

.unmarshal(jaxbDataFormat).bean(EchoBean.class, "printWeatherStation") 

i EchoBean:

public class EchoBean { 

    public String printWeatherStation(WeatherCurrent weatherCurrent) { 
     return weatherCurrent.getStation(); 
    } 
} 

ładnie wypisuje nazwy stacji pogodowych z komponentu zalogować Camel.

Ten nieudokumentowane rzeczą, która przeszkadza mi to, że musiałem umieścić ten plik jaxb.index następny WeatherCurrent źródła java choć http://camel.apache.org/jaxb.html wyraźnie mówi, że kontekst JAXB jest inicjowany z

DataFormat jaxb = new JaxbDataFormat("com.acme.model"); 
+1

Jest to wymóg JAXB, możesz mieć plik jaxb.index lub podać niestandardowy obiekt ObjectFactory. Zobacz metodę javadoc for newInstance: http://docs.oracle.com/javase/6/docs/api/javax/xml/bind/JAXBContext.html –

2

W pom.xml zawierać następującą zależność -

<dependency> 
     <groupId>org.apache.camel</groupId> 
     <artifactId>camel-jaxb</artifactId> 
     <version>2.13.0</version> 
    </dependency> 

Następny adnotacji klasę Pojo z @XmlRootElement (name = "pracownika")

package com.javainuse.model; 

import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement(name = "employee") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Employee { 

    private String empName; 
    private int empId; 

    public String getEmpName() { 
     return empName; 
    } 

    public void setEmpName(String empName) { 
     this.empName = empName; 
    } 

    public int getEmpId() { 
     return empId; 
    } 

    public void setEmpId(int empId) { 
     this.empId = empId; 
    } 
} 

Wreszcie w klasie RouteBuilder zdefiniuj format danych jaxb i użyj go w trasie.

// XML Data Format 
     JaxbDataFormat xmlDataFormat = new JaxbDataFormat(); 
     JAXBContext con = JAXBContext.newInstance(Employee.class); 
     xmlDataFormat.setContext(con); 

from("file:C:/inputFolder").doTry().unmarshal(xmlDataFormat). 
     process(new MyProcessor()).marshal(jsonDataFormat). 
     to("jms:queue:javainuse") 

kod źródłowy i więcej szczegółów - Apache Camel - Marshalling/Unmarshalling XML/JSON Data

Powiązane problemy