Невозможно проанализировать данные XML с двоеточием (:) из ответа, используя getNamespaces () - PullRequest
3 голосов
/ 12 июля 2011

Я хочу прочитать все, что находится внутри тегов <q:content></q:content> в следующем xml -

$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 не выполняется.

Я прочитал эти вопросы -

обновление
Также пробовал это решение Анализ XML с пространством имен с использованием SimpleXML -

$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, обнаружил, что проблема с URL вsrc атрибут тега iframe.Получение предупреждений, таких как -

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>';

1 Ответ

4 голосов
/ 12 июля 2011

У меня нет проблем, чтобы заставить его работать, единственная ошибка, которую я могу найти, это то, что вы загружаете XML, содержащий там не HTML-фрагмент HTML, который нарушает работу документа: метаэлементы в разделе head не являются закрыты.

См. Демонстрацию .

Совет: Всегда активируйте ведение журнала ошибок и отчетов, проверяйте предупреждения и уведомления, если вы разрабатываете и отлаживаете код. Короткая однострочная строка с отображением всех сообщений об ошибках PHP, вкл. предупреждения , уведомления и строгие :

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

DOMDocument - это разговорчивый материал о некорректных элементах при загрузке XML.

Исправление XML "на лету"

DomDocument принимает только допустимый XML. Если у вас есть HTML, вы также можете попробовать, если DOMDocument::loadHTML() тоже справится с работой, однако тогда он преобразует загруженную строку в документ X (HT) ML. Наверное, не то, что вы ищете.

Чтобы избежать загрузки определенной части строки и сделать ее совместимой с XML, вы можете искать строковые шаблоны, чтобы получить подстроку, представляющую HTML-код внутри XML, и правильно 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);
...