2011-08-19 3 views
7

j'ai une structure similaire à ce qui suit:Xpath: Sélectionnez nœud mais pas des éléments spécifiques de l'enfant

<page id='1'> 
    <title>Page 1</title>  
    <page id='2'> 
    <title>Sub Page 1</title> 
    </page> 
    <page id='3'> 
    <title>Sub Page 2</title> 
    </page>  
</page> 
<page id='4'> 
    <title>Page 2</title> 
</page> 

J'ai besoin de sélectionner une page par Id mais si cette page a des pages descendant je ne veux pas revenir ces éléments, mais je veux les autres éléments de cette page. Si je choisis Page 1 Je veux retourner titre, mais pas les pages enfant ...

//page[@id=1] 

ci-dessus me met la page 1, mais comment puis-je exclure les sous-pages? En outre, il peut y avoir n'importe quel nombre arbitraire d'éléments dans une page. J'ai trouvé que cela me donne les données que je veux. Cependant, ces données reviennent sous la forme d'un tableau d'objets avec un objet par élément et excluent apparemment les noms d'éléments. J'utilise PHP SimpleXML pour ce que ça vaut.

+0

Bonne question, +1. Voir ma réponse pour une solution courte et simple. :) –

+1

"Cependant, cette donnée se présente sous la forme d'un tableau d'objets avec un objet par élément." En quoi est-ce différent de ce que vous voulez/avez besoin? – LarsH

+0

Les données reviennent dans un format différent en fonction de la requête xpath, j'obtiens un tableau de SimpleXMLElement avec une seule chaîne dans chacune et il manque les noms des éléments. Le premier cas renvoie un seul objet SimpleXMLElement avec toutes les paires de valeurs de clé attendues. Je ne comprends pas pourquoi, je vais peut-être ouvrir une autre question. – Ben

Répondre

7

Utilisation:

//page[@id=$yourId]/node()[not(self::page)] 

Ce sélectionne tous les nœuds qui ne sont pas page et qui sont les enfants de tout page dans le document, la valeur de chaîne dont l'attribut id est égal à la chaîne contenue dans $yourId (le plus probablement vous remplacerez $yourId ci-dessus par un chaîne spécifique souhaitée, telle que '1').

Voici un simple vérification basée sur XSLT:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<xsl:param name="pId" select="3"/> 

<xsl:template match="/"> 
    <xsl:copy-of select="//page[@id=$pId]/node()[not(self::page)]"/> 
</xsl:template> 
</xsl:stylesheet> 

lorsque cette transformation est appliquée sur le document XML fourni (enveloppé dans un seul nœud supérieur pour le rendre bien formé):

<pages> 
    <page id='1'> 
     <title>Page 1</title> 
     <page id='2'> 
      <title>Sub Page 1</title> 
     </page> 
     <page id='3'> 
      <title>Sub Page 2</title> 
     </page> 
    </page> 
    <page id='4'> 
     <title>Page 2</title> 
    </page> 
</pages> 

le résultat recherché, est produit correct:

<title>Sub Page 2</title> 

Prenez note: Une hypothèse faite est qu'une valeur id identifie de manière unique un page. Si ce n'est pas le cas, l'expression XPath proposée sélectionne tous les élémentspage dont l'attribut id a une valeur de chaîne de $yourId.

Si c'est le cas et qu'un seul élément page doit être sélectionné, l'OP doit spécifier lequel parmi les nombreux éléments page avec ce id doit être sélectionné.

Par exemple, il peut être la première:

(//page[@id=$yourId]/node()[not(self::page)])[1] 

ou la dernière:

(//page[@id=$yourId]/node()[not(self::page)])[last()] 

ou ...

+0

Bien que cela semble exactement correct, il ne fonctionne pas réellement .. Je ne suis pas sûr s'il y a quelque chose de mal avec xpath dans le XML simple de PHP, mais cela renvoie plusieurs copies de la page demandée ??? – Ben

+0

@Ben: Cela peut arriver seulement si plus d'un 'page' peut avoir la même valeur de son attribut' id'. J'ai mis à jour ma réponse pour couvrir ce cas. Je fournis également une vérification simple montrant que l'expression XPath initiale sélectionne exactement un élément 'page' si une valeur' id' identifie de manière unique une 'page'. –

1

Si vous n'êtes intéressé que par l'élément de titre, cela fonctionnerait:

//page[@id=1]/title 

Si toutefois vous avez besoin d'autres éléments sous de page, je ne suis pas sûr XPath est l'outil pour vous. Cela ressemble plus à quelque chose qu'un XSLT serait adapté, car ce que vous faites vraiment, c'est transformer vos données.

+0

Malheureusement, j'ai besoin d'un certain nombre d'éléments arbitraires sauf la page ... – Ben

+0

Réponse mise à jour avec plus d'informations. N'hésitez pas à upvote si c'est utile de toute façon. :) –

+0

Merci, je commence à penser que Xpath ne peut peut-être pas faire ça. Je peux toujours écrire quelque chose pour traiter les données que je veux mais j'espérais le faire au niveau des données. – Ben

0

Si la page a toujours un titre:

//page[@id='1']/*[not(boolean(./title))] 
Questions connexes