JAXB Unmarshalling:对象列表 [英] JAXB Unmarshalling: List of objects

查看:112
本文介绍了JAXB Unmarshalling:对象列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有

@XmlRootElement(namespace = "http://www.w3.org/2005/Atom", name = "content")
@XmlType(name = "course")
public class Course implements Resource

...

@XmlElementWrapper(name="subcourses")
@XmlElement(name="course")
List<Xlink> subcourses;         //!?

和Xlink类,在内联变量中工作正常。

and Xlink class, which works fine in inline variable.

public class Xlink
{
    private String href;
    private String value;

    @XmlAttribute(namespace = "http://www.w3.org/1999/xlink")
    public String getHref()
    {
        return href;
    }

    public void setHref(String href)
    {
        this.href = href;
    }

    @XmlValue
    public String getValue()
    {
        return value;
    }

    public void setValue(String value)
    {
        this.value = value;
    }
}

对于

<atom:content atom:type="xml" xsi:type="course">
...
   <subcourses>
      <course xlink:href="course1">Some course</course>
      <course xlink:href="course2">other course</course>

并且子主义拒绝被解组(没有任何异常被抛出)。

And subcourses refuses to be unmarshalled (without any exception being thrown).

注意:遗憾的是MOXy不是一个选项。

Note: MOXy is unfortunately not an option.

编辑:新编组对象

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:content xmlns:ns2="http://www.w3.org/1999/xlink" xmlns:ns3="http://www.w3.org/2005/Atom">
    <code>SOME CODE</code>
    <name>name</name>
    <subcourses>
        <course ns2:href="Some href">some value</course>
        <course ns2:href="sdsdg">sdfhdfhdhdh</course>
    </subcourses>
</ns3:content>

Edit2:在对一个测试对象进行解组和编组的一些实验后,我发现我需要定义xmlns内容标题中的命名空间,以匹配 xlink:href = ,如 xmlns:xlink =http://www.w3.org/1999/ xlink问题是我从一个由resteasy解析出的包装类中获取了Course元素。因此,结果类不会遗留名称空间信息。

after some experimentation with unmarshalling and marshalling a test object I have discovered that I need to define xmlns namespace in the header of the content to match xlink:href= like xmlns:xlink="http://www.w3.org/1999/xlink" the problem is that I am getting the Course element from inside a wrapper class that is parsed out by resteasy. Thus the resulting class does not carry over the namespace information.

我不知何故需要强制JAXB理解 xmlns:xlink =http:/ /www.w3.org/1999/xlink适用于课程元素,但在谷歌一小时后我不知所措。

I somehow need to force JAXB to understand that xmlns:xlink="http://www.w3.org/1999/xlink" applies to the course elements, but after an hour of google I am at a loss.

Edit3:我从

https://github.com/jirutka/atom-jaxb/blob/master/src/main/java/cz/jirutka/atom /jaxb/Entry.java

在服务器对应项上使用。这又是

which is used on the server counterpart. Which in turn is a part of

https://github.com/jirutka/atom-jaxb/blob/master/src/main/java/cz/jirutka/atom/jaxb /Feed.java

我的解组代码的相关部分是:

Relevant parts of my unmarshalling code are:

Feed f = r.readEntity(Feed.class);
out.addAll(unmarshaller.Unmarshal(f.getEntries(), clazz));

其中 r javax.ws.rs.core.Response 。并且unmarshaller

where r is a javax.ws.rs.core.Response. And the unmarshaller

