简体   繁体   English

将没有对象列表的对象的xml列表解编为Java列表

[英]Unmarshall xml list of objects to java list without class list

With JAXB, I would like to unmarshall an xml document that contains several serialized objects like this : 使用JAXB,我想解组一个包含几个序列化对象的xml文档,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<Users>
<User>
    <firstName>first name value 1</firstName>
    <lastName>last name value 1</lastName>
    <account>
        <expiration>expire 1</expiration>
        <login>login 1</login>
    </account>
</User>
<User>
    <firstName>first name value 2</firstName>
    <lastName>last name value 2</lastName>
    <account>
        <expiration>expire 2</expiration>
        <login>login 2</login>
    </account>
</User>
...
</Users>

The fact is that I don't want to create a new class named "Users" for instance and which contains a list of User's elements (with @XmlWrapper annotation). 事实是,我不想创建一个名为“ Users”的新类,该类包含一个User元素列表(带有@XmlWrapper批注)。

Here is my java object that I have to translate to xml : 这是我必须转换为xml的java对象:

@Entity
@Table(name="USERS")
@XmlRootElement(name="User")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    private String firstName;
    private String lastName;

    @OneToOne(cascade={CascadeType.REMOVE}, mappedBy="user")
    private Account account;

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

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

    @XmlElement
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @XmlElement
    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @XmlInverseReference(mappedBy="user")
    @XmlElement
    public Account getAccount() {
        return account;
    }

    public void setAccount(Account account) {
        this.account = account;
    }
}

And for the moment I can juste unmarshall just one xml to an User java object. 目前,我只可以将一个xml解组到User java对象。 Like this : 像这样 :

@Test
    public void test2() {
        try {
            JAXBContext jc = JAXBContext.newInstance(User.class);
            Unmarshaller u = jc.createUnmarshaller();

            File f = new File("user.xml");
            User element = (User) u.unmarshal(f);

            System.out.println(
                    element.getAccount().getLogin()
                    );

        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }

And I would like to get a User java list instances instead of just a User instance. 我想获得一个User java列表实例,而不仅仅是一个User实例。 Like this for instance : 例如这样:

List<User> elements = (List<User>) u.unmarshal(f);

I hope this is possible and I would like to know how ;) 我希望这是可能的,我想知道如何;)


Thanks a lot for your reply Blaise. 非常感谢您的答复布莱斯。

I tried to make as you did but I've got error : 我尝试像您一样做,但是出现错误:

java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to com.thales.momoko.ws.model.User java.lang.ClassCastException:com.sun.org.apache.xerces.internal.dom.ElementNSImpl无法转换为com.thales.momoko.ws.model.User

Here are some relevant part of my code : 这是我的代码的一些相关部分:

public class Tools<T> {

public List<T> getItems(Class<T> entityClass, String xmlLocation) {
    try {
        JAXBContext jc = JAXBContext.newInstance(Wrapper.class, entityClass.getClass());
        Unmarshaller unmarshaller = jc.createUnmarshaller();

        BufferedReader br = new BufferedReader(
                new InputStreamReader(
                this.getClass().getClassLoader().getResourceAsStream(xmlLocation)));

        System.out.println(br.readLine());

        Wrapper<T> wrapper = (Wrapper<T>) unmarshaller.unmarshal(new StreamSource(br), Wrapper.class).getValue();

        System.out.println(wrapper);

        return wrapper.getItems();

    } catch (JAXBException ex) {
        Logger.getLogger(Tools.class.getName()).log(Level.SEVERE, null, ex);
    } catch (IOException ex) {
        Logger.getLogger(Tools.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}
}

The first println works fine because it displays the first line of the xml file : 第一个println可以正常工作,因为它显示xml文件的第一行:

<?xml version=....>

The second println shows a problem with the unmarshalling : 第二个println显示解组问题:

Wrapper{items=[[user: null], [user: null], [user: null], [user: null], [user: null], [user: null], [user: null], [user: null], [user: null], [user: null], [user: null], [user: null], [user: null], [user: null], [user: null]]} 包装器{items = [[用户:空],[用户:空],[用户:空],[用户:空],[用户:空],[用户:空],[用户:空],[用户:空],[用户:空],[用户:空],[用户:空],[用户:空],[用户:空],[用户:空],[用户:空]]}

The wrapper : 包装器:

public class Wrapper<T> {

private List<T> items = new ArrayList<>();

@XmlAnyElement(lax=true)
public List<T> getItems() {
    return items;
}

@Override
public String toString() {
    return "Wrapper{" + "items=" + items + '}';
}
}

And finally the call of the unmarshaller : 最后是解组员的电话:

@PostConstruct
public void init() {
   this.entityClass = User.class;
    for (User user : (List<User>) new Tools<User>().getItems(User.class, "user.xml"))
        System.out.println(user.getFirstName());
}

It gives me an error at the line with the "for" instruction. 它在“ for”指令的行中给我一个错误。

Have you got an idea about this error ? 你有关于这个错误的主意吗?

Thanks another time ! 再次感谢您!

EDIT 编辑

Solution : 解决方案:

public class Tools<T> {

public static <T> List<T> getItems(Class<T> entityClass, String xmlLocation) {
    try {
        JAXBContext jc;
        synchronized (JAXBContext.class) {
            jc = JAXBContext.newInstance(Wrapper.class, entityClass);
        }

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        BufferedReader br = new BufferedReader(
                new InputStreamReader(
                Import.class.getClassLoader().getResourceAsStream(xmlLocation)));

        Wrapper<T> wrapper = (Wrapper<T>) unmarshaller.unmarshal(new StreamSource(br), Wrapper.class).getValue();

        return wrapper.getItems();

    } catch (JAXBException ex) {
        Logger.getLogger(Import.class.getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}
}

The call : 电话:

@PostConstruct
public void init() {
   this.entityClass = User.class;
    for (User user : (List<User>) Tools.getItems(User.class, "user.xml"))
        em.persist(user);
}

You could use JAXB with StAX to do the following: 您可以将JAXB与StAX结合使用来执行以下操作:

import java.util.*;
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;

public class Demo {

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

        XMLInputFactory xif = XMLInputFactory.newFactory();
        StreamSource xml = new StreamSource("src/forum17047306/input.xml");
        XMLStreamReader xsr = xif.createXMLStreamReader(xml);

        List<User> users = new ArrayList<User>();
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        while(xsr.getEventType() != XMLStreamReader.END_DOCUMENT) {
            if(xsr.isStartElement() && "User".equals(xsr.getLocalName())) {
                User user = (User) unmarshaller.unmarshal(xsr);
                users.add(user);
            }
            xsr.next();
        }
        System.out.println(users.size());
    }

}

UPDATE UPDATE

You may prefer the following approach for handling lists using a generic list wrapper object: 您可能更喜欢以下使用通用列表包装器对象处理列表的方法:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM