www whatwg spec que org español php domdocument

whatwg - Depurar un objeto DOMDocument en PHP



www w3 org español (6)

Acabo de usar DOMDocument :: save. Es cojo que tenga que escribir en un archivo, pero lo que sea.

Estoy tratando de depurar un objeto DOMDocument grande y complejo en PHP. Idealmente, sería bueno si pudiera hacer que DOMDocument se imprimiera en un formato similar a una matriz.

DoMDocument:

$dom = new DOMDocument(); $dom->loadHTML("<html><body><p>Hello World</p></body></html>"); var_dump($dom); //or something equivalent

Esto produce

DOMDocument Object ( )

mientras que me gustaría que la salida

DOMDocument: html =>body ==>p ===>Hello World

O algo así. ¿Por qué no hay una depuración o salida útil para esto?


Aunque no lo he probado yo mismo, echa un vistazo a Zend_Dom , que forma parte de Zend Framework . La documentación y los ejemplos de la mayoría de los componentes de Zend Framework son realmente completos.


Esta respuesta probablemente sea un poco tarde, ¡pero me gustó tu pregunta!

PHP no tiene nada integrado directamente para resolver su problema, por lo que no hay volcado de XML o algo así.

Sin embargo, PHP tiene los RecursiveTreeIterator­Docs que se acercan bastante a su salida:

/-<html> /-<body> /-<p> /-Hello World

(se verá mejor si su estructura X (HT) ML parece más complicada).

Se usa bastante simple (como la mayoría de los iteradores) con un foreach :

$tree = new RecursiveTreeIterator($iterator); foreach($tree as $key => $value) { echo $value . "/n"; }

(Puedes envolver esto dentro de una función, así que solo necesitas llamar a la función)

Incluso esto parece simple, hay una advertencia: necesita un RecursiveIterator sobre el árbol DOMDocument . Como PHP no puede adivinar lo que necesita, debe estar envuelto en código. Tal como está escrito, encontré la pregunta interesante (y obviamente no has solicitado la salida XML), así que escribí un pequeño código que ofrece el iterador recursivo necesario. Así que, aquí vamos.

En primer lugar, es posible que no esté familiarizado con los iteradores en PHP. Eso no es un trato para usar el código que mostraré, ya que lo haré al revés , sin embargo, cuando considere ejecutar un código por su cuenta, considere si puede o no hacer uso de las capacidades de iterador que PHP tiene para ofrecer. . Escribo eso porque ayuda a resolver problemas comunes y a hacer componentes que no están realmente relacionados entre sí para que funcionen entre sí. Por ejemplo, RecursiveTreeIterator­Docs está integrado y funcionará con cualquier cosa que lo alimentes (e incluso puedes configurarlo). Sin embargo, se necesita un RecursiveIterator para operar.

Así que vamos a darle un RecursiveIterator que ofrece <tag> para DOMNodes que son etiquetas (elementos) y solo el text si son nodos de texto:

class DOMRecursiveDecoratorStringAsCurrent extends RecursiveIteratorDecoratorStub { public function current() { $node = parent::current(); $nodeType = $node->nodeType; switch($nodeType) { case XML_ELEMENT_NODE: return "<$node->tagName>"; case XML_TEXT_NODE: return $node->nodeValue; default: return sprintf(''(%d) %s'', $nodeType, $node->nodeValue); } } }

Esta clase DOMRecursiveDecoratorStringAsCurrent (el nombre es solo un ejemplo) hace uso de algún código abstracto en RecursiveIteratorDecoratorStub . Sin embargo, la parte importante es la función ::current que solo devuelve el nombre de DOMNode de un DOMNode entre bracketsWikipedia ( <> ) y el texto de los nodos de texto tal como están. Eso es lo que necesita su salida, así que eso es todo lo que necesita para codificar.

En realidad, esto no funciona hasta que también tenga el código abstracto, pero para visualizar el código de cómo se usa (la parte más interesante), veamos:

$iterator = new DOMRecursiveDecoratorStringAsCurrent($iterator); $tree = new RecursiveTreeIterator($iterator); foreach($tree as $key => $value) { echo $value . "/n"; }

Como se hizo al revés, por el momento tenemos la salida especificada en función de qué DOMNode se mostrará en el RecursiveTreeIterator . Bien hasta ahora, fácil de conseguir. Pero lo que falta es el código abstracto y cómo crear un RecursiveIterator en todos los nodos dentro de un elemento DOMElement . Simplemente obtenga una vista previa de todo el código cómo se invoca (como se escribió antes, puede poner esto en una función para que sea fácilmente accesible dentro de su código para propósitos de depuración. Probablemente una función llamada xmltree_dump ):

$dom = new DOMDocument(); $dom->loadHTML("<html><body><p>Hello World</p></body></html>"); $iterator = new DOMRecursiveIterator($dom->documentElement); $iterator = new DOMRecursiveDecoratorStringAsCurrent($iterator); $tree = new RecursiveTreeIterator($iterator); foreach($tree as $key => $value) { echo $value . "/n"; }

Entonces, ¿qué tenemos aquí además del código ya cubierto? Primero hay un DOMRecursiveIterator - y eso es todo. El resto del código es el código estándar de DOMDocument .

Así que vamos a escribir sobre DOMRecursiveIterator . Es el RecursiveIterator necesario que finalmente se necesita dentro de RecursiveTreeIterator . Está decorado para que el volcado del árbol en realidad imprima los identificadores entre paréntesis y el texto como está.

Probablemente vale la pena compartir el código de ahora:

