Aller au contenu

SimpleXML -> supprimer un noeud XML


MS-DOS_1991

Sujets conseillés

Bonjour :)

Je viens de me mettre au XML avec la librairie SimpleXML intégrée à PHP 5. Tout marche parfaitement et j'arrive en 2 lignes à afficher tout ce que je veux de mon fichier :thumbsup:

Le problème, c'est qu'il n'y a apparemment pas de fonction removeNode() ou removeChild() intégrée à cette classe, ce qui fait que je ne peux pas supprimer le noeud courant (utile dans mon cas car je fais un compteur de conenctés ;) )

Dans la doc PHP, quelqu'un a écrit une classe, extendedSimpleXML (class extendedSimpleXML extends SimpleXMLElement) qui contient une méthode removeNode...

Voici donc mon fichier XML (membres et invites sont séparés ;) ):

<?xml version="1.0" encoding="windows-1250"?>
<online_users>
<members>
</members>
<guests>
<user>
<ip>01.234.56.789</ip>
<last_activity_time>1157100123</last_activity_time>
<last_activity_url>/forums/index.php?show_forums</last_activity_url>
</user>
<user>
<ip>12.345.67.890</ip>
<last_activity_time>1157100456</last_activity_time>
<last_activity_url>/forums/index.php?show_forums</last_activity_url>
</user>
<user>
<ip>23.456.78.901</ip>
<last_activity_time>1157100789</last_activity_time>
<last_activity_url>/forums/index.php?show_forums</last_activity_url>
</user>
<user>
<ip>34.567.89.012</ip>
<last_activity_time>1157101234</last_activity_time>
<last_activity_url>/forums/index.php?show_forums</last_activity_url>
</user>
</guests>
</online_users>

et le code PHP :

$online_users = simplexml_load_file('././inc/online_users.xml');
$online_users = new extendedSimpleXML($online_users->asXML());
foreach ($online_users->guests->user AS $user)
if ($user->ip == $_SERVER['REMOTE_ADDR'])
{
$user->last_activity_time = time();
$user->last_activity_url = $_SERVER['REQUEST_URI'];
$found = true;
$online_users->asXML('././inc/online_users.xml');
}
elseif (time()-$user->last_activity_time > 180)
{
$user->removeNode();
$online_users->asXML('././inc/online_users.xml');
}

if (!$found)
{
$user = $online_users->guests->addChild('user');
$user->addChild('ip', $_SERVER['REMOTE_ADDR']);
$user->addChild('last_activity_time', time());
$user->addChild('last_activity_url', $_SERVER['REQUEST_URI']);
$online_users->asXML('././inc/online_users.xml');
}

Le problème est que la fonction removeNode() me fait apparemment sortir directement de ma boucle foreach, ce qui fait que je ne peux supprimer qu'un élément à la fois :(

... Une idée ?

P.S : ah oui, SimpleXML me supprime l'indentation lorsque je rajoute des éléments... Est-il possible de la restaurer ?

Modifié par MS-DOS_1991
Lien vers le commentaire
Partager sur d’autres sites

Comme son nom l'indique simpleXML est une API simple de manipulation de contenu XML. Son objectif est de pouvoir manipuler rapidement l'XML pour l'affichage et la recherche. Si tu veux vraiment supprimer un noeud de ton arbre xml, utilise une API qui est complète pour la modification du xml: DOM.

http://fr2.php.net/manual/fr/function.dom-...removechild.php

il y a un pont entre dom et simpleXML si tu veux continuer à utiliser simpleXML pour l'affichage.

Bon courage

Lien vers le commentaire
Partager sur d’autres sites

SimpleXML sert essentiellement à faire simplement des traitements simple sur des flux XML.

Si tu veux traiter un flux, pourquoi ne pas se tourner vers DOM ?

[edit]rportal a posté pendant que je tapais la causette [/edit]

Modifié par Spidetra
Lien vers le commentaire
Partager sur d’autres sites

Si tu veux traiter un flux, pourquoi ne pas se tourner vers DOM ?
Pourquoi ? Parce que SimpleXML me convient parfaitement en ce qui concerne la lecture...

Si la seule solution est de passer par le DOM (qui me paraît beaucoup plus complexe d'utilisation) ... hé bien je passerai par le DOM :sick:

Lien vers le commentaire
Partager sur d’autres sites

Il n'y a jamais une seule solution, mais il faut utiliser les outils à ta disposition en fonction de leurs objectifs. Les détourner peut se révéler utile de temps en temps mais ici il s'agit de manipuler des objets qui utilisent pas mal de ressource donc autant utiliser ceux qui sont optimisés pour l'utilisation que tu désires. Comme tu le dis, simpleXML te convient pour la lecture d'un XML et cela est normal vu qu'il a été développé pour cela... mais pas pour manipuler en profondeur du xml...

Lien vers le commentaire
Partager sur d’autres sites

Je me permet de re-poster car j'ai vraiment du mal avec le DOM :unsure:

Voici mon code

foreach ($online_users->guests->user AS $user)
{
if ($user->ip == $_SERVER['REMOTE_ADDR'])
{
$user->last_activity_time = time();
$user->last_activity_url = $_SERVER['REQUEST_URI'];
$found = true;
$online_users->asXML('././inc/online_users.xml');
}
elseif (time()-$user->last_activity_time > 180)
{
$dom = new DOMDocument();
$dom_sxe = dom_import_simplexml($online_users);
// Que mettre ici ?
$online_users = simplexml_import_dom($dom_sxe);
$online_users->asXML('././inc/online_users.xml');
}
}

Je veux importer mon objet simplexml dans un objet DOM, pour ensuite supprimer le noeud <user> en cours d'analyse depuis le DOM, réimporter l'objet dans simplexml et sauvegarder le fichier...

Le problème est qu'il faut connaitre la position du noeud pour le détruire, l'idéal serait une méthode "current_item()" mais ... ça m'étonnerais que ce soit aussi simple :wacko:

Quelqu'un sait-il comment faire ?

Lien vers le commentaire
Partager sur d’autres sites

ça fait un moment que je n'ai pas maniuplé DOM en Php mais ça devrait ressembler à un truc de ce style.

Je n'utilise pas simpleXML, je trouve trop compliqué de mélanger simpleXML et DOM

Il faut que tu vérifie les appels de méthodes et l'algo, il y a surement des erreurs. C'est juste un brouillon pour te mettre sur la voie.

$doc = new DomDocument();
$doc->loadXML( $xml ); // méthode à adapter en fct de tes besoins : load(), loadXML(), etc...

// tu recherche tout les users. Tu peux les récupérer par leur nom
$users = $doc->getElementByTagName('user');

// tu boucle sur l'ensemble de tes users
foreach( $users as $user ) {

// Tu bloucle sur tout les fils de ton node
foreach( $user->childNodes as $node ) {
if ( $node->nodeType != XML_ELEMENT_NODE ) continue;
if ( $node->tagName == '' ) { // ici tu teste le tagName qui t'intéresse
$ip = $node->nodeValue;
}
if ( $node->tagName == '' ) { // ici tu teste le tagName qui t'intéresse
$last_activity_time = $node->nodeValue;
}
...... etc
}

// Tout les fils ont été traités tu as récupéres les valeurs qui t'intéresse
// Ici tu fait tes controles
if ( il faut eliminer ce noeud ) {
$doc->removeChild( $node ); // J'ai un big doute sur cet appel !
}


}

Lien vers le commentaire
Partager sur d’autres sites

En relisant je viens de voir que tu avais des users sous deux arbo : <membre> et <guest>

Si tu ne veux traiter que les guests tu vas ajouter en début de code :

$doc = new DomDocument();
$doc->loadXML( $xml ); // méthode à adapter en fct de tes besoins : load(), loadXML(), etc...

// -> rajout ici : d'abord tu récupére le noeud guest ou memebre
$guest = $doc->getElementByTagName('guest');

// tu recherche tout les users. Tu peux les récupérer par leur nom
// J'ai remplacé $doc par $guest
$users = $guest->getElementByTagName('user');

Lien vers le commentaire
Partager sur d’autres sites

Oui, c'est ce que j'avais fait ;)

Voilà où j'en suis pour le moment :

$document = new DomDocument();
$document->load('././inc/online_users.xml');

$guests = $document->getElementsByTagName('guests');
foreach ($guests AS $guests)
{
$users = $guests->getElementsByTagName('user');
foreach ($users AS $user)
{
foreach ($user->childNodes AS $node)
{
if ($node->nodeType != XML_ELEMENT_NODE)
continue;

// Si on sait que l'on se trouve dans le bloc <user> du visiteur courant
// Alors on met a jour les valeurs (lastactivity, etc)
if ($found)
{
if ($node->tagName == 'last_activity_time')
$node->nodeValue = time();
}
// Si on se trouve dans le bloc <user> du visiteur courant (on ne le savait pas encore)
// Alors on passe au <tag> suivant
elseif ($node->tagName == 'ip' && $node->nodeValue == $_SERVER['REMOTE_ADDR'])
{
$found = true;
continue;
}
// Si on n'est pas dans le bloc <tag> de l'utilisateur courant et que l'utilisateur de ce tag est inactif depuis trop longtemps
elseif ($node->tagName == 'last_activity_time' && time()-$node->nodeValue > 180)
$guests->removeChild($user);
}
}
}

Mais je suis un peu perdu et je pense que mon code est redondant :$

Modifié par MS-DOS_1991
Lien vers le commentaire
Partager sur d’autres sites

Ca y est ! ça supprime :fete:

$document = new DomDocument();
$document->load('././inc/online_users.xml');

$guests = $document->getElementsByTagName('guests');
foreach ($guests AS $guests)
{
$users = $guests->getElementsByTagName('user');
foreach ($users AS $user)
{
$found = false;
foreach ($user->childNodes AS $node)
{
if ($node->nodeType != XML_ELEMENT_NODE)
continue;

if ($found)
{
echo 'current_user';
if ($node->tagName == 'last_activity_time')
{
$new_last_activity_time = $document->createElement('last_activity_time', 123);
$user->replaceChild($new_last_activity_time, $node);
continue;
}
}
// Si on se trouve dans le bloc <user> du visiteur courant (on ne le savait pas encore)
// Alors on passe au <tag> suivant
elseif ($node->tagName == 'ip' && $node->nodeValue == $_SERVER['REMOTE_ADDR'])
{
$found = true;
continue;
}
// Si on n'est pas dans le bloc <tag> de l'utilisateur courant et que l'utilisateur de ce tag est inactif depuis trop longtemps
elseif ($node->tagName == 'last_activity_time' && time()-$node->nodeValue > 180)
{
echo 'user_to_be_removed';
$guests->removeChild($user);
}
}
}
}
$document->save('././inc/online_users.xml');

Il me reste encore cependant à "updater" le noeud <last_activity_time></last_activity_time> en lui assignant la valeur du timestamp courant obtenu avec time().

J'ai épluché la doc et malheureusement, le seul moyen de modifier le contenu d'un noeud semble être... d'en créer un autre puis de remplacer l'ancien par le nouveau :rolleyes:

Mon code affiche bien "current_user", reconnaît bien le tag <last_activity_time> et la fonction replaceChild ne renvoie pas d'erreur, pourtant le noeud n'est pas mis à jour :mad2:

edit (le dernier ^_^) : C'est bon, tout fonctionne .

Ce n'est pas (si) compliqué le DOM XML (mais alors c'est lourd :rolleyes: )

Modifié par MS-DOS_1991
Lien vers le commentaire
Partager sur d’autres sites

J'ai un seul noeud : <guests><user>...</user><user>...</user></guests>

Mais sans le foreach ça plante et comme je ne sais pas (encore) comment dire à PHP comment aller à l'indice 0, je fais une itération de foreach ...

En tout cas, merci beaucoup de ton aide :thumbsup:

Lien vers le commentaire
Partager sur d’autres sites

edit (le dernier ^_^) : C'est bon, tout fonctionne .

Ce n'est pas (si) compliqué le DOM XML (mais alors c'est lourd :rolleyes: )

si tu doit juste parcourir un flux XML, sans le modifier, essaye de remplacer simpleXML par SAX.

C'est plus dur à utiliser, mais c'est bc plus performant.

Lien vers le commentaire
Partager sur d’autres sites

  • 7 months later...

Bonjour,

Je souhaiterais utiliser DOMDocument pour supprimer des noeuds. Un peu comme MS-DOS_1991, j'ai utilisé simpleXML jusqu'ici, mais me voilà bloqué.

Si je poste ici, c'est que j'ai un problème pour activer dom dans apache et qu'il est dit de partout "Sous PHP 5, il n'y a rien à installer, le package DOM fait partie du langage de base."...

Je suis sous fedora, avec un PHP Version 5.1.6.

Si par chance, vous pouviez m'expliquer la procédure...

Par avance , merci !

Lien vers le commentaire
Partager sur d’autres sites

Veuillez vous connecter pour commenter

Vous pourrez laisser un commentaire après vous êtes connecté.



Connectez-vous maintenant
×
×
  • Créer...