PHP-SimpleXML-AddChild avec un autre SimpleXMLElement

j'essaie de construire un document XML assez complexe.

j'ai un tas de sections du document XML qui se répète. Je pensais utiliser plusieurs modèles de chaîne de caractères comme document de base pour les sections et créer des instances D'éléments XML en utilisant simplexml_load_string.

J'ai donc une instance de SimpleXMLElement comme document de base

$racine = simplexml_load_string ($template_root);

puis je boucle certains éléments dans ma base de données, créer un nouveau SimpleXMLElement, quelque chose comme ceci:

pour (bla bla bla):

$ item = simplexml_load_string($template_item); // faire quelque chose avec l'élément // essayez d'ajouter un élément au document racine..

// Collé ici.. ne peux pas faire $racine->items->addChild($item)

finpour;

Je ne peux pas appeler addChild parce qu'il attend juste un nom et une valeur d'étiquette.. vous ne pouvez pas addChild un autre SimpleXMLElement.

est-ce que je rate quelque chose ici? cela semble vraiment stupide que addChild ne puisse pas prendre un élément SimpleXML comme paramètre.

Est-il un autre moyen pour ce faire? (mis à part l'utilisation d'une lib xml différente)

25
demandé sur Ben 2011-01-24 08:11:02

3 réponses

autant que je sache, vous ne pouvez pas le faire avec SimpleXML parce que addChild ne fait pas une copie profonde de l'élément (étant nécessaire pour spécifier le nom de la balise peut facilement être surmonté en appelant SimpleXMLElement::getName()).

Une solution serait d'utiliser des DOM à la place:

Avec cette fonction:

function sxml_append(SimpleXMLElement $to, SimpleXMLElement $from) {
    $toDom = dom_import_simplexml($to);
    $fromDom = dom_import_simplexml($from);
    $toDom->appendChild($toDom->ownerDocument->importNode($fromDom, true));
}

Nous avons

<?php
header("Content-type: text/plain");
$sxml = simplexml_load_string("<root></root>");

$n1 = simplexml_load_string("<child>one</child>");
$n2 = simplexml_load_string("<child><k>two</k></child>");

sxml_append($sxml, $n1);
sxml_append($sxml, $n2);

echo $sxml->asXML();

la sortie

<?xml version="1.0"?>
<root><child>one</child><child><k>two</k></child></root>

Voir aussi certains commentaires d'utilisateurs qui utilisent des fonctions récursives et addChild, e.g. ce .

54
répondu Artefacto 2011-01-24 05:35:58

vous pouvez utiliser cette fonction qui est basée dans la création des enfants avec des attributs de la source:

function xml_adopt($root, $new) {
    $node = $root->addChild($new->getName(), (string) $new);
    foreach($new->attributes() as $attr => $value) {
        $node->addAttribute($attr, $value);
    }
    foreach($new->children() as $ch) {
        xml_adopt($node, $ch);
    }
}

$xml = new SimpleXMLElement("<root/>");
$child = new SimpleXMLElement("<content><p a=\"aaaaaaa\">a paragraph</p><p>another <br/>p</p></content>");

xml_adopt($xml, $child);
echo $xml->asXML()."\n";

Ceci va produire:

<?xml version="1.0"?>
<root><content><p a="aaaaaaa">a paragraph</p><p>another p<br/></p></content></root>
12
répondu Carlos C Soto 2012-07-30 18:40:20

l'exemple xml_adopt () ne préserve pas les noeuds d'espace de noms.

Mon montage a été rejeté parce qu'il a beaucoup changé? est ce que le spam?.

Voici une version de xml_adopt (), qui préserve les espaces de noms.

function xml_adopt($root, $new, $namespace = null) {
    // first add the new node
    // NOTE: addChild does NOT escape "&" ampersands in (string)$new !!!
    //  replace them or use htmlspecialchars(). see addchild docs comments.
    $node = $root->addChild($new->getName(), (string) $new, $namespace);
    // add any attributes for the new node
    foreach($new->attributes() as $attr => $value) {
        $node->addAttribute($attr, $value);
    }
    // get all namespaces, include a blank one
    $namespaces = array_merge(array(null), $new->getNameSpaces(true));
    // add any child nodes, including optional namespace
    foreach($namespaces as $space) {
      foreach ($new->children($space) as $child) {
        xml_adopt($node, $child, $space);
      }
    }
}

(edit: exemple ajoutée)

$xml = new SimpleXMLElement(
  '<?xml version="1.0" encoding="utf-8"?>
  <rss version="2.0" xmlns:media="http://search.yahoo.com/mrss/">
  <channel></channel></rss>');

$item = new SimpleXMLElement(
  '<item xmlns:media="http://search.yahoo.com/mrss/">
    <title>Slide Title</title>
    <description>Some description</description>
    <link>http://example.com/img/image.jpg</link>
    <guid isPermaLink="false">A1234</guid>
    <media:content url="http://example.com/img/image.jpg" medium="image" duration="15">
    </media:content>
  </item>');

$channel = $xml->channel;
xml_adopt($channel, $item);

// output:
// Note that the namespace is (correctly) only preserved on the root element
'<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
  <channel>
    <item>
      <title>Slide Title</title>
      <description>Some description</description>
      <link>http://example.com/img/image.jpg</link>
      <guid isPermaLink="false">A1234</guid>
      <media:content url="http://example.com/img/image.jpg" medium="image" duration="15">
        </media:content>
    </item>
  </channel>
</rss>'
7
répondu GDmac 2016-05-11 04:27:41