En SimpleXML, comment puis-je ajouter un SimpleXMLElement existant comme un élément enfant?

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

  •  12-09-2019
  •  | 
  •  

Question

J'ai un objet SimpleXMLElement enfant $, et un objet SimpleXMLElement parent $.

Comment puis-je ajouter $ enfant comme un enfant de parent $? Est-il possible de le faire sans convertir en DOM et retour?

La méthode addChild () semble seulement pour me permettre de créer un nouveau élément vide, mais cela ne suffit pas quand l'élément que je veux ajouter $ enfant a aussi des enfants. Je pense que je pourrais avoir besoin récursion ici.

Était-ce utile?

La solution

Je sais que ce n'est pas le plus utile réponse, mais d'autant plus que vous créez / modifier XML, je passer à l'aide des fonctions DOM. SimpleXML est bon pour l'accès aux documents simples, mais assez pauvre à les changer.

Si SimpleXML vous traite gentiment dans tous les autres endroits et que vous voulez rester avec elle, vous avez toujours la possibilité de sauter par-dessus les fonctions DOM temporairement pour effectuer ce que vous devez, puis revenir en arrière à nouveau, en utilisant dom_import_simplexml() et simplexml_import_dom() . Je ne sais pas comment cela est efficace, mais il pourrait vous aider.

Autres conseils

SimpleXMLElement ne propose rien d'apporter deux éléments. Comme @nickf écrit , il est plus approprié pour la lecture que pour la manipulation. Cependant, l'extension sœur DOMDocument est pour l'édition et vous pouvez apporter les deux ensemble par dom_import_simplexml() . Et @salathe montre dans une réponse connexe comment cela fonctionne pour SimpleXMLElement spécifiques.

L'exemple suivant montre comment ce travail avec le contrôle d'entrée et quelques autres options. Je le fais avec deux exemples. Le premier exemple est une fonction d'insérer une chaîne 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);
}

Cette fonction exemplaire permet d'ajouter XML ou l'insérer avant un certain élément, y compris l'élément racine. Après avoir découvert s'il y a quelque chose à ajouter, il utilise DOMDocument Fonctions et méthodes pour insérer le XML comme un fragment de document, il est également décrit dans Comment importer chaîne XML dans un PHP DOMDocument. L'exemple d'utilisation:

$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();

Cela donne le résultat suivant:

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

Le deuxième exemple est l'insertion d'un SimpleXMLElement. Il utilise la première fonction si nécessaire. Il vérifie essentiellement s'il y a quelque chose à faire du tout et quel type d'élément doit être importé. Si elle est un attribut, il suffit d'ajouter, si elle est un élément, il sera sérialisé en XML et ensuite ajouté à l'élément parent au format 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);
}

Cette fonction exemplaire ne normalise la liste des éléments et attributs comme communs dans SimpleXML. Vous voudrez peut-être changer pour insérer plusieurs SimpleXMLElement à la fois, mais comme l'exemple d'utilisation ci-dessous montre, mon exemple ne supporte pas (voir l'exemple des attributs):

// 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();

Ceci est la suite du premier exemple d'utilisation. Par conséquent, la sortie est maintenant:

<?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>

J'espère que cela est utile. Vous pouvez trouver le code dans un essentiel et comme démo en ligne / aperçu version PHP .

En fait, il est possible (dynamique) si vous regardez attentivement la façon dont addChild() est défini. J'ai utilisé cette technique pour convertir tout tableau en XML en utilisant récursion et passer par référence

  • addChild() retourne SimpleXMLElement de l'enfant ajouté.
  • pour ajouter nœud feuille, utilisez $xml->addChilde($nodeName, $nodeValue).
  • pour ajouter un nœud qui peut avoir subnode ou de la valeur, l'utilisation $xml->addChilde($nodeName), aucune valeur est passée à addChild(). Cette entraînera à avoir un sous-noeud de type SimpleXMLElement! pas string!

XML cible

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

Code:

$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');

En quittant ce ici que je viens de tombé sur cette page et a constaté que SimpleXML prend désormais en charge cette fonctionnalité via

scroll top