我正在尝试利用 JAXB 将从 youtube rss feed 获得的 xml 元素转换为对象。我似乎遵循了我见过的大多数示例的结构,但仍然无法使其工作,因为提要中的列表似乎始终为空。有谁知道如何解决这一问题? 以下是我的类(class)供引用:
提要类别:
import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.*;
@XmlRootElement(
name = "feed",
namespace = "http://www.w3.org/2005/Atom"
)
@XmlAccessorType (XmlAccessType.FIELD)
public class feed {
@XmlElement(name = "entry")
private List<entry> entries;
public List<entry> getEntry() {
return this.entries;
}
public void setEntry(List<entry> entries) {
this.entries = entries;
}
}
入门级:
import javax.xml.bind.annotation.*;
import java.util.List;
@XmlRootElement(name = "entry")
@XmlAccessorType(XmlAccessType.FIELD)
public class entry {
private String title, name, id, published;
public void settitle(String title){this.title = title;}
public String gettitle(){return title;}
public void setname(String name){this.name = name;};
public String getname() {
return name;
}
public void setid(String id){this.id = id;}
public String getid() {
return id;
}
public void setpublished(String published){this.published = published;}
public String getpublished() {return published;}
public void PrintVideoInfo(){
System.out.println(gettitle());
System.out.println(getname());
System.out.println(getid());
System.out.println(getpublished());
System.out.println("-----------");
}
}
解码类:
import java.io.File;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class XMLtoObject {
public static void main(String[] args) {
try {
File file = new File("videos.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(feed.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
feed que= (feed) jaxbUnmarshaller.unmarshal(file);
for(entry ent:que.getEntry())
ent.PrintVideoInfo();
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
https://www.youtube.com/feeds/videos.xml?channel_id=UCBcRF18a7Qf58cCRy5xuWwQ这是正在使用的 xml。它保存为videos.xml,文件路径是正确的,只是为了保护隐私而没有完全包含在上面的代码片段中。任何帮助将不胜感激。
最佳答案
请让您的类名称遵循 Pascal 表示法 - 这样更容易阅读和理解,尤其是当有大量代码时。也许,您应该更多地关注您的代码风格。
您的
feed
类已正确注释,但为了让 JAXB 将 XML 解码为条目entry
类也应该正确注释。另请注意,您的字段名称与提供的 xml 文件中的标记名称不匹配(<name>
无法在<feed>
中直接访问)。 因此,添加注释和类以匹配 xml 文件结构。
更新1
我意识到我不太了解 xml 文档,所以我做了一些调查。
如果您完全熟悉 xml 命名空间,那么您可以跳过这一部分到序列化部分。否则,请继续阅读。
命名空间是一种将 xml 节点划分为不相交集合的机制。想象一下有一个 <address>
xml 中的标记,其中标记被定义了多次。例如,它可以指网址或街道地址,因此根据上下文具有完全不同的含义。为了避免混淆,您添加一个命名空间前缀,如下所示:<web:address>
<street:address>
将它们分开并将引用同一 namespace 的其他元素分组。您之前在某些根标记中定义了它们:
<root xmlns:web="Web">
<web:address> ... </web:address>
</root>
此外,还有一个特殊的命名空间 - 默认命名空间 - 定义如下:<feed xmlns="Name">
。拥有默认命名空间允许您在每次定义 xml 元素时省略编写命名空间前缀。
让我们用 xml 示例来澄清这一点:它为 <feed>
声明了三个命名空间。元素(yt、媒体和默认命名空间)
<feed xmlns:yt="http://www.youtube.com/xml/schemas/2015"
xmlns:media="http://search.yahoo.com/mrss/"
xmlns="http://www.w3.org/2005/Atom">
这意味着 <feed>
中的每个元素有点隐式地以默认命名空间为前缀。
序列化
我下载了您提供的xml文件并做了一些测试。事实证明,JAXB 只是“没有看到”实体标签,因为它们隐藏在默认命名空间后面,而且我们从未对 JAXB 说过根本有命名空间,除了 <feed>
之外。元素。
因此,解决方案是使用命名空间注释要反序列化的元素,以便 JAXB 能够理解。
更新2
看起来上面提供的解决方案太困惑了:必须用命名空间注释每个其他元素确实违反了 DRY 原则。幸运的是,有一种解决方案可以在一行中添加默认命名空间。
创建一个名为package-info.java的文件,并在其中添加以下内容并替换 package
与你的:
@XmlSchema(
namespace = "http://www.w3.org/2005/Atom",
elementFormDefault = XmlNsForm.QUALIFIED
)
package package;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
它所做的只是为我们要解析的文档定义一个 xml 模式。您现在可以删除所有 namespace = "..."
行并美化代码
如果您不熟悉 xml 架构,请查看它,因为这是控制 xml 文档结构的好方法。
更新2后的代码:
饲料类别
import javax.xml.bind.annotation.*;
import java.util.List;
@XmlRootElement(name = "feed")
@XmlAccessorType(XmlAccessType.FIELD)
public class Feed {
@XmlElement(name = "entry")
private List<Entry> entries;
public List<Entry> getEntries() {
return this.entries;
}
}
入门级
import javax.xml.bind.annotation.*;
import java.util.Date;
@XmlRootElement(name = "entry")
@XmlAccessorType(XmlAccessType.FIELD)
public class Entry {
@XmlElement(name = "title")
private String title;
@XmlElement(name = "id")
private String id;
@XmlElement(name = "published")
private Date datePublished;
@XmlElement(name = "author")
private Author author;
public String toString(){
return String.format("Id: %s, Title: %s, Author: %s, Published: %s",
id,
title,
author.toString(),
datePublished.toString());
}
}
作者类别
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "author")
@XmlAccessorType(XmlAccessType.FIELD)
public class Author {
@XmlElement(name = "name")
private String name;
@XmlElement(name = "url")
private String url;
public String getName() {
return name;
}
public String getUrl() {
return url;
}
@Override
public String toString() {
return getName();
}
}
主要
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import java.io.File;
public class Main {
public static void main(String[] args) throws JAXBException {
Feed feed = (Feed) JAXBContext
.newInstance(Feed.class)
.createUnmarshaller()
.unmarshal(new File("youtube_feed.xml"));
for (Entry entry : feed.getEntries()) {
System.out.println(entry.toString());
}
}
}
阅读理解
关于java - JAXB 未检测到元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44812855/