public List<T> Unmarshal(List<Entry> entries, Class clazz)
{
    List<T> out = new ArrayList<T>();
    T instance;
    for (Entry e : entries)
    {
        try
        {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller unmarsh = context.createUnmarshaller();
            instance = (T) unmarsh.unmarshal((Node) e.getContent());

由于这是我第一次使用这项技术,这个代码完全有可能是'wtf' 。

Since this is my first tangle with this technology, it is entirely possible that this code is 'wtf'.

推荐答案

当您注释字段(实例变量)时,请务必放入 @XmlAccessorType(XmlAccessType。 FIELD)上课。

When you annotate the field (instance variable) be sure to put @XmlAccessorType(XmlAccessType.FIELD) on your class.

import java.util.List;
import javax.xml.bind.annotation.*;

@XmlRootElement(namespace = "http://www.w3.org/2005/Atom", name = "content")
@XmlAccessorType(XmlAccessType.FIELD)
public class Course implements Resource {

    @XmlElementWrapper(name = "subcourses")
    @XmlElement(name = "course")
    List<Xlink> subcourses;

}

然后确保您的XML输入正确地进行了命名空间限定。您的输入文档应如下所示:

Then make sure your XML input is correctly namespace qualified. Your input document should look something like the following:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<atom:content xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:atom="http://www.w3.org/2005/Atom">
    <code>SOME CODE</code>
    <name>name</name>
    <subcourses>
        <course xlink:href="Some href">some value</course>
        <course xlink:href="sdsdg">sdfhdfhdhdh</course>
    </subcourses>
</atom:content>

使用我更新的课程课程,您的 Xlink 类和一个正确的命名空间限定XML文档,下面的演示代码对我来说非常合适。

With my updated Course class, your Xlink class and a properly namespace qualified XML document the following demo code worked perfectly for me.

import java.io.File;
import javax.xml.bind.*;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum17766166/input.xml");
        Course course = (Course) unmarshaller.unmarshal(xml);

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

}






更新#1


编辑2:经过一些实验,解组和编组
测试对象我发现我需要在
中定义xmlns命名空间内容的标题以匹配xlink:href = like
xmlns:xlink =http://www.w3.org/1999/ xlink问题是我是
从一个包装类中获取Course元素,该类通过resteasy解析为
。因此,结果类不会带来
命名空间信息。

after some experimentation with unmarshalling and marshalling a test object I have discovered that I need to define xmlns namespace in the header of the content to match xlink:href= like xmlns:xlink="http://www.w3.org/1999/xlink" the problem is that I am getting the Course element from inside a wrapper class that is parsed out by resteasy. Thus the resulting class does not carry over the namespace information.

解决问题的最佳位置是提取你想要解散的片段。以下是您可以使用StAX的策略。

The best place to fix your issue is where you extract the fragment you wish to unmarhal. Below is a strategy you can use with StAX.

input.xml

input.xml

下面是一个示例XML文档,其中命名空间信息定义在您要解组的片段上方。

Below is a sample XML document where the namespace information is defined above the fragment you wish to unmarshal.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:atom="http://www.w3.org/2005/Atom">
    <bar>
        <atom:content>
            <code>SOME CODE</code>
            <name>name</name>
            <subcourses>
                <course xlink:href="Some href">some value</course>
                <course xlink:href="sdsdg">sdfhdfhdhdh</course>
            </subcourses>
        </atom:content>
    </bar>
</foo>

演示

Demo

下面我们将使用StAX XMLStreamReader 导航到目标片段。我们将让我们的JAXB实现解组这个片段。这样就可以保留所有命名空间信息。

Below we will use a StAX XMLStreamReader to navigate to the target fragment. We will have our JAXB implementation unmarshal this fragment. This way all the namespace information is preserved.

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(Course.class);

        XMLInputFactory xif = XMLInputFactory.newFactory();
        StreamSource source = new StreamSource("src/forum17766166/input.xml");
        XMLStreamReader xsr = xif.createXMLStreamReader(source);
        while(xsr.hasNext()) {
            if(xsr.isStartElement() && "content".equals(xsr.getLocalName())) {
                break;
            }
            xsr.next();
        }

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Course course = (Course) unmarshaller.unmarshal(xsr);

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

}

输出

Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns3:content xmlns:ns2="http://www.w3.org/1999/xlink" xmlns:ns3="http://www.w3.org/2005/Atom">
    <subcourses>
        <course ns2:href="Some href">some value</course>
        <course ns2:href="sdsdg">sdfhdfhdhdh</course>
    </subcourses>
</ns3:content>






UPDATE#2

如果无法按照UPDATE#1中的描述生成更好的XML片段,下面是如何修复当前的XML片段。

If you can't produce a better XML fragment as described in UPDATE #1, below is how you could fix the XML fragment you currently have.

NamespaceFilter

NamespaceFilter

您可以使用SAX XMLFilter 来修复XML文档。

You could use a SAX XMLFilter to fix up your XML document.

import org.xml.sax.*;
import org.xml.sax.helpers.*;

public class NamespaceFilter extends XMLFilterImpl {

    private static final String ATOM_URI = "http://www.w3.org/2005/Atom";
    private static final String XLINK_URI = "http://www.w3.org/1999/xlink";

    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes atts) throws SAXException {
        if("atom:content".equals(qName)) {
            super.startElement(ATOM_URI, "content", qName, atts);
        } else if("course".equals(qName))  {
            AttributesImpl modifiedAtts = new AttributesImpl();
            modifiedAtts.addAttribute(XLINK_URI, "href", "xlink:href", null, atts.getValue(0));
            super.startElement(uri, localName, qName, modifiedAtts);
        } else {
            super.startElement(uri, localName, qName, atts);
        }
    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        if("atom:content".equals(qName)) {
            super.endElement(ATOM_URI, "content", qName);
        } else {
            super.endElement(uri, localName, qName);
        }
    }

}

