Question

J'ai du mal à quelques jours avec XPath assez complexe et je ne suis pas en mesure de le formuler. J'ai un arbre syntaxique de C ++ comme l'analyseur de langage et j'aimerais avoir une requête XPath, qui sélectionne tous les noms, qui ne sont pas dans le nom de la fonction.

Pour être précis, j'ai un document XML comme celui-ci

(Le document XML entier est à la fin de la question, il est assez important, je colle ici un simple aperçu de la structure du document) Il existe quatre types de nœuds
A - Cet élément contient un nœud
B - contient des informations sur le nœud (par exemple "call_expression")
C - contient du texte réel (par exemple "printf", noms de variables ...)
D - Contient des descendères du nœud actuel (A Éléments)

CALL_EXPRESSION
  DOT_EXPRESSION
    NAME_EXPRESSION
      NAME
    NAME_EXPRESSION
      NAME
  PARAMS
    NAME_EXPRESSION
      NAME

CALL_EXPRESSION
  NAME_EXPRESSION
    NAME
  PARAMS
    NAME_EXPRESSION
      NAME

ASSIGNMENT_EXPRESSION
  NAME_EXPRESSION
    NAME
  NAME_EXPRESSION
    NAME

Je voudrais formuler la requête XPath, qui sélectionnerait tous les noms qui ne sont pas des descendants de call_expression / * [1]. (Cela signifie que je voudrais sélectionner toutes les variables et non les noms de fonction).

Pour sélectionner tous les noms de fonction, je peux utiliser XPath comme celui-ci

// a [b = "call_expression"] / d / a [1

Pas de problème ici. Maintenant, si je voudrais sélectionner tous les nœuds qui ne sont pas des descendères de ces nœuds. Je n'utiliserais pas (ancêtre :: x).

Mais voici le problème, si je formule l'expression XPATH comme ceci:

// * [b = "name"] [pas (ancêtre :: a [b = "call_expression"] / d / a [1])

Il sélectionne uniquement les nœuds, qui n'ont pas du tout un enfant b = "call_expression". Dans notre exemple, il sélectionne uniquement le nom du sous-arbre d'affectation_expression.

Je soupçonnais que le problème est que Ancestor :: ne prend que le premier élément (dans notre cas A [b = "call_expression"]) et restreint en fonction de son prédicat et plus loin / sont rejetés. J'ai donc modifié la requête XPath comme ceci:

//**b="name".

Cela semble fonctionner uniquement sur le call_expression plus simple (sans le Dot_Expression). Je soupçonnais que le chemin de [] pourrait être relatif uniquement au nœud actuel, et non aux ancêtres potentiels. Mais quand j'ai utilisé la requête

// * [b = "name"] [pas (ancêtre :: a [b = "call_expression"])

Cela a fonctionné comme on pourrait le supposer (tous les noms ce qui n'ont pas d'ancêtre call_expression ont été sélectionnés).

Existe-t-il un moyen de formuler la requête dont j'ai besoin? Et pourquoi les requêtes ne fonctionnent-elles pas?

Merci d'avance :)

Le XML

<a>
 <b>CALL_EXPRESSION</b>
 <c>object.method(a)</c>
 <d>
   <a>
     <b>DOT_EXPRESSION</b>
     <c>object.method</c>
     <d>
       <a>
         <b>NAME_EXPRESSION</b>
         <c>object</c>
         <d>
           <a>
             <b>NAME</b>
             <c>object</c>
             <d>
             </d>
           </a>
         </d>
       </a>
       <a>
         <b>NAME_EXPRESSION</b>
         <c>method</c>
         <d>
           <a>
             <b>NAME</b>
             <c>method</c>
             <d>
             </d>
           </a>
         </d>
       </a>
     </d>
   </a>
   <a>
     <b>PARAMS</b>
     <c>(a)</c>
     <d>
       <a>
         <b>NAME_EXPRESSION</b>
         <c>a</c>
         <d>
           <a>
             <b>NAME</b>
             <c>a</c>
             <d>
             </d>
           </a>
         </d>
       </a>
     </d>
   </a>
 </d>