class DOMRecursiveIterator extends DOMIterator implements RecursiveIterator { public function hasChildren() { return $this->current()->hasChildNodes(); } public function getChildren() { $children = $this->current()->childNodes; return new self($children); } }

Es una clase bastante corta con solo dos funciones. Estoy haciendo trampa aquí ya que esta clase también se extiende desde otra clase. Pero como está escrito, esto es al revés, así que esta clase realmente se encarga de la recursión: hasChildren y getChildren . Obviamente, incluso esas dos funciones no tienen mucho código, solo están mapeando la "pregunta" ( hasChildren ? hasChildren ?) En un DOMNode estándar. Si un nodo tiene hijos, bueno, diga sí o simplemente devuélvalos (y este es un iterador, devuélvalos en forma de iterador, de ahí el new self() ).

Entonces, como esto es bastante corto, después de ahorcarlo, simplemente continúe con la clase DOMIterator (los documentos implements RecursiveIterator son solo para hacerlo funcionar):

class DOMIterator extends IteratorDecoratorStub { public function __construct($nodeOrNodes) { if ($nodeOrNodes instanceof DOMNode) { $nodeOrNodes = array($nodeOrNodes); } elseif ($nodeOrNodes instanceof DOMNodeList) { $nodeOrNodes = new IteratorIterator($nodeOrNodes); } if (is_array($nodeOrNodes)) { $nodeOrNodes = new ArrayIterator($nodeOrNodes); } if (! $nodeOrNodes instanceof Iterator) { throw new InvalidArgumentException(''Not an array, DOMNode or DOMNodeList given.''); } parent::__construct($nodeOrNodes); } }

Este es el iterador base para DOMPHP , solo toma un DOMNode o un DOMNodeList para iterar. Esto suena un poco superfluo tal vez, ya que DOM es compatible con DOMNodeList , pero no es compatible con un RecursiveIterator y ya sabemos que necesitamos uno para RecursiveTreeIterator para la salida. Así que en su constructor se crea un Iterator y se pasa a la clase principal, que de nuevo es un código abstracto. Claro que voy a revelar este código en solo un minuto. Como esto es al revés, revisemos lo que se ha hecho hasta ahora:

  • RecursiveTreeIterator para la salida en forma de árbol.
  • DOMRecursiveDecoratorStringAsCurrent para la visualización de un DOMNode en el árbol
  • DOMRecursiveIterator y DOMIterator para iterar recursivamente en todos los nodos en un DOMDocument .

Esto en términos de definición como todo lo que se necesita, sin embargo, aún falta el código al que llamé resumen. Es solo una especie de código proxy simple, delega el mismo método a otro objeto. Un patrón relacionado se llama Decorador . Sin embargo, este es solo el código, primero el Iterator y luego el amigo RecursiveIterator :

abstract class IteratorDecoratorStub implements OuterIterator { private $iterator; public function __construct(Iterator $iterator) { $this->iterator = $iterator; } public function getInnerIterator() { return $this->iterator; } public function rewind() { $this->iterator->rewind(); } public function valid() { return $this->iterator->valid(); } public function current() { return $this->iterator->current(); } public function key() { return $this->iterator->key(); } public function next() { $this->iterator->next(); } } abstract class RecursiveIteratorDecoratorStub extends IteratorDecoratorStub implements RecursiveIterator { public function __construct(RecursiveIterator $iterator) { parent::__construct($iterator); } public function hasChildren() { return $this->getInnerIterator()->hasChildren(); } public function getChildren() { return new static($this->getInnerIterator()->getChildren()); } }

Eso no es nada mágico, es simplemente delegar las llamadas de método a su objeto heredado $iterator . Parece que la repetición y los iteradores son sobre repetición. Pongo esto en clases abstractas, así que solo necesito escribir este código muy simple una vez. Así que al menos yo no necesito repetirlo.

Estas dos clases abstractas son utilizadas por otras clases que ya han sido discutidas anteriormente. Porque son tan simples, lo dejé hasta aquí.

Bueno, mucho para leer hasta aquí, pero lo bueno es que eso es todo.

En resumen: PHP no tiene esta versión incorporada, pero puede escribir esto por su cuenta de manera bastante simple y reutilizable. Como se escribió anteriormente, es una buena idea xmltree_dump esto en una función llamada xmltree_dump para que pueda llamarse fácilmente con fines de depuración:

function xmltree_dump(DOMNode $node) { $iterator = new DOMRecursiveIterator($node); $decorated = new DOMRecursiveDecoratorStringAsCurrent($iterator); $tree = new RecursiveTreeIterator($decorated); foreach($tree as $key => $value) { echo $value . "/n"; } }

Uso:

$dom = new DOMDocument(); $dom->loadHTML("<html><body><p>Hello World</p></body></html>"); xmltree_dump($dom->documentElement);

lo único que se necesita es tener todas las definiciones de clase utilizadas incluidas / requeridas. Puede ponerlos en un archivo y usar require_once o integrarlos con un autocargador que probablemente esté usando. Código completo a la vez .

Si necesita editar la forma de salida, puede editar DOMRecursiveDecoratorStringAsCurrent o cambiar la configuración de RecursiveTreeIterator dentro de xmltree_dump . Espero que esto sea útil (incluso bastante largo, al revés es bastante directo).


Puedes engañar y usar JSON para inspeccionar la estructura convirtiéndola en una matriz.

print_r(json_decode(json_encode($node), true));


para un nodo dom, solo usa lo siguiente:

print_r(simplexml_import_dom($entry)->asXML());