PHP SimpleXML: insert node at certain position

前端 未结 2 966
误落风尘
误落风尘 2020-11-28 14:47

say I have XML:


  
  
  
  
  
  



        
相关标签:
2条回答
  • 2020-11-28 15:26

    Salathe's answer did help me, but since I used the addChild method of SimpleXMLElement, I sought a solution to make inserting children as a first child more transparent. The solution is to take that DOM based functionality and hide it in a subclass of SimpleXMLElement:

    class SimpleXMLElementEx extends SimpleXMLElement
    {
        public function insertChildFirst($name, $value, $namespace)
        {
            // Convert ourselves to DOM.
            $targetDom = dom_import_simplexml($this);
            // Check for children
            $hasChildren = $targetDom->hasChildNodes();
    
            // Create the new childnode.
            $newNode = $this->addChild($name, $value, $namespace);
    
            // Put in the first position.
            if ($hasChildren)
            {
                $newNodeDom = $targetDom->ownerDocument->importNode(dom_import_simplexml($newNode), true);
                $targetDom->insertBefore($newNodeDom, $targetDom->firstChild);
            }
    
            // Return the new node.
            return $newNode;
        }
    }
    

    After all, SimpleXML allows to specify which element class to use:

    $xml = simplexml_load_file($inputFile, 'SimpleXMLElementEx');
    

    Now you can call insertChildFirst on any element to insert the new child as a first child. The method returns the new element as an SimpleXML element, so it's use is similar to addChild. Of course it would be easily possible to create an insertChild method that allows to specify an exact element to insert the item before, but since I don't need that right now, I decided not to.

    0 讨论(0)
  • 2020-11-28 15:30

    The following is a function to insert a new SimpleXMLElement after some other SimpleXMLElement. Since this isn't directly possible with SimpleXML, it uses some DOM classes/methods behind-the-scenes to get the job done.

    function simplexml_insert_after(SimpleXMLElement $insert, SimpleXMLElement $target)
    {
        $target_dom = dom_import_simplexml($target);
        $insert_dom = $target_dom->ownerDocument->importNode(dom_import_simplexml($insert), true);
        if ($target_dom->nextSibling) {
            return $target_dom->parentNode->insertBefore($insert_dom, $target_dom->nextSibling);
        } else {
            return $target_dom->parentNode->appendChild($insert_dom);
        }
    }
    

    And an example of how it might be used (specific to your question):

    $sxe = new SimpleXMLElement('<root><nodeA/><nodeA/><nodeA/><nodeC/><nodeC/><nodeC/></root>');
    // New element to be inserted
    $insert = new SimpleXMLElement("<nodeB/>");
    // Get the last nodeA element
    $target = current($sxe->xpath('//nodeA[last()]'));
    // Insert the new element after the last nodeA
    simplexml_insert_after($insert, $target);
    // Peek at the new XML
    echo $sxe->asXML();
    

    If you want/need an explanation of how this works (the code is fairly simple but might include foreign concepts), just ask.

    0 讨论(0)
提交回复
热议问题