From 2b0e75b3bf7dc6b188399153b7e38d34226759b6 Mon Sep 17 00:00:00 2001 From: wxlund Date: Fri, 7 Mar 2008 15:29:06 +0000 Subject: [PATCH] (1) I went into much more detail on the staxEventItemReader - but I think the right level of detail - to make the configuration and the code that uses the configuration understandable to a developer. The level I got from our HOWTOs wasn't sufficiently deep. (2) there is now very readable pseudo code (groovy script) in the end of the explanation that pulls together the developer logic. This code executes correctly if you have the groovy plugin installed. I created a separate project for myself called spring-batch-docs-examples with the groovy nature that makes it much easier for me to get example code running and then document from easier to read scripting code." /Users/wxlund/workspace/spring-batch-source-forge/trunk/docs/src/site/docbook/reference/staxReaderWriter.xml --- .../docbook/reference/readersAndWriters.xml | 168 +++++++++++++++++- 1 file changed, 160 insertions(+), 8 deletions(-) diff --git a/docs/src/site/docbook/reference/readersAndWriters.xml b/docs/src/site/docbook/reference/readersAndWriters.xml index 40e933ab9..77ed703bf 100644 --- a/docs/src/site/docbook/reference/readersAndWriters.xml +++ b/docs/src/site/docbook/reference/readersAndWriters.xml @@ -858,13 +858,6 @@ FOT;2;2;267.34 document, therefore the Spring Batch infrastructure needs to work around this fact (as described below). - On input the reader reads the XML resource until it recognizes a new - fragment is about to start (by matching the tag name by default). The - reader creates a standalone XML document from the fragment (or at least - makes it appear so) and passes the document to a deserializer (typically a - wrapper around Spring WS Unmarshaller) to map the XML to a Java - object. - Figure X: XML Inputs + + The StaxEventItemReader configuration provides a typical setup for the processing of records from an XML input stream. First, lets examine a set of xml records that the StaxEventItemReader can process. + + + +<?xml version="1.0" encoding="UTF-8"?> +<records> + <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> + <isin>XYZ0001</isin> + <quantity>5</quantity> + <price>11.39</price> + <customer>Customer1</customer> + </trade> + <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> + <isin>XYZ0002</isin> + <quantity>2</quantity> + <price>72.99</price> + <customer>Customer2c</customer> + </trade> + <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> + <isin>XYZ0003</isin> + <quantity>9</quantity> + <price>99.99</price> + <customer>Customer3</customer> + </trade> + <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> + <isin>XYZ0001</isin> + <quantity>5</quantity> + <price>11.39</price> + <customer>Customer1</customer> + </trade> + <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> + <isin>XYZ0002</isin> + <quantity>2</quantity> + <price>72.99</price> + <customer>Customer2c</customer> + </trade> + <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> + <isin>XYZ0003</isin> + <quantity>9</quantity> + <price>99.99</price> + <customer>Customer3</customer> + </trade> + <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> + <isin>XYZ0001</isin> + <quantity>5</quantity> + <price>11.39</price> + <customer>Customer1</customer> + </trade> + <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> + <isin>XYZ0002</isin> + <quantity>2</quantity> + <price>72.99</price> + <customer>Customer2c</customer> + </trade> + <trade xmlns="http://springframework.org/batch/sample/io/oxm/domain"> + <isin>XYZ0003</isin> + <quantity>9</quantity> + <price>99.99</price> + <customer>Customer3</customer> + </trade> +</records> + + + + + To be able to process the XML records we need the following: + + + Root Element Name - this is name of the root element of the fragment that constitutes the object to be mapped in. The example configuration + demonstrates this with the value of trade. + + + Resource - This is a Spring Resource that in the case of this example will abstract the details of opening a file for reading content. + + + Fragment Deserializer - this is the UnMarshalling facility provided by Spring OXM for mapping the XML fragment to an object. + + + + + <property name="itemReader"> + <bean class="org.springframework.batch.io.xml.StaxEventItemReader"> + <property name="fragmentRootElementName" value="trade" /> + <property name="resource" value="data/staxJob/input/20070918.testStream.xmlFileStep.xml" /> + <property name="fragmentDeserializer"> + <bean class="org.springframework.batch.io.xml.oxm.UnmarshallingEventReaderDeserializer"> + <constructor-arg> + <bean class="org.springframework.oxm.xstream.XStreamMarshaller"> + <property name="aliases" ref="aliases" /> + </bean> + </constructor-arg> + </bean> + </property> + </bean> +</property> + + + + Notice that it requires an alias passed in as a map with the + first key and value being the name of the fragment and the object + type that it will be mapped. Then, similar to a FieldSet, the + names of the other elements that map to fields within the object + type are described as key/value pairs in the map. In the + configuration file we can use a spring configuration utility to + described the required alias as follows: + + + <util:map id="aliases"> + <entry key="trade" + value="org.springframework.batch.sample.domain.Trade" /> + <entry key="isin" value="java.lang.String" /> + <entry key="quantity" value="long" /> + <entry key="price" value="java.math.BigDecimal" /> + <entry key="customer" value="java.lang.String" /> + </util:map> + + + + On input the reader reads the XML resource until it recognizes a new + fragment is about to start (by matching the tag name by default). The + reader creates a standalone XML document from the fragment (or at least + makes it appear so) and passes the document to a deserializer (typically a + wrapper around Spring WS Unmarshaller) to map the XML to a Java + object. + + + In summary, if you were to see this in scripted code like Java the injection provided by the spring configuration would look something like the following: + + + + def xmlStaxEventItemReader = new StaxEventItemReader() + resource = new ByteArrayResource(xmlResource.getBytes()) + + def aliases = ["trade":"org.springframework.batch.sample.domain.Trade", + "isin":"java.lang.String", + "quantity":"long", + "price":"java.math.BigDecimal", + "customer":"java.lang.String"] + def marshaller = new XStreamMarshaller() + marshaller.setAliases(aliases) + xmlStaxEventItemReader.setFragmentDeserializer(new UnmarshallingEventReaderDeserializer(marshaller)) + xmlStaxEventItemReader.setResource(resource) + xmlStaxEventItemReader.setFragmentRootElementName("trade") + def executionContext = new ExecutionContext() + xmlStaxEventItemReader.open(executionContext); + + def hasNext = true + while (hasNext) { + trade = xmlStaxEventItemReader.read() + if (trade == null) { + hasNext = false + } else { + println trade + } + } + + + Output works symetrically to input. Java object is passed to a serializer (typically a wrapper around Spring WS Marshaller) which writes to output using a custom event writer that filters the StartDocument and @@ -927,4 +1079,4 @@ FOT;2;2;267.34 - \ No newline at end of file +