В последнее время я встречал много людей, спрашивающих, как читать данные или записывать данные в середину XML-документа. В этом посте я покажу, как это можно сделать с помощью JAXB с StAX. Примечание. Реализации JAXB (JSR-222) и StAX (JSR-173) включены в JDK / JRE начиная с Java SE 6.
Мы будем использовать сообщение SOAP в качестве образца XML. Внешние части документа XML представляют информацию, относящуюся к веб-службе, а внутренние части (строки 5-8) представляют данные, которые мы хотим преобразовать в нашу модель предметной области.
Чтобы перейти к середине XML-документа, все, что нам нужно сделать, это следующее:
XML (input.xml)
Мы будем использовать сообщение SOAP в качестве образца XML. Внешние части документа XML представляют информацию, относящуюся к веб-службе, а внутренние части (строки 5-8) представляют данные, которые мы хотим преобразовать в нашу модель предметной области.
<?xml version="1.0" encoding="UTF-8"?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns0:findCustomerResponse xmlns:ns0="http://service.jaxws.blog/"> <return id="123"> <firstName>Jane</firstName> <lastName>Doe</lastName> </return> </ns0:findCustomerResponse> </S:Body> </S:Envelope>
Модель Java
Наша модель Java состоит из одного класса домена. Концепции в этом примере также применимы к более крупным моделям доменов.
package blog.stax.middle; import javax.xml.bind.annotation.*; @XmlAccessorType(XmlAccessType.FIELD) public class Customer { @XmlAttribute int id; String firstName; String lastName; }
Демоверсия демаршала
Чтобы демонтировать из середины XML-документа все, что нам нужно сделать, это следующее:
- Создайте XMLStreamReader из XML-ввода (строка 12).
- Продвиньте XMLStreamReader к элементу возврата (строки 13-16).
- Распакуйте экземпляр Customer из XMLStreamReader (строка 20)
package blog.stax.middle; import javax.xml.bind.*; import javax.xml.stream.*; import javax.xml.transform.stream.StreamSource; public class UnmarshalDemo { public static void main(String[] args) throws Exception { XMLInputFactory xif = XMLInputFactory.newFactory(); StreamSource xml = new StreamSource("src/blog/stax/middle/input.xml"); XMLStreamReader xsr = xif.createXMLStreamReader(xml); xsr.nextTag(); while(!xsr.getLocalName().equals("return")) { xsr.nextTag(); } JAXBContext jc = JAXBContext.newInstance(Customer.class); Unmarshaller unmarshaller = jc.createUnmarshaller(); JAXBElement<Customer> jb = unmarshaller.unmarshal(xsr, Customer.class); xsr.close(); Customer customer = jb.getValue(); System.out.println(customer.id); System.out.println(customer.firstName); System.out.println(customer.lastName); } }
Выходные данные
Ниже приведен результат запуска демаршальной демоверсии.
123 Jane Doe
Маршал Демо
Чтобы перейти к середине XML-документа, все, что нам нужно сделать, это следующее:
- Создайте XMLStreamWriter для вывода XML (строка 18).
- Запустите документ и напишите внешние элементы (строки 19-22).
- Установите свойство Marshaller.JAXB_FRAGMENT на Marshaller (строка 26), чтобы предотвратить запись XML-декларации.
- Маршал экземпляра Customer для XMLStreamWriter (строка 27).
- Завершите документ, это закроет все открытые элементы (строка 29).
package blog.stax.middle; import javax.xml.bind.*; import javax.xml.namespace.QName; import javax.xml.stream.*; public class MarshalDemo { public static void main(String[] args) throws Exception { Customer customer = new Customer(); customer.id = 123; customer.firstName = "Jane"; customer.lastName = "Doe"; QName root = new QName("response"); JAXBElement<Customer> je = new JAXBElement<Customer>(root, Customer.class, customer); XMLOutputFactory xof = XMLOutputFactory.newFactory(); XMLStreamWriter xsw = xof.createXMLStreamWriter(System.out); xsw.writeStartDocument(); xsw.writeStartElement("S", "Envelope", "http://schemas.xmlsoap.org/soap/envelope/"); xsw.writeStartElement("S", "Body", "http://schemas.xmlsoap.org/soap/envelope/"); xsw.writeStartElement("ns0", "findCustomerResponse", "http://service.jaxws.blog/"); JAXBContext jc = JAXBContext.newInstance(Customer.class); Marshaller marshaller = jc.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true); marshaller.marshal(je, xsw); xsw.writeEndDocument(); xsw.close(); } }
Выходные данные
Ниже приведены результаты запуска демо-версии маршала. Обратите внимание, что вывод от запуска демонстрационного кода будет отображаться в одной строке, я отформатировал вывод здесь, чтобы его было легче читать.
<?xml version="1.0" encoding="UTF-8"?> <S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"> <S:Body> <ns0:findCustomerResponse xmlns:ns0="http://service.jaxws.blog/"> <return id="123"> <firstName>Jane</firstName> <lastName>Doe</lastName> </return> </ns0:findCustomerResponse> </S:Body> </S:Envelope>