【问题标题】:Jaxb complex xml unmarshallJaxb 复杂的 xml 解组
【发布时间】:2011-05-16 16:17:12
【问题描述】:

我在解组下面的嵌套 xml 时遇到问题。如果我遗漏了什么,有人可以告诉我。
body 标签可以包含任何 Jaxb 带注释的 obj。
我是否必须创建一个自定义适配器来编组/解组此类 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 注释对象。

【问题讨论】:

    标签: java jaxb


    【解决方案1】:

    您可以使用@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);
    
        }
    
    }
    

    更多信息

    【讨论】:

    • 感谢工作。只是想补充一点,我必须将 CreateRq 添加到 JAXBContext 初始化中才能使其正常工作。感谢您的帮助
    • 如果我们将 lax 设置为 false(默认行为),它会根据 xml 内容创建一个 dom 对象,并且不会尝试将其映射到已知对象上?
    【解决方案2】:

    您可以使用@XmlAnyElement(lax=true) 和EclipseLink JAXB (MOXy) 中的@XmlPath 扩展来处理这个用例(注意:我是MOXy 负责人)。有关适用于任何 JAXB 实现(Metro、MOXy、JaxMe 等)的方法,请参阅:Jaxb complex xml unmarshall。

    ServiceRq

    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
    

    更多信息

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-15
      • 1970-01-01
      • 2013-01-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多