【问题标题】:Java feed XML with namespace bind using JAXB使用 JAXB 绑定命名空间的 Java 提要 XML
【发布时间】:2019-11-07 04:50:45
【问题描述】:

我正在尝试在下面的示例 xml 文件中绑定电子邮件元素,但无法正确绑定它。我要空了。

示例 XML

<feed xmlns="http://www.w3.org/2005/Atom" xmlns:api="http://www.example.com/publications/api">
<api:schema-version>5.3</api:schema-version>
<category scheme="http://www.example.com/publications/atom/feeds/" term="item" label="Item" />
<id>tag:elements@abcd,5.15:/proted-api/v5.5/feeds/users/12312</id>
  <entry>
   <id>tag:elements@abcd,5.15:/proted-api/v5.5/users/12312</id>
   <category scheme="http://www.example.com/publications/atom/entries/" term="item" label="Item" />
   <content type="xhtml">
   <api:object category="user" id="12312" proprietary-id="abcd123">
      <api:last-name>Jo</api:last-name>
      <api:first-name>Deo</api:first-name>
      <api:email-address>jode@example.com</api:email-address>
    </api:object>
  </entry>
</feed>

Feed.java

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Feed {

@XmlElement(name="entry")
private Entry entry;

public Entry getEntry() {
    return entry;
}

public void setEntry(Entry entry) {
    this.entry = entry;
}
}

Entry.java

@XmlAccessorType(XmlAccessType.FIELD)
public class Entry {

@XmlElement(name="object", namespace = "http://www.example.com/publications/api")
private Object object;

public Object getObject() {
    return object;
}

public void setObject(Object object) {
    this.object = object;
}
}

Object.java

@XmlAccessorType(XmlAccessType.FIELD)
public class Object {

@XmlElement(name="email-address",namespace = "http://www.example.com/publications/api")
private String email;

public String getEmail() {
    return email;
}

public void setEmail(String email) {
    this.email = email;
}

}

测试代码

//code here to read
Feed feed = response.getBody();
System.out.println("object email = " +feed.getEntry().getObject().getEmail());

完整的 XML 文件

    <feed xmlns="http://www.w3.org/2005/Atom" xmlns:api="http://www.example.com/publications/api">
    <api:schema-version>5.5</api:schema-version>
    <category scheme="http://www.example.com/publications/atom/feeds/" term="item" label="Item" />
    <id>tag:elements@Test,5.15:/secure-api/v5.5/feeds/users/676</id>
    <updated>2019-06-17T09:04:39.87+01:00</updated>
    <generator uri="https://test.com/" version="5.15">Example Elements</generator>
    <icon>https://test.com:8091/secure-api/v5.5/Example.ico</icon>
    <rights>This data is the property of the Organisation, and can only be used with permission.</rights>
    <subtitle>This feed represents a single user.</subtitle>
    <link type="application/atom+xml" rel="self" href="https://test.com:8091/secure-api/v5.5/users/676" />
    <title>John deo</title>
    <author>
    <name>Example Elements at Test PROD</name>
    </author>
    <entry>
    <id>tag:elements@Test,5.15:/secure-api/v5.5/users/676</id>
    <category scheme="http://www.example.com/publications/atom/entries/" term="item" label="Item" />
    <updated>2019-06-17T09:04:39.87+01:00</updated>
    <link type="application/atom+xml" rel="alternate" href="https://test.com:8091/secure-api/v5.5/users/676" />
    <title>John deo</title>
    <content type="xhtml">
    <div xmlns="http://www.w3.org/1999/xhtml">
    <p>User</p>
    <a href="https://test.com:8091/secure-api/v5.5/users/676/photo?type=profile">Photo</a>
    <p>
    <a href="https://test.com:8091/secure-api/v5.5/users/676/relationships">Relationships</a>
    with other data
    </p>
    </div>
    </content>
    <api:object category="user" id="676" proprietary-id="abcd1247" username="abcd1247" last-affected-when="2019-06-17T09:04:39.87+01:00" last-modified-when="2018-11-29T10:28:43.403+00:00" href="https://test.com:8091/secure-api/v5.5/users/676" created-when="2010-05-04T09:49:46.507+01:00" type-id="1" type="person">
    <!-- User type 1 is "person" -->
    <api:ever-approved>true</api:ever-approved>
    <api:is-public>false</api:is-public>
    <api:is-login-allowed>true</api:is-login-allowed>
    <api:title>Prof</api:title>
    <api:initials>Jo</api:initials>
    <api:last-name>John</api:last-name>
    <api:first-name>Deo</api:first-name>
    <api:email-address>John.deo@example.com</api:email-address>
    <api:known-as>Liz</api:known-as>
    <api:primary-group-descriptor>ABCS</api:primary-group-descriptor>
    <api:arrive-date>2009-10-05</api:arrive-date>
    <api:user-search-settings>
    <api:default>
    </api:default>
    </api:user-search-settings>
    <api:records>
    <api:record format="native" id="3245433412" source-id="1" source-name="manual" source-display-name="Manual">
    <api:native />
    </api:record>
    </api:records>
    <api:fields />
    <api:relationships href="https://test.com:8091/secure-api/v5.5/users/676/relationships" />
    <api:user-identifier-associations user-id="676" proprietary-id="abcd1247" username="abcd1247">
    </api:user-identifier-associations>
    </api:object>
    </entry>
    </feed>

