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>
Дополнительная информация