Сложный XML с использованием Spring Batch; StaxEventItemWriter; Jaxb2Marshaller
Мне нужно написать немного сложный XML с использованием Spring Batch. Может кто-нибудь, пожалуйста, помогите мне с соответствующей конфигурацией Spring?
Ниже приведен вывод, который требуется процессу.
<XML>
<USERLIST ID="something" NAME="Sample">
<USER ID="userID" NAME="Name"/>
<USER ID="userID" NAME="Name"/>
........
</USERLIST>
<XML>
"UserList" в приведенном выше XML-коде должен встречаться только один раз
Это весенняя конфигурация у меня до сих пор.
<bean id="userXMLWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
<property name="resource" value="file:outputs/users.xml" />
<property name="encoding" value="ISO-8859-1" />
<property name="version" value="1.0" />
<property name="marshaller" ref="userXMLMarshaller" />
<property name="rootTagName" value="XML" />
</bean>
<bean id="userXMLMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="marshallerProperties">
<map>
<entry>
<key>
<util:constant static-field="javax.xml.bind.Marshaller.JAXB_FORMATTED_OUTPUT" />
</key>
<value type="java.lang.Boolean">true</value>
</entry>
</map>
</property>
<property name="classesToBeBound">
<list>
<value>org.test.model.xml.UserList</value>
<value>org.test.model.xml.User</value>
</list>
</property>
</bean>
Очевидно, что когда я проверяю это, в моем XML нет элемента "USERLIST", потому что все эти объекты USER нужно где-то добавить в USERLIST. Я новичок в Spring Batch и JAXB2. Любые идеи по этому поводу приветствуются.
Спасибо хариш
1 ответ
Решением этой проблемы является реализация классов Callback /Footer Callback, предоставляемых Spring (как Майкл Минелла предложил в комментариях ниже.), Класс StaxWriterCallback в моем случае. Ниже показано, как я это реализовал.
<bean id="userXMLWriter" class="org.springframework.batch.item.xml.StaxEventItemWriter">
<property name="resource" value="file:outputs/users.xml" />
<property name="encoding" value="ISO-8859-1" />
<property name="version" value="1.0" />
<property name="marshaller" ref="userXMLMarshaller" />
<property name="headerCallback" ref="UserXMLHeaderCallBack" />
<property name="footerCallback" ref="UserXMLFooterCallBack"/>
<property name="rootTagName" value="XML" />
</bean>
<bean id="UserXMLHeaderCallBack" class ="org.test.writers.UserXMLHeaderCallBack"/>
<bean id="UserXMLFooterCallBack" class ="org.test.writers.UserXMLFooterCallBack"/>
<bean id="userXMLMarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="classesToBeBound">
<list>
<value>org.test.model.xml.User</value>
</list>
</property>
</bean>
И ниже - реализация классов обратного вызова Footer/Header
public class UserXMLHeaderCallBack implements StaxWriterCallback{
@Override
public void write(XMLEventWriter writer) throws IOException {
try{
XMLEventFactory eventFactory = XMLEventFactory.newInstance();
Attribute id = eventFactory.createAttribute("ID", "someId");
Attribute name = eventFactory.createAttribute("NAME", "someName");
List<Attribute> attributeList = Arrays.asList(id, name);
List<?> nsList = Arrays.asList();
XMLEvent event = eventFactory.createStartElement("", "", "USERLIST",attributeList.iterator(), nsList.iterator());
writer.add(event);
}catch(XMLStreamException e){
System.err.println("Something went nuts!!!");
}
}
}
Класс нижнего колонтитула
public class UserXMLFooterCallBack implements StaxWriterCallback{
@Override
public void write(XMLEventWriter writer) throws IOException {
try{
XMLEventFactory eventFactory = XMLEventFactory.newInstance();
XMLEvent event = eventFactory.createEndElement("", "", "USERLIST");
writer.add(event);
}catch(XMLStreamException e){
System.err.println("Something went nuts!!!");
}
}
}
И я получил желаемый результат!