Entfernen Sie ein untergeordnetes Element mit einem bestimmten Attribut in SimpleXML für PHP

Lesezeit: 9 Minuten

Entfernen Sie ein untergeordnetes Element mit einem bestimmten Attribut in
TimTowdi

Ich habe mehrere identische Elemente mit unterschiedlichen Attributen, auf die ich mit SimpleXML zugreife:

<data>
    <seg id="A1"/>
    <seg id="A5"/>
    <seg id="A12"/>
    <seg id="A29"/>
    <seg id="A30"/>
</data>

Ich muss eine bestimmte entfernen Seg Element, mit einer ID von “A12”, wie kann ich das tun? Ich habe versucht, das durchzuschleifen Seg Elemente und ungesetztting das spezifische, aber das funktioniert nicht, die Elemente bleiben.

foreach($doc->seg as $seg)
{
    if($seg['id'] == 'A12')
    {
        unset($seg);
    }
}

1646964849 705 Entfernen Sie ein untergeordnetes Element mit einem bestimmten Attribut in
hakre

Entgegen der landläufigen Meinung in den vorhandenen Antworten kann jeder Simplexml-Elementknoten allein und aus dem Dokument entfernt werden unset(). Der springende Punkt ist nur, dass Sie verstehen müssen, wie SimpleXML tatsächlich funktioniert.

Suchen Sie zuerst das Element, das Sie entfernen möchten:

list($element) = $doc->xpath('/*/seg[@id="A12"]');

Entfernen Sie dann das in dargestellte Element $element Sie setzen seine Selbstreferenz:

unset($element[0]);

Das funktioniert, weil das erste Element jedes Elements das Element selbst in Simplexml ist (Selbstreferenz). Das hat mit seiner magischen Natur zu tun, numerische Indizes repräsentieren die Elemente in jeder Liste (zB Eltern->Kinder), und sogar das einzelne Kind ist eine solche Liste.

Nicht-numerische String-Indizes repräsentieren Attribute (beim Array-Zugriff) oder Kind-Element(e) (beim Eigenschaften-Zugriff).

Daher numerische Indizes im Eigenschaftszugriff wie:

unset($element->{0});

Arbeit auch.

Mit diesem xpath-Beispiel ist es natürlich ziemlich einfach (in PHP 5.4):

unset($doc->xpath('/*/seg[@id="A12"]')[0][0]);

Der vollständige Beispielcode (Demo):

<?php
/**
 * Remove a child with a specific attribute, in SimpleXML for PHP
 * @link http://stackoverflow.com/a/16062633/367456
 */

$data=<<<DATA
<data>
    <seg id="A1"/>
    <seg id="A5"/>
    <seg id="A12"/>
    <seg id="A29"/>
    <seg id="A30"/>
</data>
DATA;


$doc = new SimpleXMLElement($data);

unset($doc->xpath('seg[@id="A12"]')[0]->{0});

$doc->asXml('php://output');

Ausgabe:

<?xml version="1.0"?>
<data>
    <seg id="A1"/>
    <seg id="A5"/>

    <seg id="A29"/>
    <seg id="A30"/>
</data>

  • Diese Selbstreferenztechnik wurde früher (November 2010) demonstriert in: an answer to “PHP SimpleXML – XPath-Knoten entfernen”.

    – hakre

    21. Mai 2013 um 14:23 Uhr

  • Und diese simplexml-Selbstreferenztechnik wurde früher (Juni 2010) demonstriert in: an answer to “Wie kann ich den Textwert von SimpleXmlElement festlegen, ohne das übergeordnete Element zu verwenden?”

    – hakre

    22. Juni 2013 um 8:20 Uhr

  • Sehr gut erklärte Antwort. Ein Detail, das ich nicht sofort zu schätzen wusste, ist, dass Sie XPath nicht einfach aus der Schleife nehmen können, weil das Löschen eines Elements innerhalb eines Normals foreach ( $doc->seg as $seg ) Schleife verwirrt den Iterator (Faustregel: Ändern Sie die Länge eines Iterators nicht mitten in der Schleife). Die XPath-Implementierung von SimpleXML hat dieses Problem nicht, weil ihre Ergebnisse ein gewöhnliches Array nicht verwandter Elemente sind.

    – IMSoP

    12. September 2013 um 20:06 Uhr


  • @IMSoP: Für alle Traversable und dieses Problem (Live-Listen), kann ich sehr empfehlen iterator_to_arraysetzen in SimpleXML-Iteratoren den Schlüsselparameter auf FALSE, da SimpleXMLElement den Tag-Namen als Schlüssel verwendet, der in einer solchen Auflistung häufig doppelt vorhanden ist, und diese Funktion dann nur den letzten dieser gleichnamigen Knoten zurückgeben würde, wenn der zweite Parameter dies nicht ist FALSE.

    – hakre

    30. September 2013 um 9:00 Uhr


  • Guter Tipp, gerade was den Extra-Parameter angeht. 🙂

    – IMSoP

    30. September 2013 um 9:21 Uhr

