web-dev-qa-db-fra.com

XPath pour sélectionner plusieurs tags

Étant donné ce format de données simplifié:

<a>
    <b>
        <c>C1</c>
        <d>D1</d>
        <e>E1</e>
        <f>don't select this one</f>
    </b>
    <b>
        <c>C2</c>
        <d>D2</d>
        <e>E1</e>
        <g>don't select me</g>
    </b>
    <c>not this one</c>
    <d>nor this one</d>
    <e>definitely not this one</e>
</a>

Comment sélectionneriez-vous tous les éléments Cs, Ds et Es qui sont les enfants de B éléments?

En gros, quelque chose comme:

a/b/(c|d|e)

Dans ma propre situation, au lieu de simplement a/b/ _, la requête menant à la sélection de ces nœuds C, D, E est en fait assez complexe, aussi je voudrais éviter de faire ceci:

a/b/c|a/b/d|a/b/e

Est-ce possible?

117
nickf

ne bonne réponse est:

/a/b/*[self::c or self::d or self::e]

Notez que ceci

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']

est à la fois trop long et incorrect. Cette expression XPath sélectionnera les nœuds suivants:

OhMy:c

NotWanted:d 

QuiteDifferent:e
189

Vous pouvez éviter la répétition avec un test d'attribut à la place:

a/b/*[local-name()='c' or local-name()='d' or local-name()='e']

Contrairement à l'opinion antagoniste de Dimitre, ce qui précède est non incorrect dans un vide où le PO n'a pas spécifié l'interaction avec les espaces de noms. L'axe self:: Est un espace de noms restrictif, local-name() ne l'est pas. Si l'intention de l'OP est de capturer c|d|e Indépendamment de l'espace de noms (ce qui, selon moi, est un scénario probable étant donné la nature du problème OR)], il s'agit "d'une autre réponse cela a encore quelques votes positifs "ce qui est incorrect.

Vous ne pouvez pas être définitif sans définition, bien que je sois assez heureux de supprimer ma réponse comme étant véritablement incorrecte si le PO clarifie sa question de telle sorte que je me trompe.

42
annakata

Pourquoi pas a/b/(c|d|e)? Je viens d'essayer avec bibliothèque XML Saxon (bien emballé avec un peu de bonté Clojure), et cela semble fonctionner. abc.xml est le document décrit par OP.

(require '[saxon :as xml])
(def abc-doc (xml/compile-xml (Slurp "abc.xml")))
(xml/query "a/b/(c|d|e)" abc-doc)
=> (#<XdmNode <c>C1</c>>
    #<XdmNode <d>D1</d>>
    #<XdmNode <e>E1</e>>
    #<XdmNode <c>C2</c>>
    #<XdmNode <d>D2</d>>
    #<XdmNode <e>E1</e>>)
13
Pavel Repin