Извлечение HTML из файла XML с использованием simpleXML - PullRequest
2 голосов
/ 20 января 2011

Я читаю xml-файл, созданный сторонним приложением, которое включает следующее:

<Cell>
    <Comment ss:Author="Mark Baker">
        <ss:Data xmlns="http://www.w3.org/TR/REC-html40"><B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">Mark Baker:</Font></B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">&#10;Comment 1 - No align</Font></ss:Data>
    </Comment>
</Cell>

Я пытаюсь получить доступ к необработанным данным из Cell-> Comment-> Элемент данных либо «как есть», либо как фактический блок разметки (X) HTML (желательно последней).

if (isset($cell->Comment)) {
    echo 'comment found<br />';
    $commentAttributes = $cell->Comment->attributes($namespaces['ss']);
    if (isset($commentAttributes->Author)) {
        echo 'Author: ',(string)$commentAttributes->Author,'<br />';
    }
    $commentData = $cell->Comment->children($namespaces['ss']);
    var_dump($commentData);
    echo '<br />';
}

дает мне:

comment found
Author: Mark Baker
object(SimpleXMLElement)#130 (2) { ["@attributes"]=> array(1) { ["Author"]=> string(10) "Mark Baker" } ["Data"]=> object(SimpleXMLElement)#129 (0) { } } 

, а

if (isset($cell->Comment)) {
    echo 'comment found<br />';
    $commentAttributes = $cell->Comment->attributes($namespaces['ss']);
    if (isset($commentAttributes->Author)) {
        echo 'Author: ',(string)$commentAttributes->Author,'<br />';
    }
    $commentData = $cell->Comment->Data->children();
    var_dump($commentData);
    echo '<br />';
}

дает мне:

comment found
Author: Mark Baker
object(SimpleXMLElement)#129 (2) { ["B"]=> object(SimpleXMLElement)#118 (1) { ["Font"]=> string(11) "Mark Baker:" } ["Font"]=> string(21) " Comment 1 - No align" } 

К сожалению, simpleXML, похоже, рассматривает весь элемент как последовательность узлов XML.Я уверен, что смогу получить эти необработанные данные без сложной зацикливания или передачи элемента в DOM Parser;возможно, используя пространство имен xmlns = "http://www.w3.org/TR/REC-html40", чтобы извлечь это чисто, но я не могу понять, как.

Любая помощь приветствуется.

Более сложный пример данных XML:

<Cell>
    <Comment ss:Author="Mark Baker">
        <ss:Data xmlns="http://www.w3.org/TR/REC-html40">
            <B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">Mark Baker:</Font></B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000">&#10;</Font><B><Font html:Face="Tahoma" x:Family="Swiss" html:Size="8" html:Color="#000000">Rich </Font><U><Font html:Face="Tahoma" x:Family="Swiss" html:Size="8" html:Color="#FF0000">Text </Font></U><Font html:Face="Tahoma" x:Family="Swiss" html:Size="8" html:Color="#000000">Comment</Font></B><Font html:Face="Tahoma" html:Size="8" html:Color="#000000"> Center Aligned</Font>
        </ss:Data>
    </Comment>
</Cell>

Ответы [ 4 ]

2 голосов
/ 20 января 2011

Если бы ваша реализация использовала DOM, я думаю, вы могли бы сделать следующее:

//given $node is <ss:data>

$frag = $node->ownerDocument->createDocumentFragment();
foreach($node->childNodes as $child){
    $frag->appendChild($child->cloneNode(true));
}
$string = $node->ownerDocument->saveXML($frag);
1 голос
/ 20 января 2011

Если HTML внутри элемента <ss:Data> считается строковым литералом, его необходимо заключить в секцию CDATA , как уже было указано в комментариях

$xml = <<< XML
<Cell>
    <Comment ss:Author="Mark Baker">
        <ss:Data xmlns="http://www.w3.org/TR/REC-html40">
            <![CDATA[
                <B><Font html:Face="Tahoma" … html:Color="#000000">
            ]]>
        </ss:Data>
    </Comment>
</Cell>
XML;
libxml_use_internal_errors(TRUE);
$cell = simplexml_load_string($xml);
echo $cell->Comment->Data;

Если он не находится в разделе CDATA, он будет считаться узлами.Тогда вы бы искали innerXml <ss:Data>, чтобы получить его как необработанный XML.К сожалению, ни SimpleXml, ни DOM не имеют собственного способа получить это напрямую.Вы должны будете использовать реализацию пользовательского пространства.

Пользовательские реализации innerXml обычно либо выполняют итерацию по всем дочерним узлам, либо объединяют их необработанный XML.Или они сбрасывают все дерево, а строка заменяет корневой узел.Или они создают фрагмент или импортируют узлы в другой документ.

Я не знаю другого способа сделать это.Не уверен, что это будет возможно с XSLT.XMLReader имеет метод readInnerXML.

0 голосов
/ 07 июля 2011

Итак, я знаю, что ваш вопрос пришел и ушел, но у меня была та же проблема, и я должен был выяснить, как я хотел бы с ней справиться.Для будущих поколений вот как я это понял.

Если вы принимаете только (x) HTML:

$data = str_replace('<?xml version="1.0"?>','',$xmlNode->asXML());

Если вы думаете, что кто-то собирается вставить XML, и вы в порядкепри этом вам нужно будет убить только первый автоматически сгенерированный тег XML:

$data = preg_replace('/^<\?xml version="1.0"\?\>\n/', '',$xmlNode->asXML());

Итак, ваш код будет выглядеть так:

if (isset($cell->Comment)) {
    echo 'comment found<br />';
    $commentAttributes = $cell->Comment->attributes($namespaces['ss']);
    if (isset($commentAttributes->Author)) {
        echo 'Author: ',(string)$commentAttributes->Author,'<br />';
    }
    $commentData = str_replace('<?xml version="1.0"?>','',$cell->Comment->Data->asXML());
    echo $commentData;
    echo '<br />';
}
0 голосов
/ 21 января 2011

Я пошел с быстрым и грязным решением в настоящее время.В более долгосрочной перспективе я перейду к использованию XMLReader (по всем упомянутым причинам) ... У меня просто нет времени переписать весь существующий код simpleXML на данный момент.

У меня естьпрошло с:

$node = $cell->Comment->Data->asXML();
$comment = substr($node,49,-10);
$comment = strip_tags($comment);

Хотя я бы предпочел сохранить разметку HTML, это потребует дополнительной работы, поэтому я просто убираю всю разметку, оставляя меня с простым текстом (который является критическим элементом).

Хотя это далеко не идеальное решение, оно делает то, что мне нужно (на данный момент), и я могу перейти к следующему пункту в моем списке «сделать», уже имеядобавил новый пункт «переписать с использованием XMLReader» в этот список.

Спасибо за помощь.Я обязательно вернусь к этой теме, когда буду переписывать.

...