Статьи

Обработка середины XML-документа с помощью JAXB и StAX

В последнее время я встречал много людей, спрашивающих, как читать данные или записывать данные в середину XML-документа. В этом посте я покажу, как это можно сделать с помощью JAXB с StAX. Примечание.  Реализации JAXB (JSR-222) и StAX (JSR-173) включены в JDK / JRE начиная с Java SE 6.

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-документа все, что нам нужно сделать, это следующее:

  1. Создайте XMLStreamReader из XML-ввода (строка 12).
  2. Продвиньте XMLStreamReader к элементу возврата (строки 13-16).
  3. Распакуйте экземпляр 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-документа, все, что нам нужно сделать, это следующее:
  1. Создайте XMLStreamWriter для вывода XML (строка 18).
  2. Запустите документ и напишите внешние элементы (строки 19-22).
  3. Установите свойство Marshaller.JAXB_FRAGMENT на Marshaller (строка 26), чтобы предотвратить запись XML-декларации.
  4. Маршал экземпляра Customer для XMLStreamWriter (строка 27).
  5. Завершите документ, это закроет все открытые элементы (строка 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>