2009-04-06 28 views
89

Với này đơn giản hóa định dạng dữ liệu:XPath để chọn nhiều thẻ

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

Làm thế nào bạn sẽ chọn tất cả các C s, D s và E s mà là con của B yếu tố?

Về cơ bản, một cái gì đó như:

a/b/(c|d|e) 

Trong tình huống của riêng tôi, thay vì chỉ a/b/, truy vấn dẫn đến việc lựa chọn những C, D, E nút là thực sự khá phức tạp vì vậy tôi muốn tránh làm điều này:

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

Điều này có thể không?

Trả lời

150

Một Câu trả lời đúng là:

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

Đỗ lưu ý t mũ này

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

là cả quá dài và không chính xác. Biểu thức XPath này sẽ chọn các nút như:

OhMy:c 

NotWanted:d 

QuiteDifferent:e 
+0

'hoặc' không hoạt động trên mỗi cái, bạn sẽ cần phải sử dụng một đường thẳng đứng thay vì '|' –

+5

@ Guasqueño, 'hoặc' là toán tử logic - nó hoạt động trên hai giá trị Boolean. Toán tử XPath ** union ** '|' hoạt động trên hai tập hợp các nút. Đây là những trường hợp khá khác nhau và có những trường hợp sử dụng cụ thể cho từng trường hợp. Sử dụng '|' ** có thể ** giải quyết vấn đề ban đầu, nhưng nó dẫn đến một biểu thức XPath dài hơn và phức tạp hơn và khó khăn hơn. Biểu thức đơn giản hơn trong câu trả lời này, sử dụng toán tử 'hoặc' tạo ra tập nút mong muốn và * có thể được xác định trong thuộc tính" select "của một hoạt động' 'XSLT. Hãy thử nó. –

40

Bạn có thể tránh sự lặp lại với một bài kiểm tra thuộc tính thay vì:

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

Trái ngược với quan điểm đối kháng Dimitre của, phía trên là không sai trong chân không nơi OP đã không được chỉ rõ sự tương tác với không gian tên. Trục self:: là giới hạn không gian tên, local-name() thì không. Nếu ý định của OP là chụp c|d|e bất kể không gian tên (mà tôi đề nghị thậm chí là một kịch bản có khả năng cho bản chất OR của vấn đề) thì đó là "một câu trả lời khác vẫn có một số phiếu tích cực" là không chính xác.

Bạn không thể dứt khoát mà không có định nghĩa, mặc dù tôi khá vui khi xóa câu trả lời của tôi là thực sự không chính xác nếu OP làm rõ câu hỏi của mình sao cho tôi không chính xác.

+0

Điểm * rất rõ ràng của tôi là bạn và tôi không thể dứt khoát được, và câu trả lời của bạn bị thất lạc vì câu trả lời của tôi không hoàn toàn sai. Thực tế OP chấp nhận một câu trả lời là không liên quan, vì anh ta không thể chấp nhận cả hai, cả hai đều sẽ làm việc cho hầu hết các trường hợp, và tôi đã bị xóa vào lúc đó. – annakata

+3

Hơn nữa, tôi nói rằng tôi phản đối cái gọi là "sự kiện" của bạn, và nó là * ý kiến ​​của tôi * rằng bạn đang đối lập một cách minh bạch. Ý kiến ​​của bạn có mục đích gì "vẫn có phiếu bầu tích cực" và "Tôi giải thích lý do tại sao bình chọn được bỏ phiếu nhiều nhất vào lúc này là không chính xác" phục vụ? – annakata

+0

Không, không thể xác định chính xác - tôi đã nói nhiều lần: cả hai đều có thể đúng, cả hai đều hoạt động trên một tài liệu đơn giản, nó hoàn toàn phụ thuộc vào những gì OP muốn từ việc đặt tên. Bạn dường như cố tình không biết gì về điều này, có lẽ bởi vì nó có thể đưa bạn vào sai? – annakata

-2

Không chắc chắn nếu điều này giúp, nhưng với XSL, tôi muốn làm một cái gì đó như:

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

và sẽ không XPath này chọn tất cả các con của nút B:

a/b/* 
+0

Cảm ơn Calvin, nhưng tôi không sử dụng XSL, và có nhiều phần tử bên dưới B mà tôi không muốn chọn. Tôi sẽ cập nhật ví dụ của mình để rõ ràng hơn. – nickf

+0

Ồ, trong trường hợp đó, annakata dường như có giải pháp. – Calvin

11

Tại sao không a/b/(c|d|e)? Tôi chỉ thử với Saxon XML library (được gói gọn với một số điều tốt lành của Clojure), và có vẻ như nó hoạt động. abc.xml là tài liệu được mô tả bởi 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>>) 
+4

Có, nhưng đó là XPath 2.0 –

+1

@Alejandro, tuyệt! Tôi đã đi xa (blissfully) từ thế giới XML trong 4 năm, có vẻ như XPath đã di chuyển lên đến 2.0 :) –

+0

Điều này làm việc tốt cho tôi. Có vẻ XPath 2.0 là mặc định cho phân tích cú pháp HTML trong lxml trên Python 2. –

Các vấn đề liên quan