HTML DOM: как получить элементы, не теряя детей? - PullRequest
1 голос
/ 14 марта 2011

Я пытаюсь выполнить preg_replace для текста в строке HTML. Я хочу избежать замены текста внутри тегов, поэтому я загружаю строку как элемент DOM и собираю текст в каждом узле. Например, у меня есть этот список:

<ul>
<li><a href="?p=oconnorinv&i=1">Boxes 1-3</a>: 1925 - 1928 <em>(A-Ma)</em></li>
<li><a href="?p=oconnorinv&i=2">Boxes 4-6</a>: 1928 <em>(Mb-Z)</em> - 1930 <em>(A-Wi)</em></li>
<li><a href="?p=oconnorinv&i=3">Boxes 7-9</a>: 1930 <em>(Wo-Z)</em>- 1932 <em>(A-Fl)</em></li>
</ul>

Я хочу, чтобы можно было выделить символ «1» или букву «i», не мешая ссылкам или тегу элемента списка. Поэтому я беру каждый элемент списка и получаю его значение для замены:

$invfile = [string of the unordered list above]
$invcontents = new DOMDocument;
$invcontents->loadHTML($invfile);
$inv_listitems = $invcontents->getElementsByTagName('li');
    foreach ($inv_listitems as $f) {
            $f->nodeValue = preg_replace($to_highlight, "<span class=\"highlight\">$0</span>", $f->nodeValue);
        }
    echo html_entity_decode($invcontents->saveHTML());

Проблема в том, что, когда я получаю значения узлов, дочерние узлы внутри элемента списка теряются. Если я распечатываю исходную строку как есть, все теги , и т. Д. Находятся там. Но когда я запускаю скрипт, он печатается без ссылок или каких-либо тегов форматирования. Например, если моим $ to_replace является строка «Ящики», список становится:

<ul>
<li><span class="highlight">Boxes</span> 1-3: 1925 - 1928 (A-Ma)</li>
<li><span class="highlight">Boxes</span> 4-6: 1928 (Mb-Z) - 1930 (A-Wi)</li>
<li><span class="highlight">Boxes</span> 7-9: 1930 (Wo-Z)- 1932 (A-Fl)</li>
</ul>

Как получить текст, не теряя теги внутри?

Ответы [ 3 ]

0 голосов
/ 14 марта 2011

ВЫ лучше работаете только с текстовыми узлами:

$x  = new DOMXPath(invcontents);
foreach($x->query('//li/text()' as $textnode){
    //replace text node with list of plain text nodes & your highlighting span.
}
0 голосов
/ 22 февраля 2013

Я всегда использую xpath для такого рода действий.Это даст вам больше гибкости.Этот пример обрабатывает

<mainlevel>
  <toplevel>
    <detaillevel key=...>
      <xmlvalue1></xmlvalue1>
      <xmlvalue1></xmlvalue2>

      <sublevel key=...>
        <xmlvalue1></xmlsubvalue1>
        <xmlvalue1></xmlsubvalue2>
      </sublevel>

    </detaillevel>
  </toplevel>
</mainlevel>

Для анализа этого:

$xpath = new DOMXPath($xmlDoc);
$mainNodes = $xpath->query("/mainlevel/toplevel/detaillevel");

foreach( $mainNodes as $subNode ) { 
    $parameter1=$subNode->getAttribute('key');
    $parameter2=$subNode->getElementsByTagName("xmlvalue1")->item(0)->nodeValue;
    $parameter3=$subNode->getElementsByTagName("xmlvalue2")->item(0)->nodeValue;

    foreach ($subNode->getElementsByTagName("sublevel") as $detailNode) {
        $parameter1=$detailNode->getAttribute('key');
        $parameter2=$detailNode->getAttribute('xmlsubvalue1');
        $parameter2=$detailNode->getAttribute('xmlsubvalue2');

        }
    }
0 голосов
/ 14 марта 2011

Проблема в том, что вы работаете со всем элементом

. Boxes является частью nodeValue тега привязки.

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

$ new_html = preg_replace ("##", "", $ f-> item (0) -> nodeValue);

В действительности, лучший способ сделать это - сбросить значение узла якоря, создать совершенно новый элемент и добавить его.

(рассмотрите этот код псевдо)

$inv_listitems = $invcontents->getElementsByTagName('li');
foreach ($inv_listitems as $f) {
        $span = $invcontents->createElement("span");
        $span->setAttribute("class", "highlight");
        $span->nodeValue = $f->item(0)->nodeValue;
        $f->appendChild($span);
    }
echo $invcontents->saveHTML();

Вам нужно будет выполнить некоторое сопоставление там, а также сбросить значение ноды $ f, но, надеюсь, это сделает его немного более понятным.

Кроме того, не устанавливайте HTML в nodeValue напрямую, потому что он будет запускать htmlentities () для всех установленных вами HTML. Вот почему я создаю новый элемент выше. Если вам абсолютно необходимо установить HTML в nodeValue, вам следует создать DocumentFragment Object

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...