2013-07-04 53 views
2

我有一個很深的XML結構,其中包含很多無意義的包裝,我將其映射到單個Java類。使用@XmlPath映射簡單的數據類型是在公園散步,但是當涉及到實際需要他們自己的類的類型時,我不太清楚該怎麼做,特別是當這些類型應該放在列表中時。使用帶jaxb/MOXy的@XmlPath映射覆雜類型

我有問題將以下示例中的所有element類型映射到我的Element類。由於elements包裝駐留在使用@XmlPath映射的資源中,因此我無法使用@XmlElementWrapper,否則這將是我通常會這樣做的方式。

實施例的XML結構

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<s:root xsi:schemaLocation="http://www.example.eu/test ResourceSchema.xsd" xmlns:s="http://www.example.eu/test" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> 
    <s:resource> 
     <s:information> 
      <s:date>2013-07-04</s:date> 
      <s:name>This example does not work</s:name> 
     </s:information> 
     <s:elements> 
      <s:refobj> 
       <s:id>1</s:id> 
       <s:source>First Source</s:source> 
      </s:refobj> 
      <s:refobj> 
       <s:id>2</s:id> 
       <s:source>Second Source</s:source> 
      </s:refobj> 
      <s:refobj> 
       <s:id>5</s:id> 
       <s:source>Fifth Source</s:source> 
      </s:refobj> 
     </s:elements> 
    </s:resource> 
</s:root> 

Root.java

@XmlRootElement(name = "root") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Root { 

    @XmlPath("resource/information/date/text()") 
    private String date; 

    @XmlPath("s:resource/s:information/s:name/text()") 
    private String name; 

    @XmlPath("resource/elements/refobj") 
    private List<RefObj> refObjs; 

    public String getDate() { 
     return date; 
    } 

    public void setDate(String date) { 
     this.date = date; 
    } 

    public String getName() { 
     return name; 
    } 

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

} 

RefObj.java

@XmlRootElement(name = "refobj") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class RefObj { 

    @XmlElement(name = "id") 
    private int id; 

    @XmlElement(name = "source") 
    private String source; 

    public int getId() { 
     return id; 
    } 

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

    public String getSource() { 
     return source; 
    } 

    public void setSource(String source) { 
     this.source = source; 
    } 

} 

的Marshaller/Unmarshaller的

public static void main(String[] args) { 
    String xml = getXML(); 

    Root root = null; 
    try { 
     JAXBContext context = JAXBContext.newInstance(Root.class); 

     Unmarshaller unmarshaller = context.createUnmarshaller(); 

     StringReader stringReader = new StringReader(xml); 

     root = (Root) unmarshaller.unmarshal(stringReader); 
    } catch (Exception ex) { 
     System.err.println("Failed to unmarshal XML!"); 
    } 

    try { 
     JAXBContext context = JAXBContext.newInstance(Root.class); 
     Marshaller marshaller = context.createMarshaller(); 

     marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8"); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 
     marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://www.example.eu/test ResourceSchema.xsd"); 

     StringWriter stringWriter = new StringWriter(); 
     marshaller.marshal(root, stringWriter); 

     System.out.println(new String(stringWriter.toString().getBytes(Charset.forName("UTF-8")))); 
    } catch (Exception ex) { 
     System.err.println("Failed to marshal object!"); 
    } 

} 

package-info.java

@XmlSchema(
     namespace = "http://www.example.eu/test", 
     attributeFormDefault = XmlNsForm.QUALIFIED, 
     elementFormDefault = XmlNsForm.QUALIFIED, 
     xmlns = { 
    @XmlNs(
      prefix = "s", 
      namespaceURI = "http://www.example.eu/test") 
}, 
     location = "http://www.example.eu/test ResourceSchema.xsd") 
package se.example.mavenproject1; 

import javax.xml.bind.annotation.XmlNs; 
import javax.xml.bind.annotation.XmlNsForm; 
import javax.xml.bind.annotation.XmlSchema; 

我可以執行應用程序,但是當我解組/編組的XML內容沒有元素被映射,而不是我得到一個僅包含信息的XML表示。

更新

張貼前面的例子中,我意識到,它實際工作按計劃,這讓我更糊塗了。雖然我試圖在我的生產代碼中複製(以前的)工作示例但沒有取得任何成功,儘管我已經設法實際將我遇到的問題引入示例代碼中。因爲我需要爲出現的問題添加命名空間,所以我假設它與命名約定和X(ml)路徑有關。

