Предотвращение DOMDocument :: loadHTML () от преобразования сущностей - PullRequest
4 голосов
/ 08 сентября 2011

У меня есть строковое значение, для которого я пытаюсь извлечь элементы списка.Я хотел бы извлечь текст и любые подузлы, однако DOMDocument преобразует сущности в символ, а не оставляет в исходном состоянии.

Я пытался установить DOMDocument :: resolExternals и DOMDocument ::substituteEntities для false, но это не имеет никакого эффекта.Следует отметить, что я работаю на Win7 с PHP 5.2.17.

Пример кода:

$example = '<ul><li>text</li>'.
    '<li>&frac12; of this is <strong>strong</strong></li></ul>';

echo 'To be converted:'.PHP_EOL.$example.PHP_EOL;

$doc = new DOMDocument();
$doc->resolveExternals = false;
$doc->substituteEntities = false;

$doc->loadHTML($example);

$domNodeList = $doc->getElementsByTagName('li');
$count = $domNodeList->length;

for ($idx = 0; $idx < $count; $idx++) {
    $value = trim(_get_inner_html($domNodeList->item($idx)));
    /* remainder of processing and storing in database */
    echo 'Saved '.$value.PHP_EOL;
}

function _get_inner_html( $node ) {
    $innerHTML= '';
    $children = $node->childNodes;
    foreach ($children as $child) {
        $innerHTML .= $child->ownerDocument->saveXML( $child );
    }

    return $innerHTML;
}

&frac12; заканчивается преобразованием в ½ (одиночный символ / UTF-8 версия, а не версия объекта), который не является желаемым форматом.

Ответы [ 3 ]

5 голосов
/ 08 сентября 2011

Решение для не PHP 5.3.6 ++

$html =<<<HTML
<ul><li>text</li>
<li>&frac12; of this is <strong>strong</strong></li></ul>
HTML;

$doc = new DOMDocument();
$doc->resolveExternals = false;
$doc->substituteEntities = false;
$doc->loadHTML($html);
foreach ($doc->getElementsByTagName('li') as $node)
{
  echo htmlentities(iconv('UTF-8', 'ISO-8859-1', $node->nodeValue)), "\n";
}
2 голосов
/ 08 сентября 2011

Основываясь на ответе , предоставленном ajreal , я расширил примерную переменную для обработки большего количества случаев и изменил _get_inner_html () для выполнения рекурсивных вызовов и обработки преобразования сущностей для текстовых узлов.

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

$example = '<ul><li>text</li>'.
'<li>&frac12; of this is <strong>strong</strong></li>'.
'<li>Entity <strong attr="3">in &frac12; tag</strong></li>'.
'<li>Nested nodes <strong attr="3">in &frac12; <em>tag &frac12;</em></strong></li>'.
'</ul>';

echo 'To be converted:'.PHP_EOL.$example.PHP_EOL;

$doc = new DOMDocument();
$doc->resolveExternals = true;
$doc->substituteEntities = false;

$doc->loadHTML($example);

$domNodeList = $doc->getElementsByTagName('li');
$count = $domNodeList->length;

for ($idx = 0; $idx < $count; $idx++) {
    $value = trim(_get_inner_html($domNodeList->item($idx)));

    /* remainder of processing and storing in database */
    echo 'Saved '.$value.PHP_EOL;

}

function _get_inner_html( $node ) {
    $innerHTML= '';
    $children = $node->childNodes;
    foreach ($children as $child) {
        echo 'Node type is '.$child->nodeType.PHP_EOL;
        switch ($child->nodeType) {
        case 3:
            $innerHTML .= htmlentities(iconv('UTF-8', 'ISO-8859-1', $child->nodeValue));
            break;
        default:
            echo 'Non text node has '.$child->childNodes->length.' children'.PHP_EOL;
            echo 'Node name '.$child->nodeName.PHP_EOL;
            $innerHTML .= '<'.$child->nodeName.'>';
            $innerHTML .= _get_inner_html( $child );
            $innerHTML .= '</'.$child->nodeName.'>';
            break;
        }
    }

    return $innerHTML;
}
0 голосов
/ 06 июня 2012

Не нужно повторять дочерние узлы:

function innerHTML($node)
         {$html=$node->ownerDocument->saveXML($node);
          return preg_replace("%^<{$node->nodeName}[^>]*>|</{$node->nodeName}>$%", '', $html);
         }
...