2012-08-02 29 views
1

我正在使用EclipseLink MOXy並具有具有相同數據類型的子元素的數據結構。現在我不想以無限深度序列化數據結構,但只想到第一層。帶有遞歸數據結構的EclipseLink MOXy /同一類型的子元素

這裏是數據結構的一些示例代碼:

package test; 

import java.util.Collection; 
import java.util.Vector; 

import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAttribute; 
import javax.xml.bind.annotation.XmlElementRef; 
import javax.xml.bind.annotation.XmlElementWrapper; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlAccessorType(XmlAccessType.PROPERTY) 
@XmlRootElement 
public class MyClass { 
    private int id; 
    private String details; 
    private Collection<MyClass> children = new Vector<MyClass>(); 

    public MyClass() { 
    } 

    public MyClass(int id, String details) { 
     this.id = id; 
     this.details = details; 
    } 

    @XmlElementWrapper 
    @XmlElementRef 
    public Collection<MyClass> getChildren() { 
     return children; 
    } 

    public void addChild(MyClass child) { 
     children.add(child); 
    } 

    public String getDetails() { 
     return details; 
    } 

    @XmlAttribute 
    public int getId() { 
     return id; 
    } 

    public void setChildren(Collection<MyClass> children) { 
     this.children = children; 
    } 

    public void setDetails(String details) { 
     this.details = details; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 
} 

而我的測試程序:

package test; 

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

public class Test { 
    public static void main(String[] args) throws Exception { 
     MyClass l1 = new MyClass(1, "Level 1"); 
     MyClass l2 = new MyClass(2, "Level 2"); 
     l1.addChild(l2); 
     MyClass l3 = new MyClass(3, "Level 3"); 
     l2.addChild(l3); 

     JAXBContext jc = JAXBContext.newInstance(MyClass.class); 
     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(l1, System.out); 
    } 
} 

以下XML生成:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<myClass id="1"> 
    <children> 
     <myClass id="2"> 
      <children> 
       <myClass id="3"> 
        <children/> 
        <details>Level 3</details> 
       </myClass> 
      </children> 
      <details>Level 2</details> 
     </myClass> 
    </children> 
    <details>Level 1</details> 
</myClass> 

然而,I」 d像xml一樣:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<myClass id="1"> 
    <children> 
     <myClass id="2"> 
      <details>Level 2</details> 
     </myClass> 
    </children> 
    <details>Level 1</details> 
</myClass> 

謝謝。

回答

3

要完成此用例,我們將利用JAXB的兩個概念:XmlAdapterMarshaller.Listener

MyClassAdapter

我們將利用空值未編組的元素的默認JAXB行爲。爲此,我們將實現一個XmlAdapter,它在達到指定級別後返回null。爲了計算水平,我們將創建一個Marshaller.Listener

package forum11769758; 

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

public class MyClassAdapter extends XmlAdapter<MyClass, MyClass>{ 

    private int levels; 
    private MyMarshallerListener marshallerListener; 

    public MyClassAdapter() { 
    } 

    public MyClassAdapter(int levels) { 
     this.levels = levels; 
    } 

    public Marshaller.Listener getMarshallerListener() { 
     if(null == marshallerListener) { 
      marshallerListener = new MyMarshallerListener(); 
     } 
     return marshallerListener; 
    } 

    @Override 
    public MyClass marshal(MyClass myClass) throws Exception { 
     if(null == marshallerListener || marshallerListener.getLevel() < levels) { 
      return myClass; 
     } 
     return null; 
    } 

    @Override 
    public MyClass unmarshal(MyClass myClass) throws Exception { 
     return myClass; 
    } 

    static class MyMarshallerListener extends Marshaller.Listener { 

     private int level = 0; 

     public int getLevel() { 
      return level; 
     } 

     @Override 
     public void afterMarshal(Object object) { 
      if(object instanceof MyClass) { 
       level--; 
      } 
     } 

     @Override 
     public void beforeMarshal(Object object) { 
      if(object instanceof MyClass) { 
       level++; 
      } 
     } 

    } 

} 

MyClass的

@XmlJavaTypeAdapter註解用於指定一個XmlAdapter應該被使用。

package forum11769758; 

import java.util.*; 
import javax.xml.bind.annotation.*; 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; 

@XmlAccessorType(XmlAccessType.PROPERTY) 
@XmlRootElement 
public class MyClass { 

    private int id; 
    private String details; 
    private Collection<MyClass> children = new Vector<MyClass>(); 

    public MyClass() { 
    } 

    public MyClass(int id, String details) { 
     this.id = id; 
     this.details = details; 
    } 

    @XmlElementWrapper 
    @XmlElementRef 
    @XmlJavaTypeAdapter(MyClassAdapter.class) 
    public Collection<MyClass> getChildren() { 
     return children; 
    } 

    public void addChild(MyClass child) { 
     children.add(child); 
    } 

    public String getDetails() { 
     return details; 
    } 

    @XmlAttribute 
    public int getId() { 
     return id; 
    } 

    public void setChildren(Collection<MyClass> children) { 
     this.children = children; 
    } 

    public void setDetails(String details) { 
     this.details = details; 
    } 

    public void setId(int id) { 
     this.id = id; 
    } 

} 

測試

因爲我們需要一個有狀態的方式使用XmlAdapter,我們將設置它的實例在Marshaller,我們還將設置的Marshaller.Listener的情況下,我們的Marshaller創建。

package forum11769758; 

import javax.xml.bind.*; 

public class Test { 

    public static void main(String[] args) throws Exception { 
     MyClass l1 = new MyClass(1, "Level 1"); 
     MyClass l2 = new MyClass(2, "Level 2"); 
     l1.addChild(l2); 
     MyClass l3 = new MyClass(3, "Level 3"); 
     l2.addChild(l3); 

     JAXBContext jc = JAXBContext.newInstance(MyClass.class); 
     Marshaller marshaller = jc.createMarshaller(); 
     MyClassAdapter myClassAdapter = new MyClassAdapter(2); 
     marshaller.setAdapter(myClassAdapter); 
     marshaller.setListener(myClassAdapter.getMarshallerListener()); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(l1, System.out); 
    } 

} 

輸出

<?xml version="1.0" encoding="UTF-8"?> 
<myClass id="1"> 
    <children> 
     <myClass id="2"> 
     <children/> 
     <details>Level 2</details> 
     </myClass> 
    </children> 
    <details>Level 1</details> 
</myClass> 

更多信息

以下文章對這個答案討論的議題展開:

+1

非常感謝!這和你的其他貢獻在這裏和你的博客上的文章是非常有用的開始使用JAXB等。 – Mario 2012-08-03 03:19:06