둘 이상의 Text 하위 노드가있는 노드와 함께 사용하면 XPath contains (text (), 'some string')이 작동하지 않습니다


258

Xpath에 dom4j에 포함 된 작은 문제가 있습니다 ...

내 XML이

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

루트 요소가 주어진 텍스트에서 ABC가있는 모든 노드를 찾고 싶다고 가정 해 보겠습니다.

그래서 내가 작성해야 할 xpath는

//*[contains(text(),'ABC')]

그러나 이것은 Dom4j가 반환하는 것이 아닙니다 .... 이것이 dom4j 문제 또는 xpath 작동 방식을 이해하는 것입니다. 이 쿼리는 Comment 요소가 아닌 Street 요소 만 반환하므로

DOM은 Comment 요소를 4 개의 태그가 2 인 복합 요소로 만듭니다.

[Text = 'XYZ'][BR][BR][Text = 'ABC'] 

나는 요소를 찾아서 실행해야하기 때문에 쿼리가 여전히 요소를 반환해야한다고 가정하지만 ... ...

다음 쿼리는 요소를 반환하지만 요소보다 훨씬 더 많이 반환하고 부모 요소도 반환합니다 ... 문제에 바람직하지 않습니다 ...

//*[contains(text(),'ABC')]

하나는 바로 요소 반환 XPath 쿼리 알고 있나요 <Street/><Comment/>?


내가 알 수 //*[contains(text(),'ABC')]있는 한 <Street>요소 만 반환합니다 . <Street>또는의 조상을 반환하지 않습니다 <Comment>.
Ken Bloom

답변:


706

<Comment>태그는 두 개의 텍스트 노드와이 개 포함 <br>자식으로 노드를.

당신의 xpath 표현은

//*[contains(text(),'ABC')]

이것을 분해하기 위해

  1. * 모든 요소 (예 : 태그)와 일치하는 선택기입니다. 노드 세트를 반환합니다.
  2. []노드 세트 내의 각각의 노드에서 동작하는 조건이다. 작동하는 개별 노드 중 하나가 대괄호 안의 조건과 일치하면 일치합니다.
  3. text()컨텍스트 노드의 하위 인 모든 텍스트 노드와 일치 하는 선택기 입니다. 노드 세트를 반환합니다.
  4. contains문자열에서 작동하는 함수입니다. 노드 세트에 전달되면 노드 세트 에서 문서 순서로 첫 번째 인 노드의 문자열 값을 리턴 하여 노드 세트를 문자열로 변환 합니다. 따라서 <Comment>요소 의 첫 번째 텍스트 노드와 만 일치 할 수 있습니다 BLAH BLAH BLAH. 일치하지 않기 때문에 <Comment>결과를 얻지 못합니다 .

이것을 다음으로 변경해야합니다

//*[text()[contains(.,'ABC')]]
  1. * 모든 요소 (예 : 태그)와 일치하는 선택기입니다. 노드 세트를 반환합니다.
  2. 바깥 쪽 []은 해당 노드 세트의 각 개별 노드에서 작동하는 조건부입니다. 여기서는 문서의 각 요소에서 작동합니다.
  3. text()컨텍스트 노드의 하위 인 모든 텍스트 노드와 일치 하는 선택기 입니다. 노드 세트를 반환합니다.
  4. 내부 []는 해당 노드 세트의 각 노드 (여기서는 개별 텍스트 노드)에서 작동하는 조건부입니다. 각 개별 텍스트 노드는 괄호 안에있는 경로의 시작점이며 괄호 안에 명시 적으로 언급 될 수도 있습니다 .. 작동하는 개별 노드 중 하나가 대괄호 안의 조건과 일치하면 일치합니다.
  5. contains문자열에서 작동하는 함수입니다. 여기에는 개별 텍스트 노드 ( .) 가 전달 됩니다. <Comment>태그 의 두 번째 텍스트 노드가 개별적 으로 전달되므로 'ABC'문자열 을보고 일치시킬 수 있습니다.

1
굉장한 메신저 xpath 멍청한 놈, 그래서 이것을 얻자, text ()는 contains (., 'ABC') 표현식을 취하는 함수입니다. 바보 같은 물건;)
Mike Milkin

28
자세한 설명을 제공하기 위해 답변을 편집했습니다. 나는 XPath에 대해 많이 알지 못한다. 나는 그 조합을 우연히 발견 할 때까지 조금 실험했다. 일단 조합 작업을 한 후에는 무슨 일이 있었는지 추측하고 XPath 표준 을 살펴보고 무슨 일이 있었 는지 확인하고 설명을 작성했습니다.
Ken Bloom

2
대소 문자를 구분하지 않고 검색하려면 어떻게 하시겠습니까?

@Zack :이 질문을 새로운 질문으로 만드십시오.
user1129682

1
나는 이것이 오래된 스레드라는 것을 알고 있지만, 근본적으로 차이가 있는지, 누구든지 Ken Bloom과 //*[contains(., 'ABC')]. 나는 항상 Mike Milkin이 제공 한 패턴을 사용하여 더 적절하다고 생각했지만 contains현재 컨텍스트에서 수행하는 것이 실제로 더 자주 원하는 것 같습니다.
knickum

7

[contains(text(),'')]true 또는 false 만 반환합니다. 요소 결과를 반환하지 않습니다.


''또는 ''가 있으면 어떻게 작동하지 않습니까?
shareef

