Como selecionar um nó usando XPath se o nó irmão tiver um valor específico?

88

Tenho o seguinte documento:

<a>
  <bb>abc</bb>
  <cc>ccc</cc>
  <dd>ddd</dd>
</a>
<a>
  <bb>zz</bb>
  <cc>1</cc>
  <dd>2</dd>
</a>

Como posso obter o valor de <cc>usar XPath se <bb>for zz?

HOE SENGKIANG
fonte
1
o problema é que eu sei como acessar um nó específico, mas não tenho ideia de como acessar um nó se um irmão tiver um valor específico. Pode ser algo como / a / cc / contains (/ a / bb = 'zz')?
HOE SENGKIANG

Respostas:

100

Não tenho certeza de por que todo mundo está procurando por irmãos, você também pode verificar se há <bb/>elementos correspondentes ao predicado de <a/>:

//a[bb/text() = "zz"]/cc/text()
Jens Erat
fonte
24
"Não sei por que todo mundo está perguntando por irmãos" : Talvez porque a pergunta fosse por irmãos .. ;-)
hr_117
4
Parece que não li o título. :) A resposta permanece válida de qualquer maneira.
Jens Erat
2
Suas perguntas de resposta para irmãos também. Você simplesmente não usou um *-siblingeixo. 1 embora.
LarsH de
Isso não responde à pergunta, mas responde à minha pergunta real que formulou mal. Obrigado!
User9213
37

O que você precisa é do following-siblingeixo XPath

//a/bb[text()="zz"]/following-sibling::cc[1]/text()

Teste o Xpath aqui: http://www.xpathtester.com/obj/b55ec3ac-dfa4-4f44-81e8-f963ea4a0625

Stanley
fonte
4
@HOESENGKIANG: você deve clicar na marca de seleção para "aceitar" esta resposta, ou a que você achar que responde melhor à pergunta.
LarsH
23

P: Como selecionar um nó usando XPath se o nó irmão tiver um valor específico?
Como há apenas "eixos XPath" para irmãos seguintes e irmãos anteriores, você pode usar um deles se a posição for fixa.

Mas melhor: procure cconde os pais têm filhos bbcom valor 'zz':

//cc[../bb='zz']
hr_117
fonte
6
Ou isso ou //a[bb = 'zz']/cc.
Tomalak
Não tenho certeza do que você quer dizer com 'apenas "eixos XPath" para irmão seguidor e irmão anterior'. Você está se referindo ao fato de que não existe um eixo único para todos os irmãos?
LarsH
@LarsH: Sim, desculpe, (desculpe meu péssimo inglês :-() - era isso que eu estava tentando dizer. (Porque a pergunta era para irmãos.)
hr_117
6

Primeiro, seu exemplo não é um XML bem formado. Passando por cima disso e de que você não descreveu muito bem suas intenções (o que exatamente você deseja selecionar e em que condição?), Presumo que queira fazer isso:

//cc[preceding-sibling::bb[text()="zz"]]/text()

Seleciona

TEXT VALUES OF ALL <CC> ELEMENTS
//cc                                    /text()
    THAT HAVE A PRECEDING SIBLING <BB>
    [preceding-sibling::bb             ]
                          THAT HAS TEXT VALUE EQUAL TO "zz"
                          [text()="zz"]

Você poderia escrever também é como

//bb[text()="zz"]/following-sibling::cc/text()

Por favor, olhe as especificações , tem alguns exemplos muito bem legíveis com os quais você aprenderá muito.

Petr Janeček
fonte
1
@LarsH Obrigado pela correção de "não válido" para "não bem formado". Aprendi algo novo hoje.
Petr Janeček
4
//a/cc[../bb='zz']/text()

// a: Seleciona todos os elementos 'a', não importa onde estejam.

// a / cc: Seleciona os elementos 'cc' que são filhos do elemento 'a' (não importa onde a esteja).

..: Seleciona o pai do nó atual.

[../bb='zz ']: onde o valor do elemento irmão' bb 'é zz.

Referência: http://www.w3schools.com/xsl/xpath_syntax.asp

Bae Cheol Shin
fonte
4

Outra solução para este problema é

//bb[contains(.,'zz')]/../cc/text()

Explicação : Qualquer um bbque contenha 'zz'string em todos os nós filhos do bbentão indo para o nó pai desse bbuso .., agora que podemos acessar o cctexto de retorno.

Espero que essa explicação não seja complexa.

Saleh Mahmood
fonte