web-dev-qa-db-ja.com

Xpath式とjaxbを使用したXMLの非整列化

私はJAXBを初めて使用するので、XMLを応答オブジェクトにアンマーシャルできるが、xpath式を使用できる方法があるかどうか知りたいです。問題は、サードパーティのWebサービスに電話をかけていて、受け取った応答に多くの詳細が含まれていることです。 XMLのすべての詳細を応答オブジェクトにマップしたくありません。特定のXPath式を使用して取得できるxmlからいくつかの詳細をマップし、それらを応答オブジェクトにマップしたいだけです。これを達成するのに役立つ注釈はありますか?

たとえば、次の応答を考えます

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

ありがとう

17
Pratik Shelar

注:私は 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-your.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>

詳細情報

20
bdoughan

ストリート名だけが必要な場合は、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);
    }

}
10
Michael Kay

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>

詳細情報

0
bdoughan