PHP - SimpleXML - AddChild with another SimpleXMLElement

后端 未结 3 950
野性不改
野性不改 2020-12-05 06:52

I\'m trying to build a rather complex XML document.

I have a bunch of sections of the XML document that repeats. I thought I\'d use multiple string templates as base

相关标签:
3条回答
  • 2020-12-05 07:18

    As far as I know, you can't do it with SimpleXML because addChild doesn't make a deep copy of the element (being necessary to specify the tag name can easily be overcome by calling SimpleXMLElement::getName()).

    One solution would be to use DOM instead:

    With this function:

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

    We have for

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

    the output

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

    See also some user comments that use recursive functions and addChild, e.g. this one.

    0 讨论(0)
  • 2020-12-05 07:32

    You could use this function that is based in creating the children with attributes from the 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";
    

    This will produce:

    <?xml version="1.0"?>
    <root><content><p a="aaaaaaa">a paragraph</p><p>another p<br/></p></content></root>
    
    0 讨论(0)
  • 2020-12-05 07:39

    The xml_adopt() example doesn't preserve namespace nodes.
    My edit was rejected because it changed to much? was spam?.

    Here is a version of xml_adopt() that preserves namespaces.

    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: example added)

    $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>'
    
    0 讨论(0)
提交回复
热议问题