使用getNamespaces()无法解析带有冒号(:)的xml数据响应

3

我想要阅读以下xml文件中位于<q:content></q:content>标签内的所有内容 -

$xml = '<?xml version="1.0"?>
                    <q:response xmlns:q="http://api-url">
                        <q:impression>
                            <q:content>
                                <html>
                                    <head>
                                        <meta name="HandheldFriendly" content="True">
                                        <meta name="viewport" content="width=device-width, user-scalable=no">
                                        <meta http-equiv="cleartype" content="on">
                                    </head>
                                    <body style="margin:0px;padding:0px;">
                                        <iframe scrolling="no" src="http://some-url" width="320px" height="50px" style="border:none;"></iframe>
                                    </body>
                                </html>
                            </q:content>
                            <q:cpc>0.02</q:cpc>
                        </q:impression>
                    ...
                        ... some more things
                    ...
                    </q:response>';

我已将XML放入上述变量中,然后我使用SimpleXMLElement::getNamespaces,如在“示例#1获取正在使用的文档命名空间”部分所示。
//code continued
$dom = new DOMDocument;
 // load the XML string defined above
$dom->loadXML($xml);

var_dump($dom->getElementsByTagNameNS('http://api-url', '*') ); // shows object(DOMNodeList)#3 (0) { } 


foreach ($dom->getElementsByTagNameNS('http://api-url', '*') as $element) 
{
    //this does not execute
    echo 'see - local name: ', $element->localName, ', prefix: ', $element->prefix, "\n";
}

但是for循环内部的代码不会执行。

我已经阅读了以下问题 -

更新
还尝试了这个解决方案 使用SimpleXML解析带有命名空间的XML -

$xml = new SimpleXMLElement($xml);
$xml->registerXPathNamespace('e', 'http://api-url');

foreach($xml->xpath('//e:q') as $event) {
    echo "not coming here";
    $event->registerXPathNamespace('e', 'http://api-url');
    var_export($event->xpath('//e:content'));
}

在这种情况下,foreach内部的代码不会执行。 不确定我是否写得正确... 进一步更新
采用第一种解决方案...使用error_reporting = -1,发现问题出在iframe标签的src属性中的URL。收到警告,如:
Warning: DOMDocument::loadXML(): EntityRef: expecting ';' in Entity, line: 13

更新的代码 -

$xml = '<?xml version="1.0"?>
                    <q:response xmlns:q="http://api-url">
                        <q:impression>
                            <q:content>
                                <html>
                                    <head>
                                        <meta name="HandheldFriendly" content="True" />
                                        <meta name="viewport" content="width=device-width, user-scalable=no" />
                                        <meta http-equiv="cleartype" content="on" />
                                    </head>
                                    <body style="margin:0px;padding:0px;">
                                        <iframe scrolling="no" src="http://serve.qriously.com/v1/request?type=SERVE&aid=ratingtest&at=2&uid=0000000000000000&noHash=true&testmode=true&ua=Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; Nexus One Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1&appid=12e2561f048158249e30000012e256826ad&pv=2&rf=2&src=admarvel&type=get&lang=eng" width="320px" height="50px" style="border:none;"></iframe>
                                    </body>
                                </html>
                            </q:content>
                            <q:cpc>0.02</q:cpc>
                        </q:impression>
                        <q:app_stats>
                                <q:total><q:ctr>0.023809523809523808</q:ctr><q:ecpm>0.5952380952380952</q:ecpm></q:total>
                                <q:today><q:ctr>0.043478260869565216</q:ctr><q:ecpm>1.0869565217391306</q:ecpm></q:today>
                        </q:app_stats>
                    </q:response>';

foreach内的代码块不执行,因为DOMNodeList为空。foreach确实会执行,但由于没有要迭代的元素,所以其中的代码块被跳过。我建议您先将其放入自己的变量中,以便更容易进行调试。 - hakre
@hakre,是的,我意思是一样的...但写错了。 - Sandeepan Nath
没问题,只是想让这一点清楚。函数的工作正常,但你没有正确创建文档,请看我的回答。 - hakre
你从哪里获取那个XML文件的?是自己编写的吗? - hakre
这是我从qriously API(http://www.qriously.com/)获取的响应。 - Sandeepan Nath
显示剩余4条评论
1个回答

4

我没有问题让它正常工作,我唯一发现的错误是你加载了包含非XML HTML块的XML,这破坏了文档:head部分中的meta元素没有关闭。

查看演示

提示:总是激活错误记录和报告,如果您开发和调试代码,请检查警告和通知。显示所有类型的PHP错误消息,包括警告通知严格模式的简短一行:

error_reporting(-1); ini_set('display_errors', 1);

DOMDocument在加载XML时,对于格式不正确的元素会进行详细说明。

即时修复XML

DomDocument只接受有效的XML。如果您有HTML,您可以尝试使用 DOMDocument :: loadHTML(),但它会将加载的字符串转换为X(HT)ML文档。这可能不是您想要的。

要转义特定的字符串部分以使其与XML兼容,您可以搜索字符串模式以获取表示XML中的HTML的子字符串,并适当地对其进行XML编码。

例如,您可以查找<html></html>作为周围标记,提取整个子字符串并用substr_replace()替换它。要将HTML编码为XML中使用的数据,请使用htmlspecialchars()函数,它将使用其他SO答案中的五个实体替换所有内容。

一些模拟代码:

$htmlStart = strpos($xml, '<html>');
if (false === $htmlStart) throw new Exception('<html> not found.');
$htmlEnd = strpos($xml, '</html>', $htmlStart);
if (false === $htmlStart) throw new Exception('</html> not found.');
$htmlLen = $htmlEnd - $htmlStart + 7;
$htmlString = substr($xml, $htmlStart, $htmlLen);
$htmlEscaped = htmlspecialchars($htmlString, ENT_QUOTES);
$xml = substr_replace($xml, $htmlEscaped, $htmlStart, $htmlLen);

我认为你在技术上应该转义一些HTML字符。请参考这篇文章:https://dev59.com/_XNA5IYBdhLWcg3wGJwV - Aaron Ray
@hakre - 不好意思,没有 :(,请查看此前的评论。 - Sandeepan Nath
1
尝试使用 error_reporting(-1); ini_set('display_errors', 1); 这段代码,然后仔细检查你的 XML 是否正确。 - hakre
准确来说,当我在iframe的src属性中添加第二个参数时,警告开始出现。我猜需要对&进行一些转义,正如@Aaron Ray指出的那样。如果要这样做,我需要有选择地转义 https://dev59.com/_XNA5IYBdhLWcg3wGJwV#1091953中列出的字符列表吗?我该如何做到这一点? - Sandeepan Nath
1
@Sandeepan Nath:已更新答案。关于E_ALL - 不,它不会。也许对于PHP 5.4或更高版本,它会再次出现,但现在常量名称完全具有误导性。这就是为什么我通常建议使用-1作为解决方法的原因。 - hakre
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接