2010-07-29 9 views
7

sagt ich XML haben:PHP SimpleXML: insert Knoten an bestimmten Position

<root> 
    <nodeA /> 
    <nodeA /> 
    <nodeA /> 
    <nodeC /> 
    <nodeC /> 
    <nodeC /> 
</root> 

Wie kann ich "NodeB" zwischen A und Cs einfügen? In PHP, vorzugsweise über SimpleXML? Wie:

+1

Ich bin mir nicht sicher, dass Sie können. Aus der Dokumentation geht hervor, dass SimpleXML für eine wirklich einfache Manipulation gedacht ist. – MvanGeest

+0

Kann ich Cs nicht irgendwo anders speichern, sie entfernen, B hinzufügen und Cs von diesem temporären Speicherort hinzufügen? Ich bin einfach nicht sehr versiert in PHP .... –

Antwort

13

Die folgende ist eine Funktion zum Einfügen eines neuen SimpleXMLElement nach einem anderen SimpleXMLElement. Da dies mit SimpleXML nicht direkt möglich ist, verwendet es einige Klassen/Methoden hinter den Kulissen, um die Arbeit zu erledigen.

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

Und ein Beispiel dafür, wie könnte es (spezifisch für Ihre Frage) verwendet werden:

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

Wenn Sie wollen/müssen eine Erklärung wie das funktioniert (der Code ist ziemlich einfach, aber könnte ausländische Konzepte beinhalten), einfach fragen.

+0

Ist es mir, oder ist der $ sxe-Parameter in simplexml_insert_after nie verwendet? – GolezTrol

+1

Du bist es nicht, warum nicht Spaß bei der Beantwortung von Fragen? :) – salathe

+0

Ja, warum nicht. :) Danke für deine Antwort, b.tw.w Ich nahm die Erlaubnis, sie zu benutzen, um meine eigene zu konstruieren. :) – GolezTrol

4

Salathes Antwort hat mir geholfen, aber da ich die addChild-Methode von SimpleXMLElement verwendet habe, suchte ich nach einer Lösung, um Kinder als erstes Kind transparenter zu machen. Die Lösung besteht darin, dass die DOM-basierte Funktionalität zu nehmen und es in einer Unterklasse von SimpleXMLElement verstecken:

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

Immerhin ermöglicht SimpleXML angeben, welche Elementklasse zu verwenden:

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

Jetzt können Sie insertChildFirst nennen auf ein beliebiges Element, um das neue Kind als erstes Kind einzufügen. Die Methode gibt das neue Element als SimpleXML-Element zurück, sodass es ähnlich wie addChild verwendet wird. Natürlich wäre es leicht möglich, eine insertChild-Methode zu erstellen, die es erlaubt, ein genaues Element anzugeben, um das Element vorher einzufügen, aber da ich das jetzt nicht brauche, habe ich mich entschieden, das nicht zu tun.