여러 개의 태그를 선택하는 XPath


132

이 단순화 된 데이터 형식이 주어지면 :

<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>

어떻게 모든 선택 것 CS, Ds와 E의 자녀의 B요소를?

기본적으로 다음과 같은 것이 있습니다.

a/b/(c|d|e)

대신 내 자신의 상황에서 a/b/, 사람들을 선택에 이르기까지의 쿼리 C, D, E노드가 실제로는 매우 복잡 나는이 일을하지 않도록하고 싶습니다 있도록 :

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

이게 가능해?

답변:


207

정답은 다음과 같습니다.

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

이 점에 유의하십시오

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

너무 길고 잘못되었습니다 . 이 XPath 표현식은 다음과 같은 노드를 선택합니다.

OhMy:c

NotWanted:d 

QuiteDifferent:e

2
'또는'for-each에서 작동하지 않으면 '|'대신 수직선을 사용해야합니다.
Guasqueño

8
@ Guasqueño or는 논리 연산자이며 두 개의 부울 값에서 작동합니다. XPath 공용체 연산자 |는 두 개의 노드 세트에서 작동합니다. 이들은 상당히 다르며 각각에 대한 특정 사용 사례가 있습니다. 를 사용 하면 원래 문제를 해결할 | 있지만 XPath 표현식을 이해하는 것이 더 길고 복잡하며 어려워집니다. or연산자 를 사용하는이 답변의 간단한 표현 은 원하는 노드 세트를 생성 하며 XSLT 작업 의 "select"속성에서 지정할 있습니다 <xsl:for-each>. 먹어봐.
Dimitre Novatchev

4
@JonathanBenn, "네임 스페이스를 신경 쓰지 않는 사람"은 실제로 XML을 신경 쓰지 않으며 XML을 사용하지 않습니다. 의 사용은 local-name()요소가에있는 공간에 상관없이, 우리는 그 지역의 이름을 가지는 모든 요소를 선택하려는 경우에만 올바른 이것은 매우 드문 경우입니다 - 일반적으로 사람의 차이점에 대한 관리를 수행합니다. kitchen:table그리고 sql:table, 또는 사이 architecture:column, sql:column, array:column,military:column
Dimitre Novatchev

2
@DimitreNovatchev 당신은 좋은 지적을합니다. 네임 스페이스가 그렇게 중요하지 않은 경우 인 HTML 검사에 XPath를 사용하고 있습니다.
Jonathan Benn

2
슈퍼입니다. 그걸 어디서 났어?
Keith Tyler

46

대신 속성 테스트를 사용하여 반복을 피할 수 있습니다.

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

Dimitre의 적대적 견해와는 달리 , OP가 네임 스페이스와의 상호 작용을 지정하지 않은 진공 상태에서는 위의 내용이 올바르지 않습니다 . self::축 공간 제한적인, local-name()아니다. OP의 의도가 c|d|e네임 스페이스에 관계없이 캡처하는 것이라면 (문제의 OR 특성을 감안할 때 시나리오라고 생각할 수도 있음) "정확한 투표가 여전히 남아있는 또 다른 대답"입니다.

OP가 자신의 질문에 명확하지 않은 답변을 명확하게 표시하면 답변을 진정으로 잘못된 것으로 삭제해도 무척 기쁘지만 정의없이 확정 할 수는 없습니다.


3
여기서 제 3 자라고 말하면 개인적으로 Dimitre의 제안은 사용자가 네임 스페이스와 관련이없는 태그 이름에 대해 명시 적이며 좋은 이유가있는 경우를 제외하고는 더 나은 방법이라고 생각합니다. 다른 네임 스페이스 콘텐츠 (아마도 다른 툴 체인에서 읽을 수 있음)로 혼합 된 문서에 대해이 작업을 수행 한 사람은 해당 동작이 매우 부적절한 것으로 간주합니다. 즉, 당신이 제안한 바와 같이 논쟁은 조금 엉망입니다.
Charles Duffy

4
정확히 내가 찾던 것. XML 네임 스페이스는 실생활에서 사용되는 방식이 거칠지 않습니다. / a / b / ( : c | : d | * e) 와 같은 것을 지정할 수 없으면 솔루션이 꼭 필요한 것입니다. 순수 주의자는 원하는 모든 것을 주장 할 수 있지만 사용자는 입력 파일을 생성 한 모든 것이 네임 스페이스를 망 쳤기 때문에 앱이 중단되는 것을 신경 쓰지 않습니다. 그들은 단지 그것이 작동하기를 원합니다.
Ghostrider

7
나는이 두 답변의 차이점이 무엇인지 모호한 아이디어 만 가지고 있으며 아무도 설명하지 않았습니다. "네임 스페이스 제한"이란 무엇입니까? 을 사용 local-name()하면 네임 스페이스와 태그가 일치한다는 의미입니까? 를 사용 self::하면 어떤 네임 스페이스와 일치해야합니까? 내가 어떻게 일치 OhMy:c합니까?
meustrus

15

왜 안돼 a/b/(c|d|e)? 방금 Saxon XML 라이브러리 (Clojure의 장점으로 멋지게 포장)를 사용해 보았지만 작동하는 것 같습니다. abc.xmlOP에서 설명한 문서입니다.

(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>>)

8
예, 그러나 그것은 XPath 2.0입니다

이것은 나를 위해 잘 작동했습니다. XPath 2.0은 Python 2에서 lxml의 HTML 구문 분석에 대한 기본값 인 것 같습니다.
Martin Burch

-1

이것이 도움이되는지 확실하지 않지만 XSL을 사용하면 다음과 같은 작업을 수행합니다.

<xsl:for-each select="a/b">
    <xsl:value-of select="c"/>
    <xsl:value-of select="d"/>
    <xsl:value-of select="e"/>
</xsl:for-each>

이 XPath가 B 노드의 모든 하위를 선택하지는 않습니다.

a/b/*

Calvin에게 감사하지만 XSL을 사용하지 않고 실제로 B 아래에 선택하고 싶지 않은 요소가 더 있습니다. 더 명확하게 예제를 업데이트하겠습니다.
nickf

아, 그렇다면 annakata는 해결책을 가지고있는 것 같습니다.
Calvin
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.