Nhận các nút trong đó nút con chứa một thuộc tính


116

Giả sử tôi có XML sau:

<book category="CLASSICS">
  <title lang="it">Purgatorio</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CLASSICS">
  <title lang="it">Inferno</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CHILDREN">
  <title lang="en">Harry Potter</title>
  <author>J K. Rowling</author>
  <year>2005</year>
  <price>29.99</price>
</book>

<book category="WEB">
  <title lang="en">XQuery Kick Start</title>
  <author>James McGovern</author>
  <author>Per Bothner</author>
  <author>Kurt Cagle</author>
  <author>James Linn</author>
  <author>Vaidyanathan Nagarajan</author>
  <year>2003</year>
  <price>49.99</price>
</book>

<book category="WEB">
  <title lang="en">Learning XML</title>
  <author>Erik T. Ray</author>
  <year>2003</year>
  <price>39.95</price>
</book>

Tôi muốn thực hiện một xpath lấy lại tất cả các nút sách có nút tiêu đề với thuộc tính ngôn ngữ là "it".

Nỗ lực của tôi trông giống như thế này:

//book[title[@lang='it']]

Nhưng điều đó đã không thành công. Tôi mong đợi để lấy lại các nút:

<book category="CLASSICS">
  <title lang="it">Purgatorio</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

<book category="CLASSICS">
  <title lang="it">Inferno</title>
  <author>Dante Alighieri</author>
  <year>1308</year>
  <price>30.00</price>
</book>

Bất kỳ gợi ý?


Đây là cách triển khai XPath nào?
Pavel Minaev 25/09/09

Câu trả lời:


175

Thử

//book[title/@lang = 'it']

Điều này đọc:

  • lấy tất cả bookcác yếu tố
    • có ít nhất một title
      • có một thuộc tính lang
        • với giá trị là "it"

Bạn có thể thấy điều này hữu ích - đó là một bài báo có tựa đề "XPath trong năm đoạn văn" của Ronald Bourret.

Nhưng thành thật mà nói, //book[title[@lang='it']]và những điều trên phải tương đương nhau, trừ khi công cụ XPath của bạn có "vấn đề". Vì vậy, nó có thể là một cái gì đó trong mã hoặc mẫu XML mà bạn không hiển thị cho chúng tôi - ví dụ: mẫu của bạn là một đoạn XML. Có thể phần tử gốc có một vùng tên và bạn không tính vùng đó trong truy vấn của mình? Và bạn chỉ nói với chúng tôi rằng nó không hoạt động, nhưng bạn không cho chúng tôi biết bạn đã nhận được kết quả gì.


4
Làm thế nào để làm điều tương tự nếu titlekhông phải là con trực tiếp của book, nhưng ở đâu đó sâu hơn và chúng tôi không biết chính xác ở đâu? //book[/title/@lang = 'it']dường như không hoạt động?
Martin Konicek

5
Martin, bạn có thể sử dụng //book[.//title/@lang = 'it']. Tôi tin rằng thủ thuật là dấu "." ở phần đầu của điều kiện.
Bruno Caponi

1
Cảm ơn vì liên kết, bài viết xuất sắc. Tôi đã sử dụng xPath trong nhiều năm nhưng điều này thực sự giúp tôi hiểu được logic cơ bản!
swensor

57

Nhiều năm sau, nhưng một lựa chọn hữu ích sẽ là sử dụng XPath Axes ( https://www.w3schools.com/xml/xpath_axes.asp ). Cụ thể hơn, bạn đang tìm cách sử dụng các trục con cháu .

Tôi tin rằng ví dụ này sẽ thực hiện thủ thuật:

//book[descendant::title[@lang='it']]

Điều này cho phép bạn chọn tất cả book phần tử có chứa titlephần tử con (bất kể phần tử đó được lồng sâu như thế nào) có chứa giá trị thuộc tính ngôn ngữ bằng 'nó'.

Tôi không thể nói chắc liệu câu trả lời này có liên quan đến năm 2009 hay không vì tôi không chắc chắn 100% rằng Trục XPath đã tồn tại vào thời điểm đó. Điều tôi có thể xác nhận là chúng vẫn tồn tại cho đến ngày nay và tôi thấy chúng cực kỳ hữu ích trong việc điều hướng XPath và tôi chắc chắn rằng bạn cũng sẽ như vậy.


12
//book[title[@lang='it']]

thực sự tương đương với

 //book[title/@lang = 'it']

Tôi đã thử sử dụng vtd-xml, cả hai biểu thức đều cho ra kết quả giống nhau ... bạn đã sử dụng công cụ xử lý xpath nào? Tôi đoán nó có vấn đề về tuân thủ Dưới đây là mã

import com.ximpleware.*;
public class test1 {
  public static void main(String[] s) throws Exception{
      VTDGen vg = new VTDGen();
      if (vg.parseFile("c:/books.xml", true)){
          VTDNav vn = vg.getNav();
          AutoPilot ap = new AutoPilot(vn);
          ap.selectXPath("//book[title[@lang='it']]");
                  //ap.selectXPath("//book[title/@lang='it']");

          int i;
          while((i=ap.evalXPath())!=-1){
              System.out.println("index ==>"+i);
          }
          /*if (vn.endsWith(i, "< test")){
             System.out.println(" good ");  
          }else
              System.out.println(" bad ");*/

      }
  }
}

+1 rằng nó là một vấn đề tuân thủ và cú pháp tạo ra cùng một tập hợp các nút. Mã tương tự trong C # cũng hoạt động.
Zach Bonham 22/09/09

-1: Ông Zhang, tôi đang cố gắng giúp ông bằng cách xóa mã không liên quan đến câu hỏi. Nó cho phép tôi không từ chối bạn, điều mà bây giờ tôi cảm thấy mình phải làm. Lưu ý rằng không có câu trả lời nào khác bao gồm mã để gọi truy vấn.
John Saunders

6
+1: Vì tôi không thể hiểu ông Saunders đang nói về điều gì - không có câu trả lời nào khác được thêm vào BẤT KỲ mã nào và câu trả lời này hiển thị mã được sử dụng để chúng tôi có thể 1: xác thực phương pháp của ông ấy và 2: tự thực hiện bài kiểm tra của ông ấy. Mã ngắn và dễ đọc. Tôi không thấy vấn đề.
DuckPuppy

4

Tôi nghĩ rằng đề xuất của riêng bạn là đúng, tuy nhiên xml không hoàn toàn hợp lệ. Nếu bạn đang //book[title[@lang='it']]bật <root>[Your"XML"Here]</root>thì những người kiểm tra xPath trực tuyến miễn phí như ở đây sẽ tìm thấy kết quả mong đợi.


2

Cố gắng sử dụng biểu thức xPath này:

//book/title[@lang='it']/..

Điều đó sẽ cung cấp cho bạn tất cả các nút sách trong ngôn ngữ "nó"


2
kết quả của biểu thức đó là các nút tiêu đề, không phải nút sách
Caleth

2
Điều đó không đúng. Nó sẽ trả về các nút sách (hai dấu chấm này ở cuối nhằm nhắm vào nút trên của nút tiêu đề).
user1113000
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.