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.
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
Pasé por el mismo problema. Cambió a DOM y es mucho más agradable. – Keyo