Unmarshalling XML с использованием выражения Xpath и jaxb

Я новичок в JAXB и хотел бы знать, есть ли способ, с помощью которого я могу размонтировать XML для моего объекта ответа, но используя выражения xpath. Проблема в том, что я звоню в сторонний веб-сервис, и ответ, который я получаю, содержит много деталей. Я не хочу сопоставлять все детали в XML с моим объектом ответа. Я просто хочу отобразить несколько деталей из xml, используя которые я могу получить с помощью определенных выражений XPath и сопоставить их с моим объектом ответа. Есть ли аннотация, которая может помочь мне в этом?

Например, рассмотрим следующий ответ

<root>
  <record>
    <id>1</id>
    <name>Ian</name>
    <AddressDetails>
      <street> M G Road </street>
    </AddressDetails>
  </record>  
</root>

Меня интересует только поиск имени улицы, поэтому я хочу использовать выражение xpath, чтобы получить значение улицы, используя "root/record/AddressDetails/street" и сопоставить его с объектом ответа

public class Response{
     // How do i map this in jaxb, I do not wish to map record,id or name elements
     String street; 

     //getter and setters
     ....
}   

Спасибо

Ответы

Ответ 1

Примечание. Я EclipseLink JAXB (MOXy) ведет и член группы JAXB (JST-222).

Вы можете использовать расширение MOXy @XmlPath для этого варианта использования.

ответ

import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement(name="root")
@XmlAccessorType(XmlAccessType.FIELD)
public class Response{
    @XmlPath("record/AddressDetails/street/text()")
    String street; 

    //getter and setters
}

jaxb.properties

Чтобы использовать MOXy в качестве вашего провайдера JAXB, вам нужно включить файл с именем jaxb.properties в том же пакете, что и ваша модель домена, со следующей записью (см.: <а2 > )

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Demo

import java.io.File;
import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Response.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum17141154/input.xml");
        Response response = (Response) unmarshaller.unmarshal(xml);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(response, System.out);
    }

}

Выход

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <record>
      <AddressDetails>
         <street> M G Road </street>
      </AddressDetails>
   </record>
</root>

Дополнительная информация

Ответ 2

Если вы хотите только название улицы, просто используйте выражение XPath, чтобы получить его как строку, и забудьте о JAXB - сложный механизм JAXB не добавляет никакого значения.

import javax.xml.xpath.*;
import org.xml.sax.InputSource;

public class XPathDemo {

    public static void main(String[] args) throws Exception {
        XPathFactory xpf = XPathFactory.newInstance();
        XPath xpath = xpf.newXPath();

        InputSource xml = new InputSource("src/forum17141154/input.xml");
        String result = (String) xpath.evaluate("/root/record/AddressDetails/street", xml, XPathConstants.STRING);
        System.out.println(result);
    }

}

Ответ 3

Если вы хотите сопоставить середину документа XML, вы можете сделать следующее:

Демо-код

Вы можете использовать синтаксический анализатор StAX для перехода к той части документа, которую вы хотите размонтировать, а затем отмените оттуда XMLStreamReader,

import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Response.class);

        XMLInputFactory xif = XMLInputFactory.newFactory();
        StreamSource xml = new StreamSource("src/forum17141154/input.xml");
        XMLStreamReader xsr = xif.createXMLStreamReader(xml);
        while(!(xsr.isStartElement() && xsr.getLocalName().equals("AddressDetails"))) {
            xsr.next();
        }

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        JAXBElement<Response> response = unmarshaller.unmarshal(xsr, Response.class);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(response, System.out);
    }

}

ответ

Отображения на объекте домена сделаны относительно фрагмента XML-документа, к которому вы привязываетесь.

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
public class Response{

    String street; 

    //getter and setters
}

Выход

<?xml version="1.0" encoding="UTF-8"?>
<AddressDetails>
   <street> M G Road </street>
</AddressDetails>

Дополнительная информация