57 votes

Supprimer un enfant avec un attribut spécifique, dans SimpleXML pour PHP

J'ai plusieurs éléments identiques avec différents attributs auxquels j'accède avec SimpleXML:

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

J'ai besoin de supprimer un élément segment spécifique, avec un identifiant de "A12", comment puis-je faire cela? J'ai essayé de passer en boucle à travers les éléments seg et de désactiver le paramètre en question, mais cela ne fonctionne pas, les éléments restent.

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

62voto

Stefan Gehrig Points 47227

SimpleXML ne fournit aucun moyen[1] pour supprimer ou réorganiser les nœuds XML. Ses fonctionnalités de modification sont quelque peu limitées. Vous devez recourir à l'aide du DOM extension. dom_import_simplexml() va vous aider à la conversion de votre SimpleXMLElement en DOMElement.

Juste un exemple de code (testé avec 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();

sorties

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

Par la voie: la sélection des nœuds spécifiques est beaucoup plus simple lorsque vous utilisez XPath (SimpleXMLElement->xpath):

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

60voto

hakre Points 102271

Contrairement à la croyance populaire dans les réponses, chaque élément Simplexml nœud peut être retiré du document par elle-même et unset(). Le point dans le cas est tout simplement que vous avez besoin de comprendre comment SimpleXML fonctionne réellement.

D'abord localiser l'élément que vous voulez supprimer:

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

Ensuite, retirer l'élément représenté en $element vous enlevez son auto-référence:

unset($element[0]);

Cela fonctionne parce que le premier élément d'un élément est l'élément lui-même dans simplexml (auto-référence). Cela a à voir avec la magie de la nature, des indices numériques représentent les éléments dans une liste (par exemple parent->les enfants), et même l'enfant unique est une telle liste.

Non-chaîne numérique indices de représenter les attributs (dans la gamme d'accès) ou de l'enfant-élément(s) (dans la propriété-accès).

Par conséquent numérique indecies dans la propriété-accès comme:

unset($element->{0});

travaillent ainsi.

Naturellement avec xpath exemple, il est plutôt de droite vers l'avant (en PHP 5.4):

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

L'exemple complet de code (Démo):

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

Sortie:

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

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

26voto

kavoir.com Points 2813

Désactivez simplement le noeud:

 $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
 

Ce code provient de Comment supprimer / supprimer des nœuds dans SimpleXML .

11voto

Witman Points 421

Je crois que Stefan la réponse est à droite sur. Si vous souhaitez supprimer un nœud (plutôt que tous les nœuds correspondants), voici un autre exemple:

//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');

Notez que les sections de la Charge XML... (en premier) et le Format XML... (dernier) pourrait être remplacé par un code différent selon l'endroit où vos données XML vient et ce que vous voulez faire avec la sortie; c'est les sections en entre que trouver un nœud et le retirer.

En outre, si l'instruction n'est là que pour s'assurer que le nœud cible existe avant d'essayer de le déplacer. Vous pouvez choisir différentes façons de traiter ou de les ignorer cette affaire.

6voto

sunnyface45 Points 31

Ce travail pour moi:

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X