2

使用 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>

事实是,我不想创建一个名为“Users”的新类,它包含一个用户元素列表(带有@XmlWrapper 注释)。

这是我必须转换为 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;
    }
}

目前我可以只将一个 xml 解组到一个用户 java 对象。像这样 :

@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();
        }
    }

我想获得一个用户 java 列表实例,而不仅仅是一个用户实例。例如像这样:

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

我希望这是可能的,我想知道如何;)


非常感谢您的回复布莱斯。

我试着像你一样做,但我有错误:

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

以下是我的代码的一些相关部分:

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;
}
}

第一个 println 工作正常,因为它显示了 xml 文件的第一行:

<?xml version=....>

第二个 println 显示了解组的问题:

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

包装:

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 + '}';
}
}

最后是 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());
}

它在“for”指令的行中给了我一个错误。

你对这个错误有什么想法吗?

再次感谢!

编辑

解决方案 :

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;
}
}

来电:

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

1 回答 1

2

您可以将 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());
    }

}

更新

您可能更喜欢以下使用通用列表包装对象处理列表的方法:

于 2013-06-13T16:58:22.527 回答