演示

Demo

以下是如何利用 XmlFilter 的方法JAXB:

Below is how you can leverage the XmlFilter with JAXB:

import javax.xml.bind.*;
import javax.xml.parsers.*;
import org.xml.sax.*;

public class Demo {

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

        // Create the XMLFilter
        XMLFilter filter = new NamespaceFilter();

        // Set the parent XMLReader on the XMLFilter
        SAXParserFactory spf = SAXParserFactory.newInstance();
        SAXParser sp = spf.newSAXParser();
        XMLReader xr = sp.getXMLReader();
        filter.setParent(xr);

        // Set UnmarshallerHandler as ContentHandler on XMLFilter
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        UnmarshallerHandler unmarshallerHandler = unmarshaller
                .getUnmarshallerHandler();
        filter.setContentHandler(unmarshallerHandler);

        // Parse the XML
        InputSource xml = new InputSource("src/forum17766166/input.xml");
        filter.parse(xml);
        Course course = (Course) unmarshallerHandler.getResult();

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

}

For更多信息

For More Information

  • http://blog.bdoughan.com/2012/11/applying-namespace-during-jaxb-unmarshal.html

更新#3

下面是示例代码的简化版本,其中一切正常。也许您的代码中有不同的内容可以帮助您找到。

Below is a simplified version of your example code where everything works. Maybe there is something different in your code it will help you find.

条目

import javax.xml.bind.annotation.*;

@XmlRootElement(namespace="http://www.w3.org/2005/Atom")
@XmlAccessorType(XmlAccessType.FIELD)
public class Entry<T> {

    @XmlElement(namespace = "http://www.w3.org/2005/Atom")
    @XmlSchemaType(name = "atomInlineOtherContent")
    private T content;

    public T getContent() {
        return content;
    }

}

input.xml

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<atom:entry xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:atom="http://www.w3.org/2005/Atom">
    <atom:content>
        <code>SOME CODE</code>
        <name>name</name>
        <subcourses>
            <course xlink:href="Some href">some value</course>
            <course xlink:href="sdsdg">sdfhdfhdhdh</course>
        </subcourses>
    </atom:content>
</atom:entry>

演示

import java.io.File;
import javax.xml.bind.*;
import org.w3c.dom.Node;

public class Demo {

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

        // Unmarshal Entry
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum17766166/input.xml");
        Entry entry = (Entry) unmarshaller.unmarshal(xml);

        // Unmarshal Course
        Node contentNode = (Node) entry.getContent();
        Course course = (Course) unmarshaller.unmarshal(contentNode);

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

}

输出

<?xml version="1.0" encoding="UTF-8"?>
<ns0:content xmlns:ns1="http://www.w3.org/1999/xlink" xmlns:ns0="http://www.w3.org/2005/Atom">
   <subcourses>
      <course ns1:href="Some href">some value</course>
      <course ns1:href="sdsdg">sdfhdfhdhdh</course>
   </subcourses>
</ns0:content>

这篇关于JAXB Unmarshalling:对象列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