我也添加了package-info.java和我在使用這些對象時使用的編組器/解組器。由於jaxb.properties不包含任何令人興奮的東西,所以我將它遺漏了。

回答

3

當我運行你的例子一切工作正常。由於您的真實模型可能具有get/set方法,因此您需要確保將@XmlAccessorType(XmlAccessType.FIELD)添加到您的類中,否則MOXy(或任何其他JAXB impl)也會將相應的屬性視爲映射(請參閱:http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html)。

import java.util.List; 
import javax.xml.bind.annotation.*; 
import org.eclipse.persistence.oxm.annotations.XmlPath; 

@XmlRootElement(name = "root") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Root { 

    @XmlPath("resource/information/date/text()") 
    private String date; 

    @XmlPath("resource/information/name/text()") 
    private String name; 

    @XmlPath("resource/elements/element") 
    private List<Element> elements; 

} 

你還需要確保你有一個jaxb.properties文件在同一封裝與下面進入指定莫西爲您的JAXB提供您的域模型(見:http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html)。

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory 

更多信息


更新#1

當你的文檔是南espace限定@XmlPath註釋需要將其考慮在內。路徑中的節點可以根據@XmlSchema註釋進行限定。

包信息

在你package-info類前綴s被分配到命名空間URI http://www.example.eu/test

@XmlSchema(
     namespace = "http://www.example.eu/test", 
     attributeFormDefault = XmlNsForm.QUALIFIED, 
     elementFormDefault = XmlNsForm.QUALIFIED, 
     xmlns = { 
    @XmlNs(
      prefix = "s", 
      namespaceURI = "http://www.example.eu/test") 
}, 
     location = "http://www.example.eu/test ResourceSchema.xsd") 
package se.example.mavenproject1; 

import javax.xml.bind.annotation.XmlNs; 
import javax.xml.bind.annotation.XmlNsForm; 
import javax.xml.bind.annotation.XmlSchema; 

這意味着,與http://www.example.eu/test空間限定的節點應該在@XmlPath標註前綴s

import java.util.List; 
import javax.xml.bind.annotation.*; 
import org.eclipse.persistence.oxm.annotations.XmlPath; 

@XmlRootElement(name = "root") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Root { 

    @XmlPath("s:resource/s:information/s:date/text()") 
    private String date; 

    @XmlPath("s:resource/s:information/s:name/text()") 
    private String name; 

    @XmlPath("s:resource/s:elements/s:element") 
    private List<Element> elements; 

} 

更新#2

所以它好像命名空間需要在@XmlPath 中指定映射時,一個複雜的對象的路徑,但是可以跳過當 將路徑映射到簡單對象(如字符串或整數)時。

這是一個錯誤。對於簡單對象,您應該使用與複雜對象相同的方式來命名空間@XmlPath(請參閱UPDATE#1)。今天正確的映射工作,我們將修復以下錯誤,以便不正確的映射行爲正確。您可以使用下面的鏈接來追蹤在這個問題上我們的進展:

+0

感謝您的迴應,當我實際上爲示例代碼創建項目時,我寫的代碼也適用於我。現在我已經設法通過向xml添加名稱空間來重新創建問題,我還對示例中類的命名做了一些更改,以便更好地類似實際(巨大)xml中的命名圖書館內有任何魔法多元化。 –

+0

@JakobPogulis - 我更新了地址名稱空間限定的答案。 –

2

所以它好像命名空間需要映射路徑複雜對象時,在@XmlPath指定,但在將路徑映射到簡單對象(例如Stringinteger)時可以跳過。

原件,不正確的代碼

@XmlPath("resource/elements/refobj") 
private List<RefObj> refObjs; 

更新,工作代碼

@XmlPath("s:resource/s:elements/s:refobj") 
private List<RefObj> refObjs; 

當添加的命名空間前綴@XmlPath所有的對象都如預期映射。如果有人可以證實這一點,並可能解釋爲什麼,我會很高興知道這種行爲的原因。

+1

您應該爲命名空間限定簡單映射和複雜映射的「@ XmlPath」。目前有一個錯誤導致你的簡單案例工作。我更新了更多詳細信息的答案:http://stackoverflow.com/a/17466836/383861 –

+0

XMLDirectMapping/XMLCompositeDirectCollectionMapping的XPath無效。 XPath必須包含用於屬性的@符號或用於文本節點的/ text()結尾。例如:「@name」或「name/text()」。我曾經使用過像.................. @ XmlPath(「subject/title」) private列表 title; – Yogesh