2011-03-16 50 views
7

我有以下XML結構,它跨多個XML元素對單個概念進行建模。這種格式不在我的控制之下。JAXB將多個XML元素解組爲單個類

<Output> 
    <Wrapper> 
    <Channel> 
     <id>1</id> 
     <type>x</type> 
    </Channel> 
    <Channel> 
     <id>2</id> 
     <type>y</type> 
    </Channel> 
    <ChannelName> 
     <id>1</id> 
     <name>Channel name</name> 
    </ChannelName> 
    <ChannelName> 
     <id>2</id> 
     <name>Another channel name</name> 
    </ChannelName> 
    </Wrapper> 
</Output> 

我想在我有沒有控制權,並可以有一個更簡單的Channelidtypename字段的數據庫來建模。因此,我想在Wrapper班上解組一個List<Channel>

這可以使用@Xml...註釋自動完成嗎?我目前正在使用JAXB解組到單獨的@XmlElement(name="Channel")@XmlElement(name="ChannelName")班級列表,然後在Channel上後處理暫態ChannelName/name,但我想必須有一種更簡單的自動化方法來映射這些元素。還是XSLT的工作?

它可能有助於知道XML作爲HTTP文件POST文件進入,而我正在使用Spring 3,Java和Hibernate。我希望在東西可能EclipseLink JAXB (MOXy)幫助:)

回答

12

@XmlElementWrapper將做的工作:

@XmlElementWrapper(name="Wrapper") 
@XmlElement(name="Channel") 
private List<Channel> channels; 

對於更高級的情況下,你可以使用的EclipseLink JAXB(莫西)的@XmlPath擴展:


這是我到目前爲止。我仍然試圖消除對幫助對象的需要。此示例需要EclipseLink JAXB (MOXy)

模型對象

你的模型對象是:

package example; 

import java.util.ArrayList; 
import java.util.List; 

public class Wrapper { 

    private List<Channel> channels = new ArrayList<Channel>(); 

    public List<Channel> getChannels() { 
     return channels; 
    } 

    public void setChannels(List<Channel> channels) { 
     this.channels = channels; 
    } 

} 

和:

package example; 

import javax.xml.bind.annotation.XmlID; 

public class Channel { 

    private String id; 
    private String type; 
    private String name; 

    @XmlID 
    public String getId() { 
     return id; 
    } 

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

    public String getType() { 
     return type; 
    } 

    public void setType(String type) { 
     this.type = type; 
    } 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

} 

器輔助對象

我目前的解決方案包括š一些輔助對象:

package example.adapted; 

import java.util.List; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlElementWrapper; 
import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.XmlTransient; 
import javax.xml.bind.annotation.XmlType; 

import example.Channel; 
import example.Wrapper; 

@XmlRootElement(name="Output") 
@XmlType(propOrder={"channels", "channelNames"}) 
public class AdaptedWrapper { 

    private Wrapper wrapper = new Wrapper(); 
    private List<ChannelName> channelNames; 

    @XmlTransient 
    public Wrapper getWrapper() { 
     for(ChannelName channelName : channelNames) { 
      channelName.getChannel().setName(channelName.getName()); 
     } 
     return wrapper; 
    } 

    @XmlElementWrapper(name="Wrapper") 
    @XmlElement(name="Channel") 
    public List<Channel> getChannels() { 
     return wrapper.getChannels(); 
    } 

    public void setChannels(List<Channel> channels) { 
     wrapper.setChannels(channels); 
    } 

    @XmlElementWrapper(name="Wrapper") 
    @XmlElement(name="ChannelName") 
    public List<ChannelName> getChannelNames() { 
     return channelNames; 
    } 

    public void setChannelNames(List<ChannelName> channelNames) { 
     this.channelNames = channelNames; 
    } 

} 

和:

package example.adapted; 

import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlIDREF; 

import example.Channel; 

public class ChannelName { 

    private String name; 
    private Channel channel; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 

    @XmlIDREF 
    @XmlElement(name="id") 
    public Channel getChannel() { 
     return channel; 
    } 

    public void setChannel(Channel channel) { 
     this.channel = channel; 
    } 

} 

演示代碼

package example; 

import java.io.File; 
import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Unmarshaller; 

import example.adapted.AdaptedWrapper; 

public class Demo { 

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

     File xml = new File("input.xml"); 
     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     AdaptedWrapper adaptedWrapper = (AdaptedWrapper) unmarshaller.unmarshal(xml); 
     Wrapper wrapper = adaptedWrapper.getWrapper(); 

     for(Channel channel : wrapper.getChannels()) { 
      System.out.println(channel.getName()); 
     } 
    } 

} 
+0