contains(text(),'JB-')작동하지 않습니다! conatains소요 두 개의 문자열 인수로를 - contains(**string**, **string**)! text () 는 string이 아니며 함수입니다!
AtachiShadow

6

XML 문서 :

<Home>
    <Addr>
        <Street>ABC</Street>
        <Number>5</Number>
        <Comment>BLAH BLAH BLAH <br/><br/>ABC</Comment>
    </Addr>
</Home>

XPath 표현식 :

//*[contains(text(), 'ABC')]

//*루트 노드 의 모든 하위 요소 와 일치 . 즉, 루트 노드 이외의 모든 요소입니다.

[...]A는 술어 , 그것은 노드 집합을 필터링합니다. 하는 것은 노드를 반환하는 ...것입니다 true:

술어는 노드 세트 [...]를 필터링하여 새 노드 세트를 생성합니다. 필터링 된 노드 집합의 각 노드에 대해 PredicateExpr이 평가됩니다 [...]; PredicateExpr이 해당 노드에 대해 true로 평가되면 해당 노드는 새 노드 세트에 포함됩니다. 그렇지 않으면 포함되지 않습니다.

contains('haystack', 'needle')포함하는true 경우를 반환 합니다 .haystack needle

함수 : 부울 포함 (문자열, 문자열)

contains 함수는 첫 번째 인수 문자열에 두 번째 인수 문자열이 포함되어 있으면 true를 반환하고 그렇지 않으면 false를 반환합니다.

그러나 contains()문자열을 첫 번째 매개 변수로 사용합니다. 그리고 그것은 통과 된 노드입니다. 이를 처리하기 위해 첫 번째 매개 변수로 전달 된 모든 노드 또는 노드 세트 가 함수에 의해 문자열로 변환 됩니다 string().

문자열 함수를 호출하여 인수가 문자열 유형으로 변환됩니다.

string()첫 번째 노드string-value 의 함수 반환 :

노드 세트는 문서 순서에서 첫 번째 인 노드 세트에있는 노드의 문자열 값을 리턴하여 문자열로 변환됩니다. 노드 집합이 비어 있으면 빈 문자열이 반환됩니다.

string-value요소 노드 :

요소 노드의 문자열 값은 문서 노드에서 요소 노드의 모든 텍스트 노드 자손의 문자열 값을 연결 한 것입니다.

string-value(A)의 텍스트 노드 :

텍스트 노드의 문자열 값은 문자 데이터입니다.

따라서 기본적으로 string-value노드에 포함 된 모든 텍스트 (모든 자손 텍스트 노드의 연결)입니다.

text() 모든 텍스트 노드와 일치하는 노드 테스트입니다.

모든 텍스트 노드에 대해 노드 테스트 text ()가 true입니다. 예를 들어 child :: text ()는 컨텍스트 노드의 텍스트 노드 자식을 선택합니다.

이 말을 //*[contains(text(), 'ABC')]하면 첫 번째 텍스트 노드가 포함하는 모든 요소 (그러나 루트 노드)와 일치합니다 ABC. text()컨텍스트 노드의 모든 하위 텍스트 노드가 포함 된 노드 세트를 리턴 하므로 (표현식에 상대적) 그러나 contains()첫 번째 것만 취합니다. 따라서 위의 문서의 경우 경로가 Street요소 와 일치합니다 .

다음 표현식 //*[text()[contains(., 'ABC')]]은 하나 이상의 하위 텍스트 노드가 있고을 포함하는 모든 요소 (그러나 루트 노드)와 일치합니다 ABC. .컨텍스트 노드를 나타냅니다. 이 경우 루트 노드를 제외한 모든 요소의 하위 텍스트 노드입니다. 위의 문서의 경우 경로는 Street,Comment 요소 .

이제 하위 텍스트 노드의 연결에 //*[contains(., 'ABC')]포함 된 모든 요소 (그러나 루트 노드)와 일치합니다 ABC. 가 일치 위의 문서 HomeAddrStreet, 그리고 Comment요소를. 따라서, //*[contains(., 'BLAH ABC')]성냥 HomeAddr,와 Comment요소를.


0

시간이 조금 걸렸지 만 마침내 알아 냈습니다. 아래에 일부 텍스트가 포함 된 사용자 지정 xpath가 완벽하게 작동했습니다.

//a[contains(text(),'JB-')]

2
contains(text(),'JB-')작동하지 않습니다! conatains소요 두 개의 문자열 인수로를 - contains(**string**, **string**)! text () 는 string이 아니며 함수입니다!
AtachiShadow

0

수락 된 답변은 모든 부모 노드도 반환합니다. 문자열이 뒤에 오는 경우에도 ABC로 실제 노드 만 가져 오려면 다음을 수행하십시오
.

//*[text()[contains(.,'ABC')]]/text()[contains(.,"ABC")]

0
//*[text()='ABC'] 

보고

<street>ABC</street>
<comment>BLAH BLAH BLAH <br><br>ABC</comment>

3
5 개의 기존 답변이있는 9 살짜리 질문에 대한 답변을 추가 할 때 답변에서 다루는 질문의 어떤 독특한 새 측면을 지적하는 것이 매우 중요합니다.
Jason Aller

내가 게시 한 답변은 매우 간단했습니다. 나 같은 초보자에게 도움이 될 수있는 공유를 생각했습니다.
user3520544
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.