2012-06-24 34 views
7

Tôi có một cơ sở dữ liệu xml chứa phim, ví dụ:Perl XPath: mục tìm kiếm trước khi một năm ngày

<film id="5"> 
     <title>The Avengers</title> 
     <date>2012-09-24</date> 
     <family>Comics</family> 
</film> 

Từ một kịch bản Perl Tôi muốn tìm phim theo ngày. Nếu tôi tìm kiếm những bộ phim của một năm exacly, ví dụ:

my $query = "//collection/film[date = 2012]"; 

nó hoạt động chính xác và trả lại tất cả những bộ phim của năm 2012, nhưng nếu tôi tìm kiếm tất cả phim trước một năm, nó đã không làm việc, ví dụ:

my $query = "//collection/film[date < 2012]"; 

nó sẽ trả về tất cả các bộ phim ..

+1

liên quan: http://stackoverflow.com/questions/4347320/xpath-dates -comparison – dusan

Trả lời

4

Vâng, như thường lệ, có nhiều hơn một cách để làm điều đó.) Hoặc bạn hãy XPath cụ biết rằng nó nên so sánh ngày (nó không biết từ khi bắt đầu) với một cái gì đó như thế này:

my $query = '//collection/film[xs:date(./date) < xs:date("2012-01-01")]'; 

... hoặc bạn chỉ cắn đạn và chỉ so sánh 'yyyy' chất nền:

my $query = '//collection/film[substring(date, 1, 4) < "2012"]'; 

Thứ hai tốt hơn về mặt ngữ nghĩa, tôi giả sử, nhưng yêu cầu công cụ phân tích cú pháp XML nâng cao hỗ trợ XPath 2.0. Và sau này đã được xác minh thành công với XML :: XPath.

CẬP NHẬT: Tôi muốn giải thích lý do tại sao truy vấn đầu tiên của bạn hoạt động.) Xem, bạn không so sánh các ngày ở đó - bạn so sánh các số, nhưng chỉ vì toán tử '='. Trích dẫn từ the doc:

Khi không phải đối tượng được so sánh là một nút thiết lập và các nhà điều hành là = hoặc =, sau đó các đối tượng được so sánh bằng cách chuyển đổi chúng vào một chung loại như sau và sau đó so sánh chúng! . Nếu ít nhất một đối tượng được so sánh là là một boolean, thì mỗi đối tượng cần so sánh được chuyển đổi thành một boolean như thể bằng cách áp dụng hàm boolean. Nếu không, nếu tại ít nhất một đối tượng được so sánh là một số, thì mỗi đối tượng được được so sánh được chuyển thành một số như thể bằng cách áp dụng hàm số .

See? '2012-09-24' của bạn đã được chuyển thành số - và trở thành 2012. Tất nhiên, đó là bằng với năm 2012.)

Điều này không làm việc với bất kỳ nhà khai thác so sánh nào khác: đó là lý do bạn cần hoặc sử dụng chuỗi con hoặc chuyển đổi chuỗi ngày thành số. Tôi cho rằng cách tiếp cận đầu tiên sẽ dễ đọc hơn - và nhanh hơn nữa, có lẽ.)

+0

+1 giải pháp XPath không hacky hiếm – daxim

1

Sử dụng XPath này, để kiểm tra năm

//collection/film[substring-before(date, '-') &lt; '2012'] 

kịch bản Perl của bạn sẽ được,

my $query = "//collection/film[substring-before(date, '-') &lt; '2012']"; 

HOẶC

my $query = "//collection/film[substring-before(date, '-') = '2012']"; 
0

Đơn giản chỉ cần sử dụng:

//collection/film[translate(date, '-', '') < 20120101] 

Điều này sẽ xóa dấu gạch ngang khỏi ngày sau đó so sánh dấu gạch ngang cho ít hơn 2012-01-01 (với dấu gạch ngang đã bị xóa).

Trong cùng một cách bạn có thể nhận được tất cả các bộ phim với những ngày trước một ngày nhất định (không chỉ trong năm):

//collection/film[translate(date, '-', '') < translate($theDate, '-', ''] 
Các vấn đề liên quan