Java 11+需手动添加Jakarta XML Bind依赖,Java 8–10需注意命名空间声明;推荐使用Rome库解析/生成RSS,避免JAXB移除、DTD加载、时区格式等问题。

Java里用javax.xml.bind解析RSS会直接报错
Java 11+ 默认移除了 jaxb-api,所以哪怕你写了 JAXBContext.newInstance(RSS.class),运行时大概率抛 ClassNotFoundException: javax.xml.bind.JAXBContext。这不是代码写错了,是JDK把这堆类踢出去了。
实操建议:
- 如果用 Java 8–10:照常用
JAXBContext+Unmarshaller,但注意 RSS 的命名空间(xmlns:dc="http://purl.org/dc/elements/1.1/")得在类上用@XmlSchema或@XmlElement显式声明,否则字段为空 - 如果用 Java 11 及以上:必须手动加依赖,Maven 写清楚版本:
<dependency> <groupId>jakarta.xml.bind</groupId> <artifactId>jakarta.xml.bind-api</artifactId> <version>4.0.0</version> </dependency> <dependency> <groupId>org.glassfish.jaxb</groupId> <artifactId>jaxb-runtime</artifactId> <version>4.0.3</version> </dependency>
- 别用
javax.xml.parsers.DocumentBuilder手动遍历 DOM 解析 RSS——字段多、命名空间杂、日期格式不统一,三天都调不完
用Rome库生成RSS比原生API快十倍还稳
Rome 是专为 Syndication 设计的库,封装了 RSS/Atom 全部变体(rss_2.0、atom_1.0、甚至 rss_0.91),不用自己硬扛 <pubDate> 和 <dc:date> 的时间格式转换。
常见错误现象:生成的 XML 在 Feedly 或 Inoreader 里显示“无效源”,多半是 <channel> 缺 <lastBuildDate> 或 <item> 里没填 <guid>(即使 RSS 2.0 不强制,但现代阅读器默认校验)。
立即学习“Java免费学习笔记(深入)”;
实操建议:
- 创建
SyndFeed后必须设feed.setFeedType("rss_2.0"),不设默认是rss_0.91,会导致<content:encoded>被忽略 -
SyndEntry的setUri()对应<guid>,别用setTitle()混着填;setPublishedDate()传java.util.Date即可,Rome自动转 RFC 822 格式 - 要支持
dc:creator,得先feed.setModule(new DCModuleImpl()),再往entry里加DCModule实例,不能只靠注解
DocumentBuilder 解析 RSS 时遇到 EntityResolver 报错
典型错误信息:java.io.FileNotFoundException: http://cyber.law.harvard.edu/rss/rss.html —— 这不是网络问题,是 RSS 文件开头的 DTD 声明触发了默认的外部实体加载,而那个 URL 早已失效。
根本原因:JDK 的 DocumentBuilder 默认开启 setExpandEntityReferences(true),一碰到 <!DOCTYPE rss SYSTEM "http://cyber.law.harvard.edu/rss/rss.html"> 就去远程抓取。
实操建议:
- 必须禁用外部 DTD 加载:
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); // 或兼容老 JDK: factory.setValidating(false); factory.setNamespaceAware(true); - 如果非要用 DOM 解析(比如要提取
<media:thumbnail>这种非标准扩展),记得调用document.getDocumentElement().getElementsByTagNameNS("*", "thumbnail"),别用无命名空间的getElementsByTagName - 别信“用
InputSource包一层字符串就能绕过 DTD”——只要 XML 字符串含DOCTYPE,DocumentBuilder照样报错
RSS 时间字段的时区处理最容易漏掉
RSS 规范要求 <pubDate> 用 RFC 822 格式(如 Wed, 05 Oct 2022 14:30:00 +0800),但 Java 的 SimpleDateFormat 默认不带时区偏移,ZonedDateTime 转出来的却是 ISO 8601 格式,阅读器直接当无效时间丢弃。
实操建议:
- 生成时用
new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z", Locale.US),注意Locale.US控制英文缩写(Wed,Oct),否则中文系统下输出星期三就废了 - 解析时别用
SimpleDateFormat直接 parse——RFC 822 有多个变体(+0000、GMT、UTC),Rome库内部用javax.mail.internet.MailDateFormat处理更可靠 - 如果后端时间存的是 UTC,生成前务必调用
date.setTime(date.getTime() + TimeZone.getDefault().getOffset(date.getTime()))补本地偏移——RSS 不接受纯 UTC 时间,必须带+0800这种显式标记
真正麻烦的从来不是读写 XML,而是 RSS 那些“理论上可选、实际上必填”的字段,还有阅读器厂商各自加的私有扩展。与其反复试错,不如从第一天就用 Rome,把精力留给内容逻辑。










