Jaxb复杂XML反序列化

5

我遇到了解析下面嵌套的xml的问题。请问有人可以指点一下我是否遗漏了什么。
body标签可以包含任何Jaxb注释的对象。
我需要创建自定义适配器来编组/解组这样的xml吗?

输入XML

<?xml version="1.0" encoding="UTF-8"?>
<serviceRq xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="serviceRq">
  <body>   
    <createRq>
       <id>1234</id>
    </createRq>
  </body>
</serviceRq>

我的Jaxb注解类如下:

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "serviceRq")
public class ServiceRq{    
    private Object body;
    <!-- getters and setters omitted-->
}

在这里,body可以是任何使用jaxb注释的对象,在本例中它是CreateRq。

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "createRq")
public class CreateRq{    
    private String id;
    <!-- getters and setters omitted-->
}

我正在寻找一种通用的方法来支持输入XML的正文中的任何Jaxb注释对象。
2个回答

6
你可以使用@XmlAnyElement(lax=true)XmlAdapter来处理这个用例: ServiceRq
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "serviceRq")
public class ServiceRq{    

    @XmlJavaTypeAdapter(value=BodyAdapter.class)
    private Object body;
    // getters and setters omitted
}

BodyAdapter

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class BodyAdapter extends XmlAdapter<Body, Object>{

    @Override
    public Object unmarshal(Body v) throws Exception {
        return v.getValue();
    }

    @Override
    public Body marshal(Object v) throws Exception {
        Body body = new Body();
        body.setValue(v);
        return body;
    }

}

正文

import javax.xml.bind.annotation.XmlAnyElement;

public class Body {

    private Object value;

    @XmlAnyElement(lax=true)
    public Object getValue() {
        return value;
    }

    public void setValue(Object value) {
        this.value = value;
    }

}

CreateRq

import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "createRq")
public class CreateRq{    
    private String id;
    // getters and setters omitted
}

演示

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        ServiceRq serviceRq = (ServiceRq) unmarshaller.unmarshal(new File("input.xml"));

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

    }

}

更多信息


谢谢,那个方法起作用了。只想补充一下,我还必须在JAXBContext初始化中添加CreateRq才能使它正常工作。感谢您的帮助。 - BSingh
如果将lax设置为false(默认行为),它将从xml内容创建dom对象,并且不会尝试将其映射到已知对象上? - Charles Follet

2
您可以使用@XmlAnyElement(lax=true)@XmlPath扩展来处理此用例,而这在EclipseLink JAXB (MOXy)中是可行的(注意:我是MOXy的主管)。对于适用于任何JAXB实现(例如MetroMOXyJaxMe等)的方法,请参见:Jaxb complex xml unmarshallServiceRq
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import org.eclipse.persistence.oxm.annotations.XmlPath;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "serviceRq")
public class ServiceRq{    

    @XmlPath("body/createRq")
    @XmlAnyElement(lax=true)
    private Object body;
    // getters and setters omitted
}

CreateRq

import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "createRq")
public class CreateRq{    
    private String id;
    // getters and setters omitted
}

演示

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        ServiceRq serviceRq = (ServiceRq) unmarshaller.unmarshal(new File("input.xml"));

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

    }
}

jaxb.properties

要使用MOXy作为JAXB提供程序,您必须在与域模型相同的包中包含一个名为jaxb.properties的文件,并具有以下条目:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
更多信息

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接