2015-10-16 92 views
0

我需要根據元素類型的值映射後續xml。 BaseEntity超類具有Machine和Robot類的共同元素。每個子文件夾都有不同的元素... XML結構已修復,我無法更改它。 每個入口元素應映射到相應的類,入口/類型=機器應映射到子類機器等等......JAXB基於子元素值的Unmarshal子類

JAXB中可能嗎?我怎樣才能實現這個? 有什麼建議嗎?

<root> 
    <entries> 
     <entry> 
      <name>RTM</name> 
      <description>RealTime Machine</description> 
      <code>RTM1</code> 
      <type>Machine</type> 
     </entry> 
     <entry> 
      <name>RTM</name> 
      <description>RealTime Machine</description> 
      <type>Robot</type> 
      <serial>RS123<serial> 
     </entry> 
    </entries> 
</root> 

public abstract class BaseEntity { 
    private String name; 
    private String description; 
} 
public class Machine extends BaseEntity{ 
    private String code; 
} 
public class Robot extends BaseEntity{ 
    private String serial; 
} 
+0

如果你不關心性能,對所有子類進行解組,並根據'type'值選擇一個。 –

+0

是的,我是。該文檔是一個圖表模式,可以達到1000個條目,我需要加載他更快是可能的。其他方案? – s0d

回答

1

不幸的是,你的XML佈局非常糟糕。當JAXB解析器進入一個入口節點時,節點無法判斷它是機器人還是機器人。所以它必須猜測哪種類型用於unmarshlling。通常,您可以使用該類型作爲節點名稱(1),或者使用類型參數(2)提供一個屬性。

1:

<entries> 
    <machine>...</machine> 
    <robot>...</robot> 
</entries> 

2:

<entries> 
    <entry type="machine">...</entry> 
    <entry type="robot">...</entry> 
</entries> 

所以我的解決問題的方法是科學怪人爲您的XML。

有一個適應的類,它擴展了基類,並有可用的子類的所有屬性:

@XmlRootElement(name = "ENTRY") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class AdaptedBaseEntry extends BaseEntry 
{ 


    @XmlElement(name = "CODE", required = false) 
    public String code; 

    @XmlElement(name = "SERIAL", required = false) 
    public String serial; 

    public AdaptedBaseEntry() 
    { 
     super(); 
    } 

    public AdaptedBaseEntry(BaseEntry entry) 
    { 
     super(entry.type, entry.description, entry.name); 
     if (entry instanceof Machine) 
     { 
      this.code = ((Machine) entry).code; 
     } else if (entry instanceof Robot) 
     { 
      this.serial = ((Robot) entry).serial; 
     } 
    } 

} 

使用的XmlAdapter到適配器類綁定到XML,反之亦然:

public class BaseEntryAdapter extends XmlAdapter<AdaptedBaseEntry, BaseEntry> 
{ 

    @Override 
    public BaseEntry unmarshal(AdaptedBaseEntry v) throws Exception 
    { 
     switch (v.type) 
     { 
     case Machine: 
      return new Machine(v.name, v.description, v.code); 
     case Robot: 
      return new Robot(v.name, v.description, v.serial); 
     default: 
      return null; 
     } 
    } 

    @Override 
    public AdaptedBaseEntry marshal(BaseEntry v) throws Exception 
    { 
     return new AdaptedBaseEntry(v); 
    } 

}