MS-DOS_1991 Posté 1 Septembre 2006 Posté 1 Septembre 2006 (modifié) 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 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é 1 Septembre 2006 par MS-DOS_1991
rportal Posté 1 Septembre 2006 Posté 1 Septembre 2006 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
Spidetra Posté 1 Septembre 2006 Posté 1 Septembre 2006 (modifié) 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é 1 Septembre 2006 par Spidetra
MS-DOS_1991 Posté 1 Septembre 2006 Auteur Posté 1 Septembre 2006 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
rportal Posté 1 Septembre 2006 Posté 1 Septembre 2006 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...
MS-DOS_1991 Posté 1 Septembre 2006 Auteur Posté 1 Septembre 2006 Je me permet de re-poster car j'ai vraiment du mal avec le DOM 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 Quelqu'un sait-il comment faire ?
Spidetra Posté 1 Septembre 2006 Posté 1 Septembre 2006 ç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 usersforeach( $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 ! }}
Spidetra Posté 1 Septembre 2006 Posté 1 Septembre 2006 Merci beaucoup j'essaie de suite Essaye, avant de remercier J'suis pas du tout sur que ça va marcher du premier coup !
Spidetra Posté 1 Septembre 2006 Posté 1 Septembre 2006 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');
MS-DOS_1991 Posté 1 Septembre 2006 Auteur Posté 1 Septembre 2006 (modifié) 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é 1 Septembre 2006 par MS-DOS_1991
MS-DOS_1991 Posté 1 Septembre 2006 Auteur Posté 1 Septembre 2006 (modifié) Ca y est ! ça supprime $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 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 edit (le dernier ) : C'est bon, tout fonctionne . Ce n'est pas (si) compliqué le DOM XML (mais alors c'est lourd ) Modifié 1 Septembre 2006 par MS-DOS_1991
Spidetra Posté 1 Septembre 2006 Posté 1 Septembre 2006 tu as +sieurs noeud guest ou un seul ? si tu n'as qu'un le foreach sur $guests ne sert à rien. Pour le replace pas d'idées.
MS-DOS_1991 Posté 1 Septembre 2006 Auteur Posté 1 Septembre 2006 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
Spidetra Posté 1 Septembre 2006 Posté 1 Septembre 2006 edit (le dernier ) : C'est bon, tout fonctionne .Ce n'est pas (si) compliqué le DOM XML (mais alors c'est lourd ) 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.
edouardo70 Posté 8 Avril 2007 Posté 8 Avril 2007 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 !
Sujets conseillés
Veuillez vous connecter pour commenter
Vous pourrez laisser un commentaire après vous êtes connecté.
Connectez-vous maintenant