2010-06-03 8 views
2

Disons que j'ai ce document.Comment sélectionner les éléments correspondants les moins profonds avec XPath?

<a:Root> 
    <a:A> 
     <title><a:B/></title> 
     <a:C> 
      <item><a:D/></item> 
     </a:C> 
    </a:A> 
</a:Root> 

et moi avons un XmlNode fixé à l'élément <a:A>.

Si je dis

A.SelectNodes("//a:*", namespaceManager) 

Je reçois B, C et D. Mais je ne veux pas D car il est imbriqué dans un autre élément "a:".

Si je dis

A.SelectNodes("//a:*[not(ancestor::a:*)]", namespaceManager) 

bien sûr, je reçois rien, puisque A et son parent sont dans l'espace "a".

Comment puis-je sélectionner seulement B et C, c'est-à-dire les enfants les moins profonds correspondant à l'espace de noms?

Merci. Remarque: il s'agit de XPath 1.0 (.NET 2). Je ne peux donc pas utiliser les préfixes dans le champ d'application (ce qui semble utile).

En outre, ce n'est pas vraiment une question sur les espaces de noms. Le dilemme serait le même avec d'autres critères correspondants.

+0

Bonne question (1). Voir ma réponse pour la seule solution pure XPath 1.0 jusqu'à présent. :) –

Répondre

0

Ce n'est pas faisable avec une seule expression XPath 1.0. L'extension de la réponse de Marc qui utilise XSLT, vous pouvez le faire pour 1.0:

<xsl:variable name="n" select="count(ancestor-or-self::a:*)" /> 
<xsl:variable name="result" select=".//a:*[count(ancestor::a:*) = $n]" /> 

ou la séquence équivalente d'appels C# pour Select....

+0

Merci, je l'ai un peu formulé différemment (et bien sûr en C#), mais la technique de comparaison des comtes était astucieuse. – harpo

+0

Ceci n'est pas une question XSLT. –

+0

@Dimitre: c'est clair, mais le code C# correspondant est trivial à écrire. –

2

Qu'en est-ce:

<xsl:variable name="parents" select="ancestor-or-self::a:*" /> 
<xsl:value-of select="//a:*[not(deep-equal(ancestor::a:*, $parent))]" /> 

En XSLT cela semble simple (stocker un ensemble de nœuds comme une variable), mais je ne sais pas exactement comment implémenter cela en C#.

Edit: ouvr sur l'idée d'utiliser le nombre, cela peut sans doute travailler:

int nrParents = A.SelectNodes("ancestor-or-self::a:*", namespaceManager).Count(); // Or was it Size? 
A.SelectNodes("//a:*[count(ancestor::a:*)!=" + nrParents + "]", namespaceManager) 
+0

Merci pour la réponse. Je n'utilise pas XSLT ici ou XPath 2.0. En effet, .NET ne prend toujours pas en charge XPath 2.0. – harpo

+0

'deep-equal' est XPath/XSLT 2.0 –

+0

@Pavel, je ne suis pas d'accord. Mais dans tous les cas, j'ai essayé d'utiliser deep-equal et .NET ne le reconnaît pas. – harpo

1

Ce n'est pas une question XSLT, voici donc une seule expression XPath qui sélectionne les deux nœuds voulaient:

/*/*/descendant::a:*[not(count(ancestor::a:*) > 2)] 
+0

Merci pour la contribution, je suis allé avec quelque chose de très semblable à ceci. Mais parce que la profondeur du nœud de départ était inconnue, j'ai dû le calculer dans une étape distincte. – harpo

+0

@harpo: Dans votre cas, le nœud de départ était-il connu? Aviez-vous une expression XPath en sélectionnant le noeud de départ? –

+0

Non, je viens d'avoir une référence XmlNode. En fait, j'ai fini par construire des expressions de chemin pour les nœuds sélectionnés en utilisant une routine adaptée de la réponse de Jon Skeet à une autre question, http://stackoverflow.com/questions/241238/how-to-get-xpath-from-an-xmlnode- instance-c/241291 # 241291 – harpo