En SimpleXML, ¿cómo puedo añadir una SimpleXMLElement existente como un elemento hijo?

StackOverflow https://stackoverflow.com/questions/767327

  •  12-09-2019
  •  | 
  •  

Pregunta

Tengo un niño $ SimpleXMLElement objeto, y un objeto SimpleXMLElement $ matriz.

¿Cómo puedo agregar $ niño como hijo de padres $? ¿Hay alguna manera de hacer esto sin necesidad de convertir a DOM y la espalda?

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 recursividad aquí.

¿Fue útil?

Solución

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 acceso a los mismos simples, pero bastante pobre en el cambio de ellos.

Si SimpleXML es tratar amablemente en todos los demás lugares y que desea seguir con ella, todavía tiene la opción de saltar por encima de las funciones DOM temporalmente para llevar a cabo lo que necesita y luego saltar hacia atrás de nuevo, usando dom_import_simplexml() y simplexml_import_dom() . No estoy seguro de lo eficiente que es esto, pero podría ayudarle.

Otros consejos

SimpleXMLElement no ofrece nada para traer dos elementos juntos. Como @nickf escribió , es más apropiado para la lectura que para la manipulación. Sin embargo, la extensión DOMDocument hermana es para la edición y se puede llevar a ambos a la vez a través de dom_import_simplexml() . Y @salathe muestra en una respuesta relacionada cómo esto funciona para SimpleXMLElements específicos.

A continuación se muestra cómo este trabajo con el registro 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 descubrir si hay algo que añadir, que hace uso de DOMDocument funciones y métodos para insertar el código XML como un fragmento de documento, que es también describen en Cómo importar cadena XML en un 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. Se hace uso de la primera función, si es necesario. Básicamente se comprueba si hay algo que ver en absoluto y qué tipo de elemento se va a importar. 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 hace lista de elementos normalizar y atributos como común 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 admite que (véase 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 uso-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 encontrar el código en una esencia y como demostración en línea / versión de PHP visión general .

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() vuelve SimpleXMLElement del niño añadido.
  • para añadir nodo hoja, utilice $xml->addChilde($nodeName, $nodeValue).
  • para añadir un nodo que puede tener subnodo o valor, el uso $xml->addChilde($nodeName), ningún valor se pasa a addChild(). Esta dará lugar a tener un nodo secundario de tipo SimpleXMLElement! No un 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');

Dejando esto aquí como me tropecé con esta página y se encontró que SimpleXML ahora soporta esta funcionalidad a través de la :: método addChild .

Puede utilizar este método para no 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');
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top