2009-04-20 22 views
6

Tengo un niño $ SimpleXMLElement objeto, y una matriz de objetos $ SimpleXMLElement.En SimpleXML, ¿cómo puedo agregar un SimpleXMLElement existente como elemento secundario?

¿Cómo puedo agregar $ niño como hijo de padres $? ¿Hay alguna forma de hacerlo sin convertir a DOM y viceversa?

El método addChild() sólo parece que me permiten crear un nuevo elemento, vacío, pero eso no ayuda cuando el elemento que desea agregar $ hijo también tiene hijos. Estoy pensando que podría necesitar recurrencia aquí.

Respuesta

6

Sé que esto no es la respuesta más útil, pero sobre todo porque va a crear/modificar XML, me gustaría cambiar a usar las funciones DOM. SimpleXML es bueno para acceder a documentos simples, pero bastante pobre para cambiarlos.

Si SimpleXML te trata amablemente en todos los demás lugares y quieres seguir con eso, aún tienes la opción de saltar a las funciones DOM temporalmente para realizar lo que necesitas y luego saltar de nuevo, usando dom_import_simplexml() y simplexml_import_dom(). No estoy seguro de cuán eficiente es esto, pero podría ayudarte.

+0

Afortunadamente es lo suficientemente temprano como para no perder demasiado tiempo convirtiendo todo en DOM (probablemente demore una hora). Creo que esta es la solución con la que probablemente terminaré, a menos que alguien más tenga una idea realmente sorprendente. ¡Gracias por la respuesta! – thomasrutter

+1

Pasé por el mismo problema. Cambió a DOM y es mucho más agradable. – Keyo

0

Dejando esto aquí ya que acabo de tropezar con esta página y encontré que SimpleXML ahora admite esta funcionalidad a través del ::addChild method.

Puede utilizar este método para hacer añadir ningún elemento de conexión en cascada, así:

$xml->addChild('parent'); 
$xml->parent->addChild('child'); 
$xml->parent->child->addChild('child_id','12345'); 
+0

Esto no responde a la pregunta ya que la pregunta era ho agregar un niño que ** ya es un nodo SimpleXMLElement **. – richard

1

En realidad, es posible (de forma dinámica) si se fijan bien de cómo se defina addChild(). I usado esta técnica para convertir cualquier matriz en XML usando la recursión y pasar por referencia

  • addChild() rendimientos SimpleXMLElement de niño añadido.
  • para añadir nodo hoja, utilice $xml->addChilde($nodeName, $nodeValue).
  • para agregar un nodo que puede tener subnodo o valor, use $xml->addChilde($nodeName), no se pasa ningún valor a addChild(). ¡Esto resultará en tener un subnodo de tipo SimpleXMLElement! no es una cadena !

XML de destino

<root> 
    <node>xyz</node> 
    <node> 
     <node>aaa</node> 
     <node>bbb</node> 
    </node> 
</root> 

Código:

$root = new SimpleXMLElement('<root />'); 
//add child with name and string value. 
$root.addChild('node', 'xyz'); 
//adds child with name as root of new SimpleXMLElement 
$sub = $root->addChild('node'); 
$sub.addChild('node', 'aaa'); 
$sub.addChild('node', 'bbb'); 
+0

Esto no responde la pregunta. La pregunta era cómo ** agregar un niño que ya es un SimpleXMLElement **. – richard

7

Desafortunadamente SimpleXMLElement no ofrece nada para traer dos elementos juntos. Como @nickf wrote, es más adecuado para la lectura que para la manipulación. Sin embargo, la extensión hermana DOMDocument es para editar y puede unir ambas a través del dom_import_simplexml(). Y @salathe shows in a related answer cómo funciona esto para elementos SimpleXMLE específicos.

continuación se muestra cómo este trabajo con control de entrada y algunas opciones más. Lo hago con dos ejemplos.El primer ejemplo es una función para insertar una cadena XML:

