从XML提要中的文本元素提取img src



我有一个XML提要,如下所示:

<?xml version="1.0" encoding="UTF-8"?>
<smf:xml-feed xmlns:smf="http://www.simplemachines.org/" xmlns="http://www.simplemachines.org/xml/recent" xml:lang="en-US">
<recent-post>
<time>April 04, 2021, 04:20:47 pm</time>
<id>1909114</id>
<subject>Title</subject>
<body><![CDATA[<a href="#"><img src="image.png">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure rerum in tempore sit ducimus doloribus quod commodi eligendi ipsam porro non fugiat nisi eaque delectus harum aspernatur recusandae incidunt quasi.</a>]]></body>
</recent-post>
</smf:xml-feed>

我想从body中提取图像src,然后将其保存到一个新的XML文件中,该文件包含image的元素。

到目前为止,我有

$xml = 'https://example.com/feed.xml';
$dom = new DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->recover = true;
libxml_use_internal_errors(true);
$dom->loadXML($xml);
$xpath = new DOMXPath( $dom );
$nodes = $xpath->query( 'smf:xml-feed/recent-post/body' );
foreach( $nodes as $node )
{
$html = new DOMDocument();
$html->loadHTML( $node->nodeValue );
$src = $html->getElementsByTagName( 'img' )->item(0)->getAttribute('src');
echo $src;
}

但当我尝试打印$nodes时,却一无所获。我错过了什么?

这看起来像一个Simple Machines提要。然而,名称空间是缺失的;身体;元素应该是一个CDATA部分,其中有一个html片段作为文本。我希望看起来像这样:

<smf:xml-feed 
xmlns:smf="http://www.simplemachines.org/" 
xmlns="http://www.simplemachines.org/xml/recent" 
xml:lang="en-US">
<recent-post>
<time>April 04, 2021, 04:20:47 pm</time>
<id>1909114</id>
<subject>Title</subject>
<body><![CDATA[
<a href="#"><img src="image.png">Lorem ipsum dolor sit amet, consectetur adipisicing elit. Iure rerum in tempore sit ducimus doloribus quod commodi eligendi ipsam porro non fugiat nisi eaque delectus harum aspernatur recusandae incidunt quasi.</a>
]]>
</body>
</recent-post>
</smf:xml-feed>

XML定义了两个名称空间。要在Xpath表达式中使用它们,必须为它们注册前缀。我建议迭代recent-post元素。然后使用带字符串强制转换的表达式获取特定子节点的文本内容。

body元素以文本形式包含HTML片段,因此需要将其加载到一个单独的文档中。然后,您可以在此文档上使用Xpath获取img:的src

$feedDocument = new DOMDocument();
$feedDocument->preserveWhiteSpace = false;
$feedDocument->loadXML($xmlString);
$feedXpath = new DOMXPath($feedDocument);
// register namespaces
$feedXpath->registerNamespace('smf', 'http://www.simplemachines.org/');
$feedXpath->registerNamespace('recent', 'http://www.simplemachines.org/xml/recent');
// iterate the posts
foreach($feedXpath->evaluate('/smf:xml-feed/recent:recent-post') as $post) {
// demo: fetch post subject as string
var_dump($feedXpath->evaluate('string(recent:subject)', $post));

// create a document for the HTML fragment
$html = new DOMDocument();
$html->loadHTML(
// load the text content of the body element
$feedXpath->evaluate('string(recent:body)', $post),
// just a fragment, no need for html document elements or DTD
LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD
);
// Xpath instance for the html document
$htmlXpath = new DOMXpath($html);
// fetch first src attribute of an img 
$src = $htmlXpath->evaluate('string(//img/@src)');
var_dump($src);
}

输出:

string(5) "Title"
string(9) "image.png"

您的代码有几个问题,其中一些问题我必须对…做出假设

在中

$dom->loadXML($xml);

这需要实际的源XML而不是URL,您需要使用load()

我不得不假设smf名称空间是在文档中的某个地方定义的,出于测试目的,我已经将示例XML更改为…

<smf:xml-feed xml:lang="en-US" xmlns:smf="http://a.com">

我还将查询更改为

//smf:xml-feed/recent-post/body

以测试此代码。

最后,不确定为什么要在循环中创建另一个文档,但应该能够直接从循环中的节点处理这个文档,所以我使用$node作为getElementsByTagName()调用的基础。。。

$xml = 'https://example.com/feed.xml';
$dom = new DOMDocument();
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->recover = true;
libxml_use_internal_errors(true);
$dom->load($xml);
$xpath = new DOMXPath( $dom );
$nodes = $xpath->query( '//smf:xml-feed/recent-post/body' );
foreach( $nodes as $node )
{
$src = $node->getElementsByTagName( 'img' )->item(0)->getAttribute('src');
echo $src;
}

最新更新