2017-03-01 4 views
1

Ich möchte Xml basierend auf Attributwert analysieren mit Spring Batch unten ist XML als Referenz.Parsen Sie XML-Fragment basierend auf Attributwert mit Spring-Batch

<?xml version="1.0" encoding="UTF-8"?> 
<customerInfo> 
<cutommer dept="IT"> 
<param value="Jane" name="first-name"/> 
<param value="Doe" name="last-name"/> 
<param value="17 Streets" name="address"/> 
<param value="1234567" name="phone-number"/> 
</customer> 
<cutommer dept="ES"> 
<param value="Jane" name="first-name"/> 
<param value="Doe" name="last-name"/> 
<param value="17 Streets" name="address"/> 
<param value="1234567" name="phone-number"/> 
</customer> 
</customerInfo> 

Base auf oben xml wollen nur Kunden Tag zu analysieren, welche dept atribute Wert ist "IT" Jede mögliche Hilfe appriciated wird

Update 1:

@Configuration 
@EnableBatchProcessing 
public class ControllerInfoParser_Config extends DefaultBatchConfigurer { 

    @Autowired 
    private JobBuilderFactory jobs; 
    @Autowired 
    private StepBuilderFactory steps; 
    @Bean 
    public Job parseComponentInfoXML(Step parseComponentInfo,Step partitionStep, CustomJobExecutionerListener customJobExecutionerListener) 
      throws UnexpectedInputException, ParseException, Exception { 

     return jobs.get("parseComponentInfoXML").listener(customJobExecutionerListener).start(parseComponentInfo) 
       .next(partitionStep).build(); 


    } 
    @Bean 
    public Step parseComponentInfo(ItemReader<Customer> oneDeptITItemReader) throws UnexpectedInputException, ParseException, Exception { 

     return steps.get("parseComponentInfo").<Customer, Customer> chunk(1) 
       .reader(componentInfoReader()).reader(oneDeptITItemReader).processor(componentInfoProcessor()) 
       .writer(componentInfoWriter()).build(); 
    } 

    @Bean 
    public ItemReader<Customer> componentInfoReader() throws UnexpectedInputException, ParseException, Exception { 

     //OneDeptITItemReader <Customer> reader1 = new OneDeptITItemReader<Customer>(); 
     StaxEventItemReader<Customer> reader = new StaxEventItemReader<Customer>(); 
     reader.setResource(new ClassPathResource("xml//customer.xml")); 
     reader.setFragmentRootElementName("customer"); 

     Jaxb2Marshaller marshaller = new org.springframework.oxm.jaxb.Jaxb2Marshaller(); 
     marshaller.setClassesToBeBound(Customer.class); 

     // marshaller.setSchema(new ClassPathResource("xml//company.xsd")); 

     reader.setUnmarshaller(marshaller); 

     return reader; 
    } 

    @Bean 
    public ItemReader<Customer> oneDeptITItemReader(ItemReader<Customer> ir) { 
     OneDeptITItemReader<Customer> odIR = new OneDeptITItemReader<Customer>(); 
     odIR.setDelegate(ir); 
     return odIR; 
    } 
    @Bean 
    public ItemProcessor<Customer, Customer> componentInfoProcessor() { 

     return new CustomerProcessor(); 
    } 

    @Bean 
    public ItemWriter<Object> componentInfoWriter() { 

     return new SqlWritter(); 
    } 
} 

public class OneDeptITItemReader <T> implements ItemReader <Customer>{ 

    ItemReader<Customer> delegate; 

     public ItemReader<Customer> getDelegate() { 
     return delegate; 
    } 

    public void setDelegate(ItemReader<Customer> delegate) { 
     this.delegate = delegate; 
    } 

    @Override 
    public Customer read() { 
     boolean read = true; 
     Customer item = null; 
     while(read) { 
      try { 
      item = delegate.read(); 
     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
      read =false; 
     } 
     read = !"IT".equals(item.getDept()); 
     } 
     return item; 
     } 

} 
+0

Konzentrieren Sie sich nicht auf zu lesen, sondern auf Prozessphase: mit einem benutzerdefinierten 'ItemProcessor ' null zurück, wenn dept <> „IT“ oder Objekt zurückgeben selbst wenn dept gleich ist zu „IT“ –

+0

Danke Luca für den Vorschlag, früher habe ich über diesen Ansatz nachgedacht, aber meine XML-Datei wird rund 15 MB groß sein und sie enthält nur ein Fragment, das Attribut Wert ist "IT", und Tausende von Kundenfragment wird unnötig Parsen und kommen zu ItemProcessor . Gibt es einen Weg, wie wir den weiteren Batch-Prozess stoppen können, wenn wir Kundenfragmente mit IT-Abteilung erhalten, um unnötigen Verbrauch von Ressourcen zu vermeiden. –

Antwort

0

Die Art und Weise das Lesen zu stoppen ist, zurückgeben null von ItemReader.read().
Schreiben Sie einen benutzerdefinierten ItemReader-Delegaten und stoppen Sie das Lesen, nachdem eine "IT" -Abteilung gefunden wurde.

Bei der Delegierung müssen Sie den delegierten Leser als Stream registrieren, damit der SB seinen Lebenszyklus verwalten kann. Siehe 6.5 The Delegate Pattern and Registering with the Step

+0

Danke Luca für das Teilen von Snippet, habe ich oben Code versucht, aber Null Zeiger Ausnahme beim Aufruf von delegate.read(). –

+0

Ich nehme an, Sie haben einen gültigen Delegaten vor dem Aufruf meines Code-Snippets gesetzt. –

+0

Ich habe Implementierungsdetails in Frage gestellt siehe Update 1: lassen Sie mich wissen, wenn etwas zu ändern ist. –

0

Unten Schnipsel arbeiten für mich.

Die Methode zum Beenden des Lesens besteht darin, von ItemReader.read() null zurückzugeben. Schreiben Sie einen benutzerdefinierten ItemReader-Delegaten und stoppen Sie das Lesen, nachdem eine "IT" -Abteilung gefunden wurde.

class OneDeptITItemReader implements ItemReader<Customer> { 
StaxEventItemReader<Customer> delegate; 

public void setDelegate(StaxEventItemReader<Customer> delegate) { 
     this.delegate = delegate; 
    } 

    @Override 
    public Customer read() { 
    boolean read = true; 
    delegate.open(new ExecutionContext()); 
    Customer item = null; 
    while(read) { 
    item = delegate.read(); 
    read = item != null && !"IT".equals(item.getDept()); 
    } 
    return item; 
    } 
} 
Verwandte Themen