【问题标题】:JAXB not detecting elementsJAXB 未检测到元素
【发布时间】:2017-06-28 21:30:08
【问题描述】:

我正在尝试利用 JAXB 将从 youtube rss 提要获得的 xml 元素转换为对象。我似乎遵循了我见过的大多数示例的结构,但仍然无法使其工作,因为提要中的列表似乎总是空的。有谁知道如何解决这一问题? 以下是我的课程供参考:

饲料类:

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并且文件路径是正确的,只是在上面的sn-p中没有完全包含隐私。任何帮助将不胜感激。

【问题讨论】:

  • 尝试在setter中放置一个断点。如果它中断检查内容
  • @efekctive 在使用断点进行测试后,它进入了提要类并命中了@xmlelement(name = "entry") 行,但是它根本没有进入入口类。是因为我只是想说明 XML 文件中的特定信息而不是全部信息吗?
  • 也就是说:“setEntry(List entries)”中的参数条目为null还是为空?
  • Entry 类除了根元素没有注释。它需要类似 "@XmlElement(name = "entry")" 如果可行,我会将其作为答案发布
  • 您是说在 Entry 类中为每个变量放置一个 @XmlElement(name = variable) 吗?参数条目可能为空,我不完全确定在解组过程中是否有任何东西将列表传递给它。

标签: java xml youtube jaxb rss


【解决方案1】:
  1. 请让您的类名遵循 Pascal 表示法 - 这样更容易阅读和理解,尤其是在有大量代码的情况下。可能,您应该更多地处理您的代码风格。

  2. 您的 feed 类已正确注释,但为了让 JAXB 将 XML 解组到条目中,entry 类也应正确注释。另请注意,您的字段名称与提供的 xml 文件中的标记名称不匹配(&lt;name&gt; 不能在 &lt;feed&gt; 中直接访问)。 因此,添加注释和类以匹配 xml 文件结构。

更新 1

我意识到我对xml文档不太了解,所以我做了一点调查。

如果你完全熟悉 xml 命名空间,那么你可以跳过这部分到序列化部分。否则,请继续阅读。

Namespace 是一种将 xml 节点划分为不相交集的机制。想象一下,在您的 xml 中有一个 &lt;address&gt; 标签,该标签被定义了很多次。例如,它可以指代网址或街道地址,因此根据上下文具有完全不同的含义。为避免混淆,您可以添加这样的命名空间前缀:&lt;web:address&gt; &lt;street:address&gt; 以分隔它们并将引用同一命名空间的其他元素分组。您之前在一些根标签中定义它们:

<root xmlns:web="Web"> 
    <web:address> ... </web:address>
</root>

此外,还有一个特殊的命名空间 - 默认命名空间 - 定义如下:&lt;feed xmlns="Name"&gt;。拥有默认命名空间允许您在每次定义 xml 元素时省略写入命名空间前缀。

让我们用您的 xml 示例来澄清这一点:它为 &lt;feed&gt; 元素声明了三个命名空间(yt、media 和 default 命名空间)

<feed xmlns:yt="http://www.youtube.com/xml/schemas/2015" 
      xmlns:media="http://search.yahoo.com/mrss/" 
      xmlns="http://www.w3.org/2005/Atom">

这意味着&lt;feed&gt; 中的每个 元素都隐含地以默认命名空间为前缀。

Intro to XML namespaces

Atom namespace explained

序列化

我下载了您提供的 xml 文件并进行了一些测试。事实证明,JAXB 只是“没有看到”实体标签,因为它们隐藏在默认命名空间后面,而且我们从未对 JAXB 说过除了 &lt;feed&gt; 元素之外还有命名空间。

因此,解决方案是使用命名空间注释要反序列化的元素,以便 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());
        }

    }
}

阅读理解

JAXB and XML namespaces

Oracle JAXB annotations reference

【讨论】:

  • 我很抱歉,我的代码实际上在 intelliJ 上看起来组织得很完美,当我把它放在这里时,它似乎失去了缩进!前几个标签实际上不是用于条目,而是用于通道本身。
  • xml 也不会只有条目的问题吗?这是我从 youtube 频道获取的 xml 文件,我必须能够在不修改文件的情况下从中提取数据。我尝试将 xmlelement 符号添加到入口类中的其余元素,但似乎仍然无法创建它们。
  • 非常感谢您提供如此详细的解决方案!我会在早上阅读它并自己测试它!:)
  • 嗨@GoodMove,我尝试自己复制和粘贴所有这些类并修复文件路径以检查它是否有效,但我似乎遇到了命名空间的问题。我想我对您在更新 2 中所做的事情感到困惑。您是否只是按顺序创建了一个包含小代码 sn-p 的全新 Java 文件?因为它似乎告诉我这是不可能的,即使在移动导入和包之后它告诉我“这里不允许注释”
  • @DevinAmatya,是的,只需创建一个名为 package-info.java 的 java 文件,将代码粘贴到那里并更新包的路径
猜你喜欢
  • 1970-01-01
  • 2012-08-20
  • 2019-10-03
  • 1970-01-01
  • 1970-01-01
  • 2019-11-09
  • 1970-01-01
  • 2017-05-21
  • 2020-11-19
相关资源
最近更新 更多