【问题讨论】:

    标签: java spring xml-parsing jaxb resttemplate


    【解决方案1】:

    问题在于您的 POJO 结构与 xml 不匹配(正如我们最后发现的那样,RestTemplate 没有使用 JAXB 注释,请参阅下面的编辑 4)。

    让我们解决这个问题,以便您能够正确解组。

    大部分字段都使用http://www.w3.org/2005/Atom 命名空间。我们将使用 package-info 而不是在每个元素中添加它。因此,在您的类的包中创建一个文件 package-info.java,其中包含以下内容:

    @javax.xml.bind.annotation.XmlSchema(namespace = "http://www.w3.org/2005/Atom", elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
    package the.package.of.your.classes;
    

    然后让我们修复提要。您的 xml 包含您的类没有的元素,这是一个问题,因为它遇到了意外的元素。饲料将是:

    @XmlRootElement
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Feed {
    
        @XmlElement(name="schema-version", namespace = "http://www.example.com/publications/api")
        private String schemaVersion;
        @XmlElement
        private String category;
        @XmlElement
        private String id;
    
        @XmlElement(name="entry")
        private Entry entry;
    
    }
    

    请注意,schema-version 的命名空间与我们在 package-info 中的命名空间不同,因此我们在注释中明确覆盖它。

    现在,这被简化了。例如,类别具有 xml 属性,例如术语和标签。如果您想获取此信息,您应该创建一个类来表示类别而不是字符串。但如果你不这样做,像这样的 Feed 允许我们继续解组。接下来是条目:

    @XmlAccessorType(XmlAccessType.FIELD)
    public class Entry {
    
    
        @XmlElement
        private String id;
        @XmlElement
        private String category;
        @XmlElement
        private String content;
    
        @XmlElement(name="object", namespace = "http://www.example.com/publications/api")
        private ApiObject object;
    
    }
    

    再次使用字符串忽略属性。我将 Object 更改为一个名为 ApiObject 的类,它的结构与 xml 匹配。它看起来像这样:

    @XmlAccessorType(XmlAccessType.FIELD)
    public class ApiObject {
    
        @XmlElement(name= "last-name", namespace = "http://www.example.com/publications/api")
        private String lastName;
        @XmlElement(name = "first-name", namespace = "http://www.example.com/publications/api")
        private String firstName;
        @XmlElement(name = "email-address", namespace = "http://www.example.com/publications/api")
        private String emailAddress;
    }
    

    最后一件事,xml。它不是有效的 xml,粘贴的示例中未关闭标签“内容”。我将其更改为 &lt;content type="xhtml" /&gt; 以测试我的解决方案。

    确实它可以正常工作并且可以很好地解组:)

    编辑回复:

    对于问题 1,您将在现在不直接指定命名空间的每个元素中添加命名空间。

    对于问题 2,您可以使用此处提出的内容忽略未知元素:JAXB Ignore 'extra' elements from Response XML

    Feed 示例如下所示:

    @XmlRootElement(namespace = "http://www.w3.org/2005/Atom")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Feed {
    
        @XmlAnyElement(lax = true)
        private List<Object> anything;
    
        @XmlElement(name="entry", namespace = "http://www.w3.org/2005/Atom")
        private Entry entry;
    
    
    }
    

    编辑 2:

    获取您尝试解组的 xml 并执行以下操作:

    try {
                File file = new File("/path/to/your/file.xml");
                JAXBContext jaxbContext = JAXBContext.newInstance(YouRootClass.class);
    
                Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
                jaxbUnmarshaller.setEventHandler(
                        new ValidationEventHandler() {
                            public boolean handleEvent(ValidationEvent event ) {
                                throw new RuntimeException(event.getMessage(),
                                        event.getLinkedException());
                            }
                        });
                YouRootClass pojo = (YouRootClass) jaxbUnmarshaller.unmarshal(file);
            } catch (JAXBException e) {
                e.printStackTrace();
            }
    

    您的 xml 和 POJO 之间的任何不匹配都将作为异常抛出,您可以按照自己的方式进行纠正

    编辑 3:

    饲料

    @XmlRootElement(namespace = "http://www.w3.org/2005/Atom")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Feed {
    
        @XmlAnyElement(lax = true)
        private List<Object> anything;
    
        @XmlElement(name="entry", namespace = "http://www.w3.org/2005/Atom")
        private Entry entry;
    
    }
    

    进入

    @XmlAccessorType(XmlAccessType.FIELD)
    public class Entry {
    
    
        @XmlAnyElement(lax = true)
        private List<Object> anything;
    
        @XmlElement(name="object", namespace = "http://www.example.com/publications/api")
        private ApiObject object;
    
    }
    

    ApiObject:

    @XmlAccessorType(XmlAccessType.FIELD)
    public class ApiObject {
    
        @XmlAnyElement(lax = true)
        private List<Object> anything;
    
        @XmlElement(name= "last-name", namespace = "http://www.example.com/publications/api")
        private String lastName;
        @XmlElement(name = "first-name", namespace = "http://www.example.com/publications/api")
        private String firstName;
        @XmlElement(name = "email-address", namespace = "http://www.example.com/publications/api")
        private String emailAddress;
    }
    

    编辑 4:

    在您的 github 项目中,创建 RestTemplate 后的类 Test(第 31 行)添加:

    List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
    Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter = new Jaxb2RootElementHttpMessageConverter();
    messageConverters.add(jaxb2RootElementHttpMessageConverter);
    rest.setMessageConverters(messageConverters);
    

    【讨论】:

    • 谢谢你,要问两件事。第一个我如何在不使用包文件的情况下更改代码。 2,在 Feed 类 schemaVersion、category、id 中我必须包含吗?我提供的文件是实际文件的缩小版本.. 我有大约 50 个元素,所以我必须将所有 50 个元素添加到 Feed 类吗?
    • @VK321 我现在不在我的机器上。稍后将粘贴我如何解组 xml,以便您尝试。你也可以提出你的问题,你是如何解组的?你在xml中解决了这个问题吗?粘贴完整的 xml 以便我可以尝试使用您的相同输入?
    • @VK321 我将在答案中提供一种使用 xml 运行解组的方法,看看是什么导致了问题。
    • Mart,非常感谢您抽出宝贵时间。我测试了我现在没有收到任何错误,但仍然是空值。如果我上传完整的文件,你能帮我吗?
    • @VK321 是的,请这样做
    猜你喜欢
    • 2020-10-11
    • 2018-11-29
    • 2016-09-21
    • 1970-01-01
    • 2014-11-28
    • 2012-11-27
    • 1970-01-01
    • 2013-12-06
    • 1970-01-01
    相关资源
    最近更新 更多