XPath không phân biệt chữ hoa chữ thường chứa () có được không?


94

Tôi đang chạy trên tất cả các textnode trong DOM của mình và kiểm tra xem nodeValue có chứa một chuỗi nhất định hay không.

/html/body//text()[contains(.,'test')]

Đây là trường hợp nhạy cảm. Tuy nhiên, tôi cũng muốn nắm bắt Test, TESThoặc TesT. Điều đó có khả thi với XPath (trong JavaScript) không?

Câu trả lời:


111

Đây là dành cho XPath 1.0. Nếu môi trường của bạn hỗ trợ XPath 2.0, hãy xem tại đây .


Đúng. Có thể, nhưng không đẹp.

/html/body//text()[
  contains(
    translate(., 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz'),
    'test'
  )
]

Điều này sẽ hoạt động đối với các chuỗi tìm kiếm đã biết trước bảng chữ cái. Thêm bất kỳ ký tự có dấu nào bạn muốn xem.


Nếu bạn có thể, hãy đánh dấu văn bản mà bạn quan tâm bằng một số phương tiện khác, chẳng hạn như đặt nó trong một <span>lớp có một lớp nhất định trong khi xây dựng HTML. Những thứ như vậy dễ dàng xác định vị trí bằng XPath hơn nhiều so với các chuỗi con trong văn bản phần tử.

Nếu đó không phải là một tùy chọn, bạn có thể để JavaScript (hoặc bất kỳ ngôn ngữ máy chủ nào khác mà bạn đang sử dụng để thực thi XPath) giúp bạn xây dựng biểu thức XPath động:

function xpathPrepare(xpath, searchString) {
  return xpath.replace("$u", searchString.toUpperCase())
              .replace("$l", searchString.toLowerCase())
              .replace("$s", searchString.toLowerCase());
}

xp = xpathPrepare("//text()[contains(translate(., '$u', '$l'), '$s')]", "Test");
// -> "//text()[contains(translate(., 'TEST', 'test'), 'test')]"

(Lời khuyên cho câu trả lời của @ KirillPolishchuk - tất nhiên bạn chỉ cần dịch những ký tự mà bạn đang thực sự tìm kiếm .)

Cách tiếp cận này sẽ hoạt động với bất kỳ chuỗi tìm kiếm nào mà không yêu cầu kiến ​​thức trước về bảng chữ cái, đây là một điểm cộng lớn.

Cả hai phương pháp trên đều thất bại khi các chuỗi tìm kiếm có thể chứa các dấu ngoặc kép, trong trường hợp này, mọi thứ trở nên phức tạp hơn .


Cảm ơn! Ngoài ra, bổ sung là tốt đẹp, chỉ dịch các ký tự cần thiết. Tôi rất tò mò về chiến thắng của màn trình diễn này Lưu ý rằng xpathPrepare () có thể xử lý các ký tự xuất hiện nhiều lần theo cách khác nhau (ví dụ: bạn nhận được TEEEEEST và teeeeest).
Aron Woost

@AronWoost: Chà, có thể có một số lợi ích, chỉ cần đánh giá điểm chuẩn nếu bạn muốn tìm hiểu. translate()chính nó không quan tâm tần suất bạn lặp lại mỗi ký tự - translate(., 'EE', 'ee')hoàn toàn tương đương với translate(., 'E', 'e'). PS: Đừng quên bỏ phiếu @KirillPolishchuk, ý tưởng là của anh ấy.
Tomalak

2
System.Xml.XmlNodeList x = mydoc.SelectNodes ("// * [chứa (dịch (text (), 'ABCDEFGHIJKLMNOPQRSTUVWXYZÄÖÜÉÈÊÀÁÂÒÓÔÙÚÛÇÅÏÕÑŒ', 'abcdefghijklmõnqrstuvéóxyzäo');
Stefan Steiger

1
Không. Hãy xem phần "tất nhiên bạn chỉ cần dịch những ký tự mà bạn đang thực sự tìm kiếm" .
Tomalak

61

Đẹp hơn:

/html/body//text()[contains(translate(., 'TES', 'tes'), 'test')]

4
+1 Hoàn toàn đúng. Đó là điều mà tôi không nghĩ tới. (Tôi sẽ sử dụng điều đó trong câu trả lời của mình, điều này tốt hơn nhiều so với quy trình JavaScript ban đầu mà tôi đã viết)
Tomalak 12/12/11

4
nó sẽ không chỉ chuyển đổi TESTthành testvà để lại Testnhư nó là?
Muhammad Adeel Zahid

6
@MuhammadAdeelZahid - Không, đó là thay thế "T" bằng "t", "E" bằng "e", v.v. Đây là trận đấu 1 chọi 1.
Daniel Haley

Nó có thể rõ ràng hơn để làm translate(., 'TES', 'tes'). Bằng cách đó, mọi người sẽ nhận ra đó không phải là một bản dịch từ, mà đó là một bản dịch thư.
mlissner

55

Giải pháp XPath 2.0

  1. Sử dụng chữ thường () :

    /html/body//text()[contains(lower-case(.),'test')]

  2. Sử dụng đối sánh () đối sánh regex với cờ không phân biệt chữ hoa chữ thường:

    /html/body//text()[matches(.,'test', 'i')]


1
Cú pháp này không được hỗ trợ trong Firefox và Chrome? Tôi vừa thử nó trong bảng điều khiển và cả hai đều trả về lỗi cú pháp.
db

1
Firefox và Chrome chỉ triển khai XPath 1.0.
kjhughes

8

Đúng. Bạn có thể sử dụng translateđể chuyển đổi văn bản bạn muốn đối sánh thành chữ thường như sau:

/html/body//text()[contains(translate(., 
                                      'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
                                      'abcdefghijklmnopqrstuvwxyz'),
                   'test')]

6

Nếu bạn đang sử dụng XPath 2.0 thì bạn có thể chỉ định một đối chiếu làm đối số thứ ba để chứa (). Tuy nhiên, URI đối chiếu không được chuẩn hóa nên các chi tiết phụ thuộc vào sản phẩm mà bạn đang sử dụng.

Lưu ý rằng các giải pháp được đưa ra trước đó bằng cách sử dụng translate () đều giả định rằng bạn chỉ đang sử dụng bảng chữ cái tiếng Anh gồm 26 chữ cái.

CẬP NHẬT: XPath 3.1 định nghĩa một URI đối chiếu tiêu chuẩn cho đối sánh phân biệt chữ hoa chữ thường.


3

Cách tôi luôn làm điều này là sử dụng hàm "dịch" trong XPath. Tôi sẽ không nói nó rất đẹp nhưng nó hoạt động chính xác.

/html/body//text()[contains(translate(.,'abcdefghijklmnopqrstuvwxyz',
                                        'ABCDEFGHIJKLOMNOPQRSTUVWXYZ'),'TEST')]

hi vọng điêu nay co ich,

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.