2008-10-22 22 views
79

Bất cứ ai cũng biết cách lấy vị trí của một nút bằng cách sử dụng xpath?Tìm vị trí của một nút bằng cách sử dụng xpath

Nói rằng tôi có xml sau:

<a> 
    <b>zyx</b> 
    <b>wvu</b> 
    <b>tsr</b> 
    <b>qpo</b> 
</a> 

tôi có thể sử dụng truy vấn xpath sau đây để chọn thứ ba <b> nút (<b> TSR </b >):

a/b[.='tsr'] 

Đó là tất cả tốt và tốt nhưng tôi muốn trả lại vị trí thứ tự của nút đó, chẳng hạn như:

a/b[.='tsr']/position() 

(nhưng làm việc nhiều hơn một chút!)

Là nó thậm chí có thể?

chỉnh sửa: Quên đề cập đến đang sử dụng .net 2 vì vậy nó là xpath 1.0!


Cập nhật: Đã kết thúc bằng James Sulak 's excellent answer. Đối với những người quan tâm, đây là triển khai của tôi trong C#:

int position = doc.SelectNodes("a/b[.='tsr']/preceding-sibling::b").Count + 1; 

// Check the node actually exists 
if (position > 1 || doc.SelectSingleNode("a/b[.='tsr']") != null) 
{ 
    Console.WriteLine("Found at position = {0}", position); 
} 

Trả lời

84

Hãy thử:

count(a/b[.='tsr']/preceding-sibling::*)+1. 
+1

'Coz Tôi đang sử dụng .net hoặc là nó hoặc tôi không thể xử lý sức mạnh tôi đã đi với: int position = doc.SelectNodes ("a/b [. =' Tsr ']/trước-Sibling :: b ") .Count + 1; if (position> 1 || doc.SelectSingleNode ("a/b [. = 'tsr']")! = null) // Kiểm tra nút thực sự tồn tại {// Do magic here} –

+0

trong các ngôn ngữ được lập chỉ mục bằng không bạn don ' t cần +1 –

8

Bạn có thể làm điều này với XSLT nhưng tôi không chắc chắn về XPath thẳng.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" encoding="utf-8" indent="yes" 
       omit-xml-declaration="yes"/> 
    <xsl:template match="a/*[text()='tsr']"> 
    <xsl:number value-of="position()"/> 
    </xsl:template> 
    <xsl:template match="text()"/> 
</xsl:stylesheet> 
1

Vấn đề là vị trí của các nút không có nghĩa là nhiều mà không có một bối cảnh.

Đoạn mã dưới đây sẽ cung cấp cho bạn vị trí của nút trong mẹ nút con của nó

using System; 
using System.Xml; 

public class XpathFinder 
{ 
    public static void Main(string[] args) 
    { 
     XmlDocument xmldoc = new XmlDocument(); 
     xmldoc.Load(args[0]); 
     foreach (XmlNode xn in xmldoc.SelectNodes(args[1])) 
     { 
      for (int i = 0; i < xn.ParentNode.ChildNodes.Count; i++) 
      { 
       if (xn.ParentNode.ChildNodes[i].Equals(xn)) 
       { 
        Console.Out.WriteLine(i); 
        break; 
       } 
      } 
     } 
    } 
} 
+1

Vì vậy, không thực sự là công cụ tìm XPath ngay bây giờ, mà là công cụ tìm C#. – jamesh

0

tôi làm rất nhiều Novell Identity Manager công cụ, và XPATH trong bối cảnh đó trông hơi khác một chút.

Giả sử giá trị mà bạn đang tìm kiếm là một biến chuỗi, được gọi là mục tiêu, sau đó các XPATH sẽ là: sẽ

count(attr/value[.='$TARGET']/preceding-sibling::*)+1 

Bên cạnh đó nó đã được chỉ ra rằng để tiết kiệm một vài ký tự không gian, sau đây làm việc cũng như:

count(attr/value[.='$TARGET']/preceding::*) + 1 

tôi cũng đăng tải một phiên bản đẹp của này tại Solutions mát Novell: Using XPATH to get the position node

3

Không giống như previou nêu sly 'preceding-sibling' thực sự là trục để sử dụng, không phải là 'trước' làm điều gì đó hoàn toàn khác, nó chọn mọi thứ trong tài liệu trước thẻ bắt đầu của nút hiện tại. (xem http://www.w3schools.com/xpath/xpath_axes.asp)

+4

Không bao gồm nút tổ tiên. Đừng tin tưởng w3schools về các chi tiết! Nhưng tôi đồng ý ... mặc dù trước đó :: hoạt động trong trường hợp này, bởi vì không có yếu tố nào trước các phần tử b có liên quan khác với tổ tiên, nó dễ vỡ hơn so với trước-anh chị em. OTOH, OP không cho chúng tôi biết ngữ cảnh nào ông muốn biết vị trí bên trong, vì vậy có khả năng trước :: có thể đúng. – LarsH

5

Tôi nhận thấy rằng bài đăng là cổ .. nhưng ..

replace'ing dấu hoa thị với nodename sẽ cung cấp cho bạn kết quả tốt hơn

count(a/b[.='tsr']/preceding::a)+1. 

thay vì

count(a/b[.='tsr']/preceding::*)+1. 
1

Chỉ cần một lưu ý cho câu trả lời thực hiện bởi James Sulak.

Nếu bạn muốn xem xét rằng nút có thể không tồn tại và muốn giữ nó hoàn toàn XPATH, hãy thử sau đây sẽ trả về 0 nếu nút không tồn tại.

count(a/b[.='tsr']/preceding-sibling::*)+number(boolean(a/b[.='tsr'])) 
1

Nếu bạn đã từng nâng cấp lên XPath 2.0, lưu ý rằng nó cung cấp chức năng index-of, nó giải quyết vấn đề theo cách này:

index-of(//b, //b[.='tsr']) 

đâu:

  • tham số 1 là chuỗi để tìm kiếm
  • thứ 2 là những gì cần tìm kiếm
+0

Cần lưu ý rằng điều này sẽ chỉ hoạt động với XPath 2+. Bất cứ điều gì dưới đây sẽ phải sử dụng chức năng đếm 'lạ'. –

+1

@Dan, nó đã được ghi chú trong liên kết tới tài liệu gốc, đã thêm thông báo rõ ràng, cảm ơn! – CroWell

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