希望你會在@Blaise :)我看看XmlPath,但無法找到如何查找給定ID的名稱。所以當解組第一個'Channel'時,XPath我想拿起名字是'ChannelName [id =「1」]/name',但是看不到如何插入'id'。我會有一個現在看看你的博客。 – andyb 2011-03-16 12:53:31

+0

@andyb - 我們目前正在開發一個相關功能(請參閱https://bugs.eclipse.org/339596)。初始階段針對屬性上的條件(即ChannelName [@ id =「1」]/Name)。你需要組隊還是解組? – 2011-03-16 13:56:35

+0

@Blaise - 我只需要解組,看起來謂詞特徵可能是解決方案,因爲我需要從文檔中其他位置的元素中獲取數據?另外,我看了你的(優秀)博客,幾乎有MOXy在春季工作。花了一段時間讓我瞭解了jaxb.properties和jaxb.in​​dex文件。我目前正在得到'class org.springframework.oxm.jaxb.Jaxb2Marshaller $ ByteArrayDataSource需要一個零參數構造函數例外。我正在使用Eclipse持久性服務2.3.0.v20110312-r9123 – andyb 2011-03-16 14:51:47

2

您可以通過自動化的JAXB這個過程中節省您的編碼時間:

創建使用以下鏈接爲您的XML提供一個XML模式,並將其保存爲輸出。XSD文件: http://www.xmlforasp.net/CodeBank/System_Xml_Schema/BuildSchema/BuildXMLSchema.aspx

運行批處理腳本文件(命名爲output.bat)使用JDK作爲唯一的JDK有xjc.exe工具(填寫下面從項目的根文件夾(。)必要的細節):

"C:\Program Files\Java\jdk1.6.0_24\bin\xjc.exe" -p %1 %2 -d %3 

其中...

syntax: output.bat %1 %2 %3 
%1 = target package name 
%2 = full file path name of the generated XML schema .xsd 
%3 = root source folder to store generated JAXB java files 

實施例:

讓的說項目文件夾組織如下:(。)

. 
\_src 

運行在命令提示符下,從以下幾點:

output.bat com.project.xml .\output.xsd .\src 

它會創建一些文件:

. 
\_src 
    \_com 
    \_project 
     \_xml 
     |_ObjectFactory.java 
     |_Output.java 

然後,您可以在下面創建幾個有用的方法來操作對象:

private JAXBContext jaxbContext = null; 
private Unmarshaller unmarshaller = null; 
private Marshaller marshaller = null; 

public OutputManager(String packageName) { 
    try { 
     jaxbContext = JAXBContext.newInstance(packageName); 
     unmarshaller = jaxbContext.createUnmarshaller(); 
     marshaller = jaxbContext.createMarshaller(); 
    } catch (JAXBException e) { 
    } 
} 

public Output loadXML(InputStream istrm) { 

    Output load = null; 

    try { 
     Object o = unmarshaller.unmarshal(istrm); 

     if (o != null) { 

      load = (Output) o; 

     } 

    } catch (JAXBException e) { 

     JOptionPane.showMessageDialog(null, e.getLocalizedMessage(), e.getClass().getSimpleName(), JOptionPane.ERROR_MESSAGE); 

    } 
    return load; 
} 

public void saveXML(Object o, java.io.File file) { 

    Output save = null; 

    try { 
     save = (Output) o; 

     if (save != null) { 
      marshaller.marshal(save, file); 
     } 

    } catch (JAXBException e) { 

     JOptionPane.showMessageDialog(null, e.getLocalizedMessage(), e.getClass().getSimpleName(), JOptionPane.ERROR_MESSAGE); 

    } 
} 

public void saveXML(Object o, FileOutputStream ostrm) { 

    Output save = null; 

    try { 

     save = (Output) o; 

     if (save != null) { 
      marshaller.marshal(save, ostrm); 
     } 

    } catch (JAXBException e) { 

     JOptionPane.showMessageDialog(null, e.getLocalizedMessage(), e.getClass().getSimpleName(), JOptionPane.ERROR_MESSAGE); 

    } 
} 
+0

這很有用,但我認爲它不會解決我的問題,因爲我真的想盡可能少編寫代碼,但也可以在綁定時操作XML結構。儘可能少編寫代碼並不是因爲我很懶惰,而是真的認爲這是不必要的,並且增加了複雜性並需要更廣泛的測試。簡單,優雅的代碼讓我開心。但是,答案爲+1,因爲我不知道您提到的鏈接或工具。 – andyb 2011-03-17 11:54:05

+1

@andyb:也許你可以先自動化,然後編輯生成的文件。 – eee 2011-03-17 14:27:36

相關問題