2011-05-19 18 views
6

我正在尝试将第三方XML负载解组到类中。问题是负载具有父/子关系,并且根节点,父节点和子节点都具有相同的元素名称。以下是有效负载的示例。如何使用错误的父/子模型解组xml消息

<?xml version="1.0" encoding="UTF-8"?> 
<Directory> 
    <id>2</id> 
    <name>Media</name> 
    <Directory> 
     <id>5</id> 
     <name>Default_Content</name> 
     <Directory> 
      <id>9</id> 
      <name>Images</name> 
     </Directory> 
     <Directory> 
      <id>8</id> 
      <name>Icons</name> 
     </Directory> 
     <Directory> 
      <id>6</id> 
      <name>Additional_Content</name> 
     </Directory> 
    </Directory> 
    <Directory> 
     <id>12</id> 
     <name>IC</name> 
    </Directory> 
</Directory> 

所以我想注释一个类,以便JAXB/JAX-RS可以解组成这个有用的东西。

我已经试过这样的事情

@XmlRootElement(name="Directory") 
public class Directory { 
    private int id; 
    private String name; 

    @XmlElement(name="Directory"); 
    private List<Directory> directories = new ArrayList<Directory>(); 
} 

但是,可以预见,它抛出一个IllegalAnnotationException因为有两个属性名称相同的。

任何想法,我该如何使用JAXB/JAX-RS干净地处理这个烂摊子,或者我应该只是解析它在我自己的?

回答

13

简答

唯一的例外是由于字段/属性的冲突。您可以注释属性(get方法)或设置你的类型如下注释:

@XmlAccessorType(XmlAccessType.FIELD) 
public class Directory { 
    ... 
} 

长的答案

JAXB的默认接入类型为PUBLIC_MEMBER这意味着JAXB将映射所有公共领域(实例变量)和属性(get/set方法)。

public class Foo { 

    private String bar; 

    public String getBar() { 
     return bar; 
    } 

    public void setBar(String bar) { 
     this.bar = bar; 
    } 

} 

如果您注释字段:

public class Foo { 

    @XmlAttribute 
    private String bar; 

    public String getBar() { 
     return bar; 
    } 

    public void setBar(String bar) { 
     this.bar = bar; 
    } 

} 

然后JAXB会认为它具有映射,并且抛出一个异常2个bar属性:

Exception in thread "main" com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions 
Class has two properties of the same name "bar" 
    this problem is related to the following location: 
     at public java.lang.String example.Foo.getBar() 
     at example.Foo 
    this problem is related to the following location: 
     at private java.lang.String example.Foo.bar 
     at example.Foo 

解决的办法是注释属性并将XmlAccessType类型设置为FIELD

@XmlAccessorType(XmlAccessType.FIELD) 
public class Foo { 

    @XmlAttribute 
    private String bar; 

    public String getBar() { 
     return bar; 
    } 

    public void setBar(String bar) { 
     this.bar = bar; 
    } 

} 

模型

目录

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

import javax.xml.bind.annotation.XmlAccessorType; 
import javax.xml.bind.annotation.XmlAccessType; 
import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement(name="Directory") 
@XmlAccessorType(XmlAccessType.FIELD) 
public class Directory { 
    private int id; 
    private String name; 

    @XmlElement(name="Directory") 
    private List<Directory> directories = new ArrayList<Directory>(); 

    public int getId() { 
     return id; 
    } 

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

    public String getName() { 
     return name; 
    } 

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

    public List<Directory> getDirectories() { 
     return directories; 
    } 

    public void setDirectories(List<Directory> directories) { 
     this.directories = directories; 
    } 

} 

演示

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

public class Demo { 

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

     Unmarshaller unmarshaller = jc.createUnmarshaller(); 
     Directory directory = (Directory) unmarshaller.unmarshal(new File("input.xml")); 

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

} 
+2

美女。像冠军一样工作。感谢您的快速,有用的回应。 – jspyeatt 2011-05-19 19:08:42

+1

+1。非常好的解释! – asgs 2011-05-25 18:51:52