JAXB - marshalling with recursive dependency

筅森魡賤 提交于 2019-12-08 04:46:49

问题


is anybody try to marshal JAXB object with recurisive referency? I have following class:

public class A {

   private Long id;
   private String name;
   private List<A> aList;

}

and I'd like to marshall it to:

<a>
  <a>
    <a>...</a>
  ...
  </a>
...
</a>

I'm using maven plugin to auto generate JAXB class from XSD. Any suggestions?


回答1:


Below is how you can support this use case starting from your XML schema.

XML SCHEMA (schema.xsd)

The following XML schema is based on the comment you made to a previous answer (http://stackoverflow.com/a/14317461/383861).

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.example.org" 
    xmlns:tns="http://www.example.org"
    elementFormDefault="qualified">

    <xs:element name="b">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="tns:a" maxOccurs="unbounded" />
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    <xs:element name="a">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="id" type="xs:long" />
                <xs:sequence>
                    <xs:element ref="tns:a" minOccurs="0" maxOccurs="10" />
                </xs:sequence>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

</xs:schema>

GENERATED MODEL

The following code was generated using the xjc tool. The get/set methods and comments have been removed to save space.

A

package org.example;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "id",
    "a"
})
@XmlRootElement(name = "a")
public class A {

    protected long id;
    protected List<A> a;

}

B

package org.example;

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
    "a"
})
@XmlRootElement(name = "b")
public class B {

    @XmlElement(required = true)
    protected List<A> a;

}

package-info

@javax.xml.bind.annotation.XmlSchema(
        namespace = "http://www.example.org", 
        elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package org.example;

ObjectFactory

package org.example;

import javax.xml.bind.annotation.XmlRegistry;

@XmlRegistry
public class ObjectFactory {

    public ObjectFactory() {
    }

    public B createB() {
        return new B();
    }

    public A createA() {
        return new A();
    }

}

DEMO CODE

import java.io.File;
import javax.xml.bind.*;
import org.example.A;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance("org.example");

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum14306965/input.xml");
        A a = (A) unmarshaller.unmarshal(xml);

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

}

INPUT (input.xml)/OUTPUT

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a xmlns="http://www.example.org">
    <id>1</id>
    <a>
        <id>2</id>
        <a>
            <id>3</id>
        </a>
    </a>
</a>



回答2:


You could do the following:

A

You can use the @XmlElementRef annotation on the aList field so that the element it uses comes from the @XmlRootElement annotation on the A class.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class A {

    private Long id;

    private String name;

    @XmlElementRef
    private List<A> aList;

}

Demo

Below is some sample code to prove that everything works.

import java.io.File;
import javax.xml.bind.*;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum14306965/input.xml");
        A a = (A) unmarshaller.unmarshal(xml);

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

}

input.xml/Output

Below is the input to and output from running the demo code.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<a>
    <id>1</id>
    <name>A</name>
    <a>
        <id>2</id>
        <name>B</name>
        <a>
            <id>3</id>
            <name>C</name>
        </a>
    </a>
</a>

XML Schema

Below is the XML schema that corresponds to this model. You could generate the model from it or start from the Java model.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <xs:element name="a" type="a"/>

  <xs:complexType name="a">
    <xs:sequence>
      <xs:element name="id" type="xs:long" minOccurs="0"/>
      <xs:element name="name" type="xs:string" minOccurs="0"/>
      <xs:element ref="a" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

</xs:schema>


来源:https://stackoverflow.com/questions/14306965/jaxb-marshalling-with-recursive-dependency

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!