Pregunta

Necesito imprimir arbitraria objetos SimpleXML de una manera específica, con un manejo especial de nodos de atributo.

El problema es que los elementos y atributos SimpleXML parecen utilizar exactamente la misma clase, atributo del nodo siquiera pretende apoyar método attributes() y SimpleXML esconde sus componentes internos, por lo que no parece haber ninguna manera de saber el tipo de nodo ( suficientes para generar XML y reparsing él).

Ambos dan idénticos resultado:

$element = new SimpleXMLElement('<foo>test</foo>');
echo $element;
print_r($element);

$element = new SimpleXMLElement('<foo attr="test" />');
echo $element['attr'];
print_r($element['attr']);

¿Hay una propiedad / método oculto que permite identificar el tipo de nodo en SimpleXML? Equivalente de $node->nodeType o $node instanceof DOMAttr de DOM? (No puedo utilizar DOM lugar, el apoyo a SimpleXML es requisito básico).

¿Fue útil?

Solución

No hay propiedades integradas en SimpleXMLElement que permitirían que decir a estos pedazos.

Como otros han sugerido dom_import_simplexml puede ser apropiado, sin embargo, que la función puede cambiar los nodos sobre la marcha a veces, por ejemplo, si se pasa en una lista de childNodes o childNodes con nombre, que se llevará a aquellos y los convierten en el primer elemento.

Si se trata de una lista vacía, por ejemplo, no hay atributos regresaron de attributes() o no existente childNodes nombradas, se le dará una advertencia indicando un tipo de nodo no válido se le ha dado:

  

Advertencia: dom_import_simplexml (): Invalid Nodetype para importar

Así que si usted necesita este preciso con un ágil booleano true / false, aquí es cómo funciona con simplexml:

$isElement   = $element->xpath('.') == array($element);

$isAttribute = $element[0] == $element
               and $element->xpath('.') != array($element);

Funciona de manera similar con las listas de atributos y listas de elementos, he solo blogs sobre esto en la mañana , es necesario tener algún conocimiento específico acerca de qué evaluar para qué, así que creó un cheatsheet para ello:

+------------------+---------------------------------------------+
| TYPE             | TEST                                        |
+------------------+---------------------------------------------+
| Element          | $element->xpath('.') == array($element)     |
+------------------+---------------------------------------------+
| Attribute        | $element[0] == $element                     |
|                  | and $element->xpath('.') != array($element) |
+------------------+---------------------------------------------+
| Attributes       | $element->attributes() === NULL             |
+------------------+---------------------------------------------+
| Elements         | $element[0] != $element                     |
|                  | and $element->attributes() !== NULL         |
+------------------+---------------------------------------------+
| Single           | $element[0] == $element                     |
+------------------+---------------------------------------------+
| Empty List       | $element[0] == NULL                         |
+------------------+---------------------------------------------+
| Document Element | $element->xpath('/*') == array($element)    |
+------------------+---------------------------------------------+

Otros consejos

Sí, hay un camino. Bueno, nada elegante que se puede recuperar a través de la API, pero en algún lugar de las entrañas de la SimpleXML es hacer el seguimiento de lo que es y hace una diferencia, por ejemplo, cuando se llama a funciones tales como getName () o asXML ().

$element = new SimpleXMLElement('<foo>test</foo>');
print_r($element->getName());
print_r($element->asXML());
echo "------------------\n";
$element = new SimpleXMLElement('<foo attr="test" />');
$at = $element['attr'];
print_r($at->getName());
print_r($at->asXML());

foo
<?xml version="1.0"?>
<foo>test</foo>
------------------
attr 
attr="test"

El código no va a ganar un concurso de belleza, pero al menos puede hacerlo.

Usando lo palako señaló, una función como esta podría funcionar:

function is_attribute($node) {
    return !($node->asXML()[0] == "<")
}

Es necesario SimpleXMLElement :: atributos :

function xml_out($el) {
    $name = $el->getName();
    echo '<'. $name;

    if (count($el->attributes())) {
        foreach ($el->attributes() as $a=>$v) {
            echo ' '. ((string)$a) . '="' . htmlspecialchars((string)$v) . '"';
        }
    }

    echo '>'. (string)$el;

    if (count($el->children())) {
        foreach($el->children() as $c) {
            xml_out($c);
        }
    }
    echo '</'. $name . '>';

}

Es posible que necesite un poco de ajuste.

  

¿Hay una propiedad / método oculto que permite identificar el tipo de nodo en SimpleXML? Equivalente de DOM de $ node-> nodeType o nodo $ instanceof DOMAttr? (No puedo usar DOM lugar, el apoyo a SimpleXML es requisito básico)

La respuesta es no ... y sí. SimpleXML no tiene una propiedad tal, pero aquí está la buena noticia: SimpleXML y DOM son dos caras de la misma moneda. (la moneda es libxml;)) Usted no tiene que elegir uno u otro, puede utilizar tanto! Puede activar SimpleXMLElement en DOMNode y viceversa. En su caso, usted podría hacer algo como:

$element = new SimpleXMLElement('<foo attr="test" />');
$is_attr = (dom_import_simplexml($element['attr'])->nodeType === XML_ATTRIBUTE_NODE);

Si eso es algo que se hace a menudo, o que no quieren manejar el malabarismo DOM / SimpleXML, se puede echar un vistazo a SimpleDOM .

$element = new SimpleDOM('<foo attr="test" />');
$is_attr = ($element['attr']->nodeType() === XML_ATTRIBUTE_NODE);

Desafortunadamente no hay una propiedad oculta o un método que permite identificar el tipo de nodo en SimpleXML. SimpleXML sólo utiliza una Clase y los elementos no tienen nada que apuntan a sus padres. Si intenta la reflexión por debajo de usted verá que no hay nada que distinga elemento o atributo.

$element = new SimpleXMLElement('<foo>test</foo>');
echo ReflectionObject::export($element);

$element = new SimpleXMLElement('<foo attr="test">test</foo>');
echo ReflectionObject::export($element['attr']);

Sin embargo, si un elemento tiene atributos que puede detectar eso. Por lo que tendría que asumir que todos los elementos tienen aprobadas en atributos. Con esa suposición se podía distinguirlos.

$element = new SimpleXMLElement('<foo attr="test">test</foo>');

echo ReflectionObject::export($element);
echo ReflectionObject::export($element['attr']);

Esto es lo mejor que puedo llegar a. Recuerde que es posible que un elemento sin atributos para después volver falsa con esto.

function isNotAttribute($simpleXML)
{
  return (count($simpleXML->attributes()) > 0);
}

$element = new SimpleXMLElement('<foo attr="test">test</foo>');
var_dump(isNotAttribute($element));
var_dump(isNotAttribute($element['attr']));

// returns
bool(true)
bool(false)
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top