</a>

<a>
 <b>CALL_EXPRESSION</b>
 <c>puts(b)</c>
 <d>
   <a>
     <b>NAME_EXPRESSION</b>
     <c>puts</c>
     <d>
       <a>
         <b>NAME</b>
         <c>puts</c>
         <d>
         </d>
       </a>
     </d>
   </a>
   <a>
     <b>PARAMS</b>
     <c>(b)</c>
     <d>
       <a>
         <b>NAME_EXPRESSION</b>
         <c>b</c>
         <d>
           <a>
             <b>NAME</b>
             <c>b</c>
             <d>
             </d>
           </a>
         </d>
       </a>
     </d>
   </a>
 </d>
</a>

<a>
 <b>ASSIGNMENT_EXPRESSION</b>
 <c>c=d;</c>
 <d>
   <a>
     <b>NAME_EXPRESSION</b>
     <c>c</c>
     <d>
       <a>
         <b>NAME</b>
         <c>c</c>
         <d>
         </d>
       </a>
     </d>
   </a>
   <a>
     <b>NAME_EXPRESSION</b>
     <c>d</c>
     <d>
       <a>
         <b>NAME</b>
         <c>d</c>
         <d>
         </d>
       </a>
     </d>
   </a>
 </d>
</a>
Était-ce utile?

La solution

Vous n'avez pas dit s'il s'agissait de XPATH 1.0 ou 2.0. Dans XPath 2.0, vous pouvez utiliser l'opérateur sauf: par exemple

//* except //x//*

Pour sélectionner tous les éléments qui n'ont pas X comme ancêtre.

L'opérateur sauf peut également être simulé dans XPATH 1.0 en utilisant l'équivalence

E1 except E2 ==> E1[count(.|E2)!=count(E2)]

(mais prendre soin du contexte de l'évaluation de E2).

Autres conseils

La question n'est pas très claire et le XML fourni n'est pas un document XML bien formé.

Quoi qu'il en soit, voici ma tentative de réponse en fonction de ma compréhension de ce texte de question.

Ayons le document XML simple suivant:

<t>
 <x>
   <y>
     <z>Text 1</z>
   </y>
 </x>
 <x>
  <y>
    <z> Text 2</z>
  </y>
 </x>
</t>

Nous voulons sélectionner tout z éléments qui ne sont pas descendants de /t/x[1]

Utilisez soit cette expression XPATH:

/t/z | /t/x[position() > 1]//z

ou celui-ci:

//z[not(ancestor::x
             [count(ancestor::*) = 1
            and
              not(preceding-sibling::x)
             ]
        )
    ]

Je recommanderais certainement la première expression XPath car il est évidemment beaucoup plus simple, plus court et plus facile à comprendre.

Ça veut dire: Tout sélectionner z Enfants de l'élément supérieur t du document XML et de tous z descendants de tout x Enfant de l'élément supérieur t Ce n'est pas le premier x enfant (dont la position parmi tous x enfants de t n'est pas 1).

La deuxième expression signifie: Tout sélectionner z Éléments du document XML qui n'ont pas un élément aussi ancêtre x qui n'a qu'un seul élément-ancêteur (est un enfant de l'élément supérieur) et n'a pas de frères et sœurs précédents nommés x (En d'autres termes, c'est le premier x enfant de son parent).

Enfin, voici une vérification rapide de l'exactitude des deux expressions XPath:

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

 <xsl:template match="/">
  <xsl:copy-of select=
  "//z[not(ancestor::x
             [count(ancestor::*) = 1
            and
              not(preceding-sibling::x)
             ]
          )
      ]
  "/>

-------------------

 <xsl:copy-of select="/t/z | /t/x[position() > 1]//z"/>
 </xsl:template>
</xsl:stylesheet>

Lorsque cette transformation est appliquée sur le document XML simple (illustré ci-dessus), nous voyons que les deux expressions sélectionnent exactement le recherché z élément. Le résultat de la transformation est:

<z> Text 2</z>

-------------------

 <z> Text 2</z>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top