18

我是 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
     ....
}   

谢谢

4

3 回答 3

21

注意: 我是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在与域模型相同的包中调用的文件,其中包含以下条目(请参阅: http ://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as -你的.html )

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

演示

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>

了解更多信息

于 2013-06-17T10:34:26.597 回答
10

如果您只需要街道名称,只需使用 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);
    }

}
于 2013-06-17T09:22:13.440 回答
0

如果要映射到 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>

了解更多信息

于 2013-06-17T15:37:45.303 回答