PHP - SimpleXML - AddChild с другим элементом SimpleXMLElement - PullRequest
26 голосов
/ 24 января 2011

Я пытаюсь создать довольно сложный документ XML.

У меня есть несколько разделов XML-документа, которые повторяются. Я подумал, что буду использовать несколько строковых шаблонов в качестве базового документа для разделов и создавать экземпляры элементов XML с использованием simplexml_load_string.

Итак, у меня есть один экземпляр SimpleXMLElement в качестве базового документа

$ root = simplexml_load_string ($ template_root);

затем я перебираю некоторые элементы в моей базе данных, создаю новый SimpleXMLElement, что-то вроде этого:

для (бла бла бла):

$ item = simplexml_load_string ($ template_item); // делать вещи с предметом // пытаемся добавить элемент в корневой документ ..
// Застрял здесь .. не могу сделать $ root-> items-> addChild ($ item)

ENDFOR;

Я не могу вызвать addChild, потому что он просто ожидает имя и значение тега ... вы не можете добавитьChild другой SimpleXMLElement.

Я что-то здесь упускаю? кажется действительно глупым, что addChild не может принять SimpleXMLELement в качестве параметра.

Есть ли другой способ сделать это? (кроме использования другой библиотеки xml)

Ответы [ 3 ]

56 голосов
/ 24 января 2011

Насколько я знаю, вы не можете сделать это с SimpleXML, потому что addChild не делает глубокую копию элемента (необходимость указать имя тега может быть легко преодолена путем вызова SimpleXMLElement::getName()).

Одним из решений было бы использование DOM вместо:

С этой функцией:

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

Мы имеем для

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

выход

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

См. Также некоторые комментарии пользователей, которые используют рекурсивные функции и addChild, например this .

15 голосов
/ 30 июля 2012

Вы можете использовать эту функцию, которая основана на создании дочерних элементов с атрибутами из источника:

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";

Это даст:

<?xml version="1.0"?>
<root><content><p a="aaaaaaa">a paragraph</p><p>another p<br/></p></content></root>
8 голосов
/ 06 мая 2013

В примере xml_adopt () не сохраняются узлы пространства имен.
Мое редактирование было отклонено, потому что оно сильно изменилось? был спам?

Вот версия xml_adopt (), которая сохраняет пространства имен.

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);
      }
    }
}

(редактировать: пример добавлен)

$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>'
...