Pregunta

Ok, la otra noche tuve esta pequeña idea para crear una clase auxiliar para DOMDOCUMENT que imita, hasta cierto punto, la capacidad de jQuery para manipular el DOM de una cadena basada en HTML o XML. En lugar de selectores CSS, se utiliza XPath. Por ejemplo:

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

Esto invocaría una función de devolución de llamada en cada nodo resultante. Desafortunadamente, la versión PHP & Lt; 5.3.x no admite funciones o cierres lambda, por lo que me veo obligado a hacer algo un poco más así por el momento:

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

Todo está funcionando muy bien en este momento y creo que este proyecto sería útil para mucha gente, pero estoy atascado con una de las funciones. Estoy intentando imitar el método 'reemplazar' de jQuery. Usando el siguiente código, puedo lograr esto fácilmente aplicando el siguiente método:

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

El código detrás de este método es:

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

    return $this;
}

Ahora, esto funciona. Reemplaza cada elemento resultante con una versión clonada de $ Content. El problema es que los agrega al final de la lista de hijos del nodo principal. La pregunta es, ¿cómo clono este elemento para reemplazar otros elementos, sin perder la posición original en el DOM?

Estaba pensando en hacer ingeniería inversa del nodo que debía reemplazar. Básicamente, copiando valores, atributos y nombre del elemento desde $ Content, pero no puedo cambiar el nombre real del elemento del elemento objetivo.

La reflexión podría ser una posibilidad, pero debe haber una manera más fácil de hacerlo.

¿Alguien?

¿Fue útil?

Solución

Use replaceChild en lugar de appendChild / removeChild.

Otros consejos

Busque si $ element tiene una nextsibbling antes de eliminar, si es así, haga una inserción Antes del próximo hermano, de lo contrario simplemente agregue.

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

Sin embargo, no se ha probado por completo.

O como AnthonyWJones sugirió replaceChild , big oomph cómo perdí ese momento :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top