Entfernen Sie ein untergeordnetes Element mit einem bestimmten Attribut in
Stefan Gehrig

Während SimpleXML bietet eine Möglichkeit, XML-Knoten zu entfernen, seine Änderungsmöglichkeiten sind etwas eingeschränkt. Eine andere Lösung besteht darin, auf die Verwendung von zurückzugreifen Dom Verlängerung. dom_import_simplexml() hilft Ihnen bei der Konvertierung SimpleXMLElement in ein DOMElement.

Nur ein Beispielcode (getestet mit PHP 5.2.5):

$data="<data>
    <seg id="A1"/>
    <seg id="A5"/>
    <seg id="A12"/>
    <seg id="A29"/>
    <seg id="A30"/>
</data>";
$doc=new SimpleXMLElement($data);
foreach($doc->seg as $seg)
{
    if($seg['id'] == 'A12') {
        $dom=dom_import_simplexml($seg);
        $dom->parentNode->removeChild($dom);
    }
}
echo $doc->asXml();

Ausgänge

<?xml version="1.0"?>
<data><seg id="A1"/><seg id="A5"/><seg id="A29"/><seg id="A30"/></data>

Übrigens: Die Auswahl bestimmter Knoten ist viel einfacher, wenn Sie XPath verwenden (SimpleXMLElement->xpath):

$segs=$doc->xpath('//seq[@id="A12"]');
if (count($segs)>=1) {
    $seg=$segs[0];
}
// same deletion procedure as above

  • Vielen Dank dafür – anfangs war ich geneigt, diese Antwort zu vermeiden, da ich die Verwendung von DOM vermeiden wollte. Ich habe mehrere andere Antworten ausprobiert, die nicht funktionierten, bevor ich schließlich Ihre ausprobierte – die einwandfrei funktionierte. Für alle, die erwägen, diese Antwort zu vermeiden, probieren Sie sie zuerst aus und sehen Sie, ob sie nicht genau das tut, was Sie wollen. Ich denke, was mich abgeschreckt hat, war, dass ich nicht wusste, dass dom_import_simplexml() immer noch mit der gleichen zugrunde liegenden Struktur wie simplexml funktioniert, sodass alle Änderungen in einem sofort das andere beeinflussen, ohne dass geschrieben/gelesen oder neu geladen werden muss.

    – dimo414

    5. Juli 2010 um 2:01 Uhr

  • Beachten Sie, dass dieser Code nur das erste gefundene Element entfernt. Ich vermute, dass dies daran liegt, dass das Ändern der Daten während der Iteration die Position des Iterators ungültig macht, wodurch die foreach-Schleife beendet wird. Ich habe dies gelöst, indem ich die dom-importierten Knoten in einem Array gespeichert habe, das ich dann durchlaufen habe, um die Löschung durchzuführen. Keine tolle Lösung, aber es funktioniert.

    – Ryan Ballantyne

    12. September 2010 um 3:50 Uhr

  • Sie können SimpleXML-Elemente tatsächlich mit unset löschen. Eine Lösung finden Sie in der Antwort von posthy.

    – Francois Feugeas

    17. August 2011 um 16:05 Uhr


  • Eigentlich können Sie SimpleXML-Elemente mit unset löschen, aber es ist in meiner Antwort;) stackoverflow.com/a/16062633/367456

    – hakre

    17. April 2013 um 14:27 Uhr

  • Unset hat bei mir nicht funktioniert, aber die Dom-Methode hat sehr gut funktioniert. Dank dafür!

    – Jarvis

    20. Juli 2016 um 17:15 Uhr

1646964850 244 Entfernen Sie ein untergeordnetes Element mit einem bestimmten Attribut in
datasn.io

Deaktivieren Sie einfach den Knoten:

$str = <<<STR
<a>
  <b>
    <c>
    </c>
  </b>
</a>
STR;

$xml = simplexml_load_string($str);
unset($xml –> a –> b –> c); // this would remove node c
echo $xml –> asXML(); // xml document string without node c

Dieser Code wurde entnommen So löschen / entfernen Sie Knoten in SimpleXML.

  • Dies funktioniert nur, wenn der Knotenname in der Menge eindeutig ist. Wenn dies nicht der Fall ist, entfernen Sie am Ende alle Knoten mit demselben Namen.

    – Dallas

    6. Dezember 2012 um 16:34 Uhr

  • @Dallas: Was Sie kommentieren, ist richtig, aber es enthält auch die Lösung. Wie greife ich nur auf das erste Element zu? Siehe hier: stackoverflow.com/a/16062633/367456

    – hakre

    17. April 2013 um 14:30 Uhr


1646964851 400 Entfernen Sie ein untergeordnetes Element mit einem bestimmten Attribut in
Wittmann

Ich glaube, Stefans Antwort ist richtig. Wenn Sie nur einen Knoten entfernen möchten (und nicht alle übereinstimmenden Knoten), hier ein weiteres Beispiel:

//Load XML from file (or it could come from a POST, etc.)
$xml = simplexml_load_file('fileName.xml');

//Use XPath to find target node for removal
$target = $xml->xpath("//seg[@id=$uniqueIdToDelete]");

//If target does not exist (already deleted by someone/thing else), halt
if(!$target)
return; //Returns null

//Import simpleXml reference into Dom & do removal (removal occurs in simpleXML object)
$domRef = dom_import_simplexml($target[0]); //Select position 0 in XPath array
$domRef->parentNode->removeChild($domRef);

//Format XML to save indented tree rather than one line and save
$dom = new DOMDocument('1.0');
$dom->preserveWhiteSpace = false;
$dom->formatOutput = true;
$dom->loadXML($xml->asXML());
$dom->save('fileName.xml');

Beachten Sie, dass die Abschnitte XML laden… (zuerst) und XML formatieren… (zuletzt) ​​durch unterschiedlichen Code ersetzt werden können, je nachdem, woher Ihre XML-Daten stammen und was Sie mit der Ausgabe machen möchten; es sind die Abschnitte dazwischen, die einen Knoten finden und ihn entfernen.

Außerdem dient die if-Anweisung nur dazu, sicherzustellen, dass der Zielknoten existiert, bevor versucht wird, ihn zu verschieben. Sie können diesen Fall auf verschiedene Arten behandeln oder ignorieren.

1646964851 152 Entfernen Sie ein untergeordnetes Element mit einem bestimmten Attribut in
sonnengesicht45

Diese Arbeit für mich:

$data="<data>
<seg id="A1"/>
<seg id="A5"/>
<seg id="A12"/>
<seg id="A29"/>
<seg id="A30"/></data>";

$doc = new SimpleXMLElement($data);

$segarr = $doc->seg;

$count = count($segarr);

$j = 0;

for ($i = 0; $i < $count; $i++) {

    if ($segarr[$j]['id'] == 'A12') {
        unset($segarr[$j]);
        $j = $j - 1;
    }
    $j = $j + 1;
}

echo $doc->asXml();

  • +1 Dies ist erstaunlich perfekt für das, was es tut. Nein muss. Keine Aufregung.

    – Giacomo1968

    4. Oktober 2014 um 2:08 Uhr


Entfernen Sie ein untergeordnetes Element mit einem bestimmten Attribut in
Michal Tatarynowicz

Wenn Sie die Basisklasse SimpleXMLElement erweitern, können Sie diese Methode verwenden:

class MyXML extends SimpleXMLElement {

    public function find($xpath) {
        $tmp = $this->xpath($xpath);
        return isset($tmp[0])? $tmp[0]: null;
    }

    public function remove() {
        $dom = dom_import_simplexml($this);
        return $dom->parentNode->removeChild($dom);
    }

}

// Example: removing the <bar> element with id = 1
$foo = new MyXML('<foo><bar id="1"/><bar id="2"/></foo>');
$foo->find('//bar[@id="1"]')->remove();
print $foo->asXML(); // <foo><bar id="2"/></foo>

  • +1 Dies ist erstaunlich perfekt für das, was es tut. Nein muss. Keine Aufregung.

    – Giacomo1968

    4. Oktober 2014 um 2:08 Uhr


1646964852 944 Entfernen Sie ein untergeordnetes Element mit einem bestimmten Attribut in
Josh Davis

Für die Zukunft: Das Löschen von Knoten mit SimpleXML kann manchmal mühsam sein, besonders wenn Sie die genaue Struktur des Dokuments nicht kennen. Deshalb habe ich geschrieben SimpleDOMeine Klasse, die SimpleXMLElement erweitert, um einige praktische Methoden hinzuzufügen.

Beispielsweise löscht deleteNodes() alle Knoten, die mit einem XPath-Ausdruck übereinstimmen. Und wenn Sie alle Knoten mit dem Attribut “id” gleich “A5” löschen möchten, müssen Sie nur noch Folgendes tun:

// don't forget to include SimpleDOM.php
include 'SimpleDOM.php';

// use simpledom_load_string() instead of simplexml_load_string()
$data = simpledom_load_string(
    '<data>
        <seg id="A1"/>
        <seg id="A5"/>
        <seg id="A12"/>
        <seg id="A29"/>
        <seg id="A30"/>
    </data>'
);

// and there the magic happens
$data->deleteNodes('//seg[@id="A5"]');

989590cookie-checkEntfernen Sie ein untergeordnetes Element mit einem bestimmten Attribut in SimpleXML für PHP

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy