[RESOLU] pb fonction xpath et siplexml

nounet
Invité n'ayant pas de compte PHPfrance

07 nov. 2007, 16:21

B*onjour a tous,

Voici une ligne tiré d'un fichier xml:

Code : Tout sélectionner

<text:p text:style-name="Standard">{Image}</text:p>
Etant donné que dom xml est remplacé par la classe simplexml autant commencer monapprentissage par celle ci.cependant je toruve les exmeples tres obscurs concernant la gestions des namesapce ce qui est le cas au vu de la ligne xml que j'ai proposé ci dessus.

Pour commencer je dois utiliser la classe simpleXmlElement d'ou le code suivant:

Code : Tout sélectionner

$oXml=new SimpleXmlElement('content.xml');
mais comment faire pour trouver la baslise que jai mise plus haut .

faut il faire par exmeple:

Code : Tout sélectionner

$oXml->Xpath('//text:p');
ou plutot faire comme ceci

Code : Tout sélectionner

foreach($oXml->text->attibutes('p')){ }
merci a tous de votre aide.[/code]

Mammouth du PHP | 2937 Messages

07 nov. 2007, 16:36

Pour charger un fichier avec SimpleXML, il faut procéder comme suit :
$oXml = simplexml_load_file ('content.xml');
Ensuite, pour trouver ta balise XML, tout dépend de son emplacement dans l'arborescence du fichier XML.
Si l'arborescence de ton XML est ainsi :

Code : Tout sélectionner

<?xml version="1.0"?> <root> <text:p></text:p> </root>
il suffira de parcourir ton XML ainsi :
$text_p = $oXml -> text:p;
foreach ($text_p as $valeur)
{
  echo htmlspecialchars ((string) $valeur);
}
// Il se peut qu'il y ait plusieurs nœuds text:p, donc on les affiche les uns après les autres

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

07 nov. 2007, 17:01

faut il faire [...]
Tu nous donnes le choix entre un truc qui marche et un truc qui ne marche pas, donc je conseillerais plutôt d'utiliser celui qui marche. 8-| SimpleXML n'est pas spécialement adapté à l'utilisation de namespaces, donc XPath est probablement le chemin le plus sûr.
$text_p = $oXml -> text:p;
Euh... :-*

nounet
Invité n'ayant pas de compte PHPfrance

07 nov. 2007, 17:17

le probleme est bien que je ne sais pas ou sera situé cette balise,je n'ai aucun moyen d'avoir de chemin absolu.c'est pourquoi la fonction Xpath me semblait la plus plausible mais dans les exmples elle n'etait presenté qu'avec des balises ne presentant aucun namespace.C'est poour cela que j'avais besoin d'en savoir un peu plus.
donc pour vous deux la seule methode possible est elle bien la suivante ?

Code : Tout sélectionner

$oXml->Xpath(//text:p');

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

07 nov. 2007, 17:29

Si tu ne connais pas le chemin précis de ces éléments alors XPath est fait pour ça, oui.

nounet
Invité n'ayant pas de compte PHPfrance

07 nov. 2007, 18:08

merci de vos conseils.
Maintenant toujours en me basant sur ma premiere balise xml j'aimerai remplacer{Image} par une chaine de caraetere vide puis d'inserer une sous categorie suivante:

Code : Tout sélectionner

<draw:frame draw:style-name="fr2" draw:name="graphics2" text:anchor-type="as-char" svg:width="18.983cm" svg:height="26.852cm" draw:z-index="1"><draw:image xlink:href="Pictures/10000000000004D8000006DA58D31A94.png" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/></draw:frame>
que pensez vous alors de cette methode suivante:

 if ((string)$oXml->Xpath('//text:p') == '{Image}'{
         str_replace('{Image}','','$oXml');
          $oXml->addchild('draw:frame');
              $oxml->addAttribute('draw:name','graphics2');
              $oXml->addAttribute('text:anchor-type','as-char');
              $oXml->addAttribute('svg:width','18.983cm');
              $oXml->addAttribute('svg:height','26.852cm');
              $oXml->addAttribute('draw:z-index','1');
creation d'une sous-categorie
           $oXml->addChild('draw:image');
              $oxml->addAttribute('xlink:href','Pictures/10000000000004D8000006DA58D31A94.png');
              $oXml->addAttribute('xlink:type','simple');
              $oXml->addAttribute('xlink:show','embed');
              $oXml->addAttribute('xlink:actuate','onLoad');
              $oXml->addAttribute('draw:z-index','1');

}
Et comment gerer les fins de balise??ou les balieses qui se ferme automatiquement comme </>
d'avance merci pour tous vos commentaires.

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

08 nov. 2007, 10:53

que pensez vous alors de cette methode suivante:
J'en pense que Parse error: syntax error, unexpected '{'.

Quand tu postes un extrait de source, il est primordial que tu l'aies déjà exécuté et testé son fonctionnement. S'il ne fonctionne pas de la manière attendu il te faut alors expliquer ce qui diffère entre le fonctionnement attendu et le fonctionnement réel. De la même façon, si tu postes du XML, il faut que ce soit du XML valide, donc il te faut inclure l'élément racine (sans pour autant recopier les éléments/attributs qui ne sont pas concernés), sans quoi il nous est impossible de tester sa validité. Et dans ce cas on se retrouve à répondre au hasard et ça n'avance personne.

À part ça, le code que tu proposes souffres de plusieurs défaut de conception. Par exemple, xpath() renvoit systématiquement un tableau, tu ne peux donc pas le comparer à une chaîne. D'ailleurs, cette comparaison n'est pas vraiment nécessaire puisqu'on peut l'inclure dans l'expression XPath: (voir http://www.w3.org/TR/xpath#predicates)

Code : Tout sélectionner

//text:p[text() = "{Image}"]
SimpleXML n'est d'ailleurs pas conçu pour ce genre de modification et ne possède pas de méthodes pour remplacer des éléments. J'ai créé une classe visant à pallier ce manque, et je viens de la mettre à jour pour permettre les remplacements par XPath.

Il te faut donc modifier ton script pour inclure cette classe, utiliser cette classe pour ton objet $oXml, créer un objet pour représenter l'image de remplacement (il est impératif de redéclarer les namespaces pour créer cet objet), et finalement effectuer le remplacement. Le résultat doit ressembler à
<?php
include 'sxe.php';

$oXml = new SXE('<?xml version="1.0"?> 
<root xmlns:text="urn:text" xmlns:draw="urn:draw" xmlns:xlink="urn:xlink" xmlns:svg="urn:svg">
	<foo>
		<text:p>{Image}</text:p>
	</foo>
</root>');

$xpath = '//text:p[text() = "{Image}"]';
$img = new SXE('<draw:frame xmlns:draw="urn:draw" />');
$oXml->replaceNodes($xpath, $img);

die($oXml->asXML());
Dernière chose, tu demandes "comment gerer les fins de balise?", la réponse est : tu ne le fais pas. Tu ne dois surtout pas imaginer le contenu de SimpleXML comme du texte, SimpleXML n'est pas du texte, c'est un objet. Lorsque tu utilises la méthode asXML(), l'objet est transformé en texte et SimpleXML se charge de tous les détails techniques, ouvrir/fermer les balises, mettres les namespaces/préfixes, etc...

nounet
Invité n'ayant pas de compte PHPfrance

08 nov. 2007, 12:21

Merci pour tout ton aide

Prmeierement ,autant pour moi des la lecture ,j'ai vu qu'il manquait la parenthese dans mon code.
deuxiemmement, je poensais que le fait d'utiliser (string) permettait de caster un objet en texte ?d'autant plus quec'est un exmemple de la documentatni officiel de php.

Troisiemment,(j'aime comprendre un code avant de l'utiliser betement).Ta classe ne presente aucun constructeur donc pourquoi passe tu un arguement quand tu instancie ton objet :

Code : Tout sélectionner

$oXml= new SXE('.....');
Pour finir je ne savais tout simplement pas que la balise racine etait si importante que cela dans la recontitution.Voici en effet l'exemple total du fichier xml

Code : Tout sélectionner

<?xml version="1.0" encoding="UTF-8" ?> - <office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.0"> <office:scripts /> - <office:font-face-decls> <style:font-face style:name="Tahoma1" svg:font-family="Tahoma" /> <style:font-face style:name="Times New Roman" svg:font-family="'Times New Roman'" style:font-family-generic="roman" style:font-pitch="variable" /> <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" style:font-pitch="variable" /> <style:font-face style:name="Arial Unicode MS" svg:font-family="'Arial Unicode MS'" style:font-family-generic="system" style:font-pitch="variable" /> <style:font-face style:name="MS Mincho" svg:font-family="'MS Mincho'" style:font-family-generic="system" style:font-pitch="variable" /> <style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="system" style:font-pitch="variable" /> </office:font-face-decls> <office:automatic-styles /> - <office:body> - <office:text> <office:forms form:automatic-focus="false" form:apply-design-mode="false" /> - <text:sequence-decls> <text:sequence-decl text:display-outline-level="0" text:name="Illustration" /> <text:sequence-decl text:display-outline-level="0" text:name="Table" /> <text:sequence-decl text:display-outline-level="0" text:name="Text" /> <text:sequence-decl text:display-outline-level="0" text:name="Drawing" /> </text:sequence-decls> <text:p text:style-name="Standard">{Image}</text:p> </office:text> </office:body> </office:document-content>
Et encore bravo pour ta classe qui garde vraiment cette esprit de simple.
Il me reste encore a me pencher sur la facon d'inserer une nouvelle balise xml mlais je crois que je vais m'orienter sur ta fonction insert before.

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

08 nov. 2007, 12:36

le fait d'utiliser (string) permettait de caster un objet en texte ?
Forcer le type de données via (string) (ou (int), etc...) s'appelle "transtypage", certains objets offrent la possibilités d'être transformés en chaînes, mais pas tous. Et en l'occurence, xpath() ne renvoit pas d'objet, mais un tableau.
Ta classe ne presente aucun constructeur donc pourquoi passe tu un arguement quand tu instancie ton objet
Ma classe hérite de la classe SimpleXMLElement qui, elle, possède bien un constructeur. D'ailleurs, je ne l'ai pas précisé mais
simplexml_load_string($txt);
est identique à
new SimpleXMLElement($txt);
Et tu peux utiliser ma classe de la même façon
simplexml_load_string($txt, 'SXE');
// ou
new SXE($txt);
Il me reste encore a me pencher sur la facon d'inserer une nouvelle balise xml mlais je crois que je vais m'orienter sur ta fonction insert before.
Maintenant que tu sais comment formuler tes problèmes n'hésite pas à poster un nouveau sujet si tu as du mal avec ta prochaine étape.

a++ ;)

nounet
Invité n'ayant pas de compte PHPfrance

08 nov. 2007, 13:06

merci bien ,j'ai bien compris la notion de extends.

Or il se tourve qu'il est possible non pas de donné une chaine xml mais un path vers une chaine xml a partir du moment ou :
$oXml=newSimpleXmlElement('path/To/xmlvalide.xml',NULL,TRUE);
est il juste alors d'instancier ta classe de la maniere qui suit si je veux appeler non pas une chaine xml mais un chemin :
$oXml=new SXE('path/To/xmlvalide.xml',NULL,TRUE);

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

08 nov. 2007, 13:15

Oui, ou même utiliser simplexml_load_file() si tu préfères.

nounet
Invité n'ayant pas de compte PHPfrance

08 nov. 2007, 17:07

toujours en partant du mem code xml ci dessus.
j'obtiens un message d'erreur concernant les namespace.
j'ai ecrit le code suivant :
<?php
  include_once('ClassExtendsSimpleXml.class');
  $oXml=new SXE('content.xml',NULL,TRUE);
  
  list($fWidth,$fHeight,$sType,$sAttr)= getimagesize('menu.png');
  
 $xpath = '//text:p[text() = "{Image}"]';

 
   
 
  $img = new SXE('<draw:frame draw:style-name="fr2" draw:name="graphics2" text:anchor-type="as-char" svg:width="'.$fWidth.'cm" svg:height="'.$fHeight.'cm" draw:z-index="1"><draw:image xlink:href="Pictures/10000000000004D8000006DA58D31A94.png" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/></draw:frame>');
  if(!$oXml->replaceNodes($xpath, $img)){
   echo 'non reussi';
  }else{
  echo 'reussi';
  } 
  
  
  
  
  
  
?>[/code]
mais j'obtiens le message d'erreur suivant :
Warning: SimpleXMLElement::__construct() [function.SimpleXMLElement---construct]: namespace error : Namespace prefix draw for style-name on frame is not defined in C:\wamp\www\diagnostiqueur\ernt\test.php on line 12

Warning: SimpleXMLElement::__construct() [function.SimpleXMLElement---construct]: text:anchor-type="as-char" svg:width="130cm" svg:height="30cm" draw:z-index="1" in C:\wamp\www\diagnostiqueur\ernt\test.php on line 12

Warning: SimpleXMLElement::__construct() [function.SimpleXMLElement---construct]: ^ in C:\wamp\www\diagnostiqueur\ernt\test.php on line 12

Warning: SimpleXMLElement::__construct() [function.SimpleXMLElement---construct]: namespace error : Namespace prefix draw for name on frame is not defined in C:\wamp\www\diagnostiqueur\ernt\test.php on line 12

il y en a bien d'autre ensuite.

Google mon ami ne m'a pas plus avancé c'est pour cela queje me troune vers vous .

Administrateur PHPfrance
Administrateur PHPfrance | 3088 Messages

08 nov. 2007, 17:39

Comme je le disais plus tôt, il est impératif de redéclarer les namespaces pour créer $img. Il faut que tous les namespaces utilisés dans ton nouvel élément soit déclarés à la racine de celui-ci à l'identique de l'arbre principal.

nounet
Invité n'ayant pas de compte PHPfrance

08 nov. 2007, 18:13

c'est bien ce que j'avais compris d'apres votre message,pourtant on est d'accord qu'ils sont bien disponible en debut du document xml.

donc en gros il faut proceder de la suite

Code : Tout sélectionner

<text:p> <office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" office:version="1.0"> <office:scripts /> <draw ....</draw> </text:p>
ainsi tous mes espaces d enomseront recrée une dexueime fois.est ce que j'ai bine compris ou pas?

nounet
Invité n'ayant pas de compte PHPfrance

08 nov. 2007, 18:47

j'aifinit par utiliser les lignes cidessous .En effet,la documentation n'indique pas qu'il SOIT OBLIGATOIRE d'utiliser la balise du haut du document xml qui contient les namesapce.

la forme d'un namesapce est :
xmlnsd:prefixe="adresse du namespace" soit pour mes balises draw j'ai noté 4 prefixe qui sont draw, xlink,text,svg .

Est ce que je n'aurai pas oublié quelque chose ?ce qui nous donne le code suivant:

Code : Tout sélectionner

$xpath = '//text:p[text() = "{Image}"]'; $img = new SXE('<text:p xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0"><draw:frame draw:style-name="fr2" draw:name="graphics2" text:anchor-type="as-char" svg:width="'.$fWidth.'cm" svg:height="'.$fHeight.'cm" draw:z-index="1"><draw:image xlink:href="Pictures/10000000000004D8000006DA58D31A94.png" xlink:type="simple" xlink:show="embed" xlink:actuate="onLoad"/></draw:frame></text:p>'); $oXml->replaceNodes($xpath, $img)