Использование DOMXPath для замены узла при сохранении его положения - PullRequest
0 голосов
/ 13 марта 2009

Ладно, однажды вечером у меня появилась эта замечательная маленькая идея создать вспомогательный класс для DOMDOCUMENT, который в некоторой степени имитирует способность jQuery манипулировать DOM строки на основе HTML или XML. Вместо селекторов CSS используется XPath. Например:

$Xml->load($source)
    ->path('//root/items')
    ->each(function($Context)
    {
        echo $Context->nodeValue;
    });

Это вызовет функцию обратного вызова на каждом полученном узле. К сожалению, версия PHP <5.3.x не поддерживает лямбда-функции или замыкания, поэтому на данный момент я вынужден сделать что-то более похожее на это: </p>

$Xml->load($source)
    ->path('//root/items')
    ->walk('printValue', 'param1', 'param2');

В настоящее время все работает отлично, и я думаю, что этот проект был бы полезен для многих людей, но я застрял с одной из функций. Я пытаюсь имитировать метод замены jQuery. Используя следующий код, я могу легко это сделать, применив следующий метод:

$Xml->load($source)
    ->path('//root/items')
    ->replace($Xml->createElement('foo', 'bar')); // can be an object, string or XPath pattern

Код этого метода:

public function replace($Content)
{
    foreach($this->results as $Element)
    {
        $Element->parentNode->appendChild($Content->cloneNode(true));
        $Element->parentNode->removeChild($Element);
    }

    return $this;
}

Теперь это работает. Он заменяет каждый результирующий элемент клонированной версией $ Content. Проблема в том, что он добавляет их в конец списка дочерних узлов родительского узла. Вопрос в том, как мне клонировать этот элемент для замены других элементов, сохраняя при этом исходную позицию в DOM?

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

Отражение может быть возможным, но должен быть более простой способ сделать это.

* +1018 * Любой

Ответы [ 2 ]

2 голосов
/ 13 марта 2009

Используйте replaceChild вместо appendChild / removeChild.

0 голосов
/ 13 марта 2009

Поиск, если $ element имеет nextsibbling перед удалением, если это так, сделайте insertB перед тем, как следующий брат или сестра просто добавятся.

public function replace($Content)
{
        foreach($this->results as $Element)
        {
                if ($Element->nextSibling) {
                    $NextSiblingReference = $Element->nextSibling;
                    $Element->parentNode->insertBefore($Content->cloneNode(true),$NextSiblingReference);
                }
                else {
                    $Element->parentNode->appendChild($Content->cloneNode(true));   
                }
                $Element->parentNode->removeChild($Element);
        }

        return $this;
}

Полностью не проверено.

Или, как предложил Энтони Джонс replaceChild , большой oomph как я пропустил этот момент:)

...