最可靠方式是用 SimpleXML 配合 libxml 容错处理:先调用 libxml_use_internal_errors(true),再用 simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NONET | LIBXML_NOWARNING),最后 libxml_clear_errors()。

PHP 解析 RSS 或 Atom feed 的 XML,最可靠的方式是用 SimpleXML 配合 libxml 的容错处理——不是所有 feed 都严格符合规范,直接 simplexml_load_string() 容易报错中断。
为什么 simplexml_load_string() 常失败?
RSS/Atom feed 常含以下问题:XML declaration 编码声明不匹配、BOM 字节、命名空间混用、HTML 实体未转义、CDATA 块嵌套非法字符。默认调用会因 DOMDocument::loadXML() 的严格解析而抛出警告或返回 false。
- 必须先用
libxml_use_internal_errors(true)抑制错误 - 再用
simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NONET | LIBXML_NOWARNING) -
LIBXML_NONET防止解析器尝试加载外部 DTD(安全且提速) - 解析后记得调用
libxml_clear_errors()避免污染后续 XML 操作
如何统一处理 RSS 2.0 和 Atom 1.0 的结构差异?
RSS 用 包裹条目,Atom 用 ;条目标签分别是 和 。别硬写两套逻辑,用命名空间 + XPath 更稳:
if ($xml->getName() === 'rss') {
$items = $xml->channel->item;
} elseif ($xml->getName() === 'feed' && $xml->getNamespaces()) {
$atom = $xml->getNamespaces()[''];
$items = $xml->xpath('//entry');
} else {
$items = $xml->xpath('//item | //entry');
}
注意:$xml->getNamespaces() 返回空数组 ≠ 没命名空间,Atom 常用默认命名空间(xmlns="http://www.w3.org/2005/Atom"),此时需显式传入 '' 键取值。
立即学习“PHP免费学习笔记(深入)”;
提取标题、链接、发布时间时容易踩哪些坑?
字段名看似一致,实际分布混乱:
- RSS 的
是字符串,需用strtotime()转时间戳;Atom 的或是 ISO 8601 格式,可用DateTime::createFromFormat()或直接传给new DateTime() - 链接字段:RSS 用
(可能为文本内容或属性href),Atom 必须查的href属性 - 内容字段:RSS 多用
或(需注册命名空间),Atom 用或,且可能含type="html"属性
建议封装一个 getSafeText($node, $tagName) 函数,内部用 ->__toString() + trim() + htmlspecialchars_decode() 统一清理。
要不要用第三方库?比如 php-feed-reader?
小项目够用,但要注意:php-feed-reader 内部仍基于 SimpleXML,只是封装了命名空间和字段映射。它对 malformed feed 的容错没比手写强多少,反而增加一层抽象导致调试困难。真正省心的场景只有两个:需要自动发现 feed 链接(从 HTML 提取),或要同时支持 JSON Feed。否则,20 行以内手写解析更可控。
复杂点永远在 feed 源本身——同一个站点今天发标准 RSS,明天加个自定义命名空间字段,或者把 写成 。别指望一次解析适配所有源,留好 fallback 字段和日志记录才是关键。