/** 
* Insert XML into a SimpleXMLElement 
* 
* @param SimpleXMLElement $parent 
* @param string $xml 
* @param bool $before 
* @return bool XML string added 
*/ 
function simplexml_import_xml(SimpleXMLElement $parent, $xml, $before = false) 
{ 
    $xml = (string)$xml; 

    // check if there is something to add 
    if ($nodata = !strlen($xml) or $parent[0] == NULL) { 
     return $nodata; 
    } 

    // add the XML 
    $node  = dom_import_simplexml($parent); 
    $fragment = $node->ownerDocument->createDocumentFragment(); 
    $fragment->appendXML($xml); 

    if ($before) { 
     return (bool)$node->parentNode->insertBefore($fragment, $node); 
    } 

    return (bool)$node->appendChild($fragment); 
} 

Esta función ejemplar permite anexar XML o insertarlo antes de que un determinado elemento, incluyendo el elemento raíz. Después de averiguar si hay algo que agregar, utiliza DOMDocument funciones y métodos para insertar el XML como un fragmento de documento, también se describe en How to import XML string in a PHP DOMDocument. El ejemplo de uso:

$parent = new SimpleXMLElement('<parent/>'); 

// insert some XML 
simplexml_import_xml($parent, "\n <test><this>now</this></test>\n"); 

// insert some XML before a certain element, here the first <test> element 
// that was just added 
simplexml_import_xml($parent->test, "<!-- leave a comment -->\n ", $before = true); 

// you can place comments above the root element 
simplexml_import_xml($parent, "<!-- this works, too -->", $before = true); 

// but take care, you can produce invalid XML, too: 
// simplexml_add_xml($parent, "<warn><but>take care!</but> you can produce invalid XML, too</warn>", $before = true); 

echo $parent->asXML(); 

Esto da el siguiente resultado:

<?xml version="1.0"?> 
<!-- this works, too --> 
<parent> 
    <!-- leave a comment --> 
    <test><this>now</this></test> 
</parent> 

El segundo ejemplo es la inserción de un SimpleXMLElement. Hace uso de la primera función si es necesario. Básicamente, verifica si hay algo que hacer y qué tipo de elemento debe importarse. Si se trata de un atributo, se acaba de añadir que, si se trata de un elemento, se serializa en XML y luego se añade al elemento padre como XML:

/** 
* Insert SimpleXMLElement into SimpleXMLElement 
* 
* @param SimpleXMLElement $parent 
* @param SimpleXMLElement $child 
* @param bool $before 
* @return bool SimpleXMLElement added 
*/ 
function simplexml_import_simplexml(SimpleXMLElement $parent, SimpleXMLElement $child, $before = false) 
{ 
    // check if there is something to add 
    if ($child[0] == NULL) { 
     return true; 
    } 

    // if it is a list of SimpleXMLElements default to the first one 
    $child = $child[0]; 

    // insert attribute 
    if ($child->xpath('.') != array($child)) { 
     $parent[$child->getName()] = (string)$child; 
     return true; 
    } 

    $xml = $child->asXML(); 

    // remove the XML declaration on document elements 
    if ($child->xpath('/*') == array($child)) { 
     $pos = strpos($xml, "\n"); 
     $xml = substr($xml, $pos + 1); 
    } 

    return simplexml_import_xml($parent, $xml, $before); 
} 

Esta función ejemplar tiene la lista de elementos a normalizar y atributos comunes en Simplexml. Es posible que desee cambiar para insertar múltiples SimpleXMLElements a la vez, pero como el ejemplo de uso muestra a continuación, mi ejemplo no soporta que (vea el ejemplo de atributos):

// append the element itself to itself 
simplexml_import_simplexml($parent, $parent); 

// insert <this> before the first child element (<test>) 
simplexml_import_simplexml($parent->children(), $parent->test->this, true); 

// add an attribute to the document element 
$test = new SimpleXMLElement('<test attribute="value" />'); 
simplexml_import_simplexml($parent, $test->attributes()); 

echo $parent->asXML(); 

Esta es una continuación de la primera usage- ejemplo. Por lo tanto, la salida actual es:

<?xml version="1.0"?> 
<!-- this works, too --> 
<parent attribute="value"> 
    <!-- leave a comment --> 
    <this>now</this><test><this>now</this></test> 
<!-- this works, too --> 
<parent> 
    <!-- leave a comment --> 
    <test><this>now</this></test> 
</parent> 
</parent> 

espero que esto sea útil. Puede find the code in a gist y como online demo/PHP version overview.

Cuestiones relacionadas