Tìm vị trí của một nút bằng xpath


86

Có ai biết cách lấy vị trí của một nút bằng xpath không?

Giả sử 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 để chọn <b> nút thứ ba (<b> tsr </b>):

a/b[.='tsr']

Tất cả đều tốt và tốt nhưng tôi muốn trả lại vị trí thứ tự của nút đó, giống như:

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

(nhưng hiệu quả hơn một chút!)

Nó thậm chí có thể?

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


Cập nhật : Kết thúc bằng câu trả lời xuất sắc của James Sulak . Đối với những người quan tâm, đây là cách 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);
}

Vui lòng cố gắng không đăng câu trả lời trong câu hỏi -> tốt hơn là nên đăng câu trả lời này như một câu trả lời, sau đó có thể được liên kết với nó từ câu hỏi.
theMayer

Câu trả lời:


94

Thử:

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

1
'Vì tôi đang sử dụng .net & hoặc nó hoặc tôi không thể xử lý sức mạnh mà tôi đã sử dụng: int position = doc.SelectNodes ("a / b [. =' Tsr '] / beforeing-Sibling :: b") .Tài khoản + 1; if (vị trí> 1 || doc.SelectSingleNode ( "a / b [= 'TSR'.]") = null!) // Kiểm tra nút thực sự tồn tại {// Đỗ ma thuật ở đây}
Wilfred Knievel

bằng 0 ngôn ngữ được lập chỉ mục, bạn không cần +1
JonnyRaa

9

Bạn có thể làm điều này với XSLT nhưng tôi không chắc 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>

9

Tôi nhận ra rằng bài viết là cổ xưa .. nhưng ..

thay thế dấu hoa thị bằng tên nút sẽ 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.

4

Nếu bạn đã từng nâng cấp lên XPath 2.0, hãy lưu ý rằng nó cung cấp chỉ mục hàm của , nó giải quyết vấn đề theo cách này:

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

Ở đâu:

  • Tham số đầu tiên là trình tự tìm kiếm
  • Thứ 2 là tìm kiếm gì

Cần lưu ý rằng điều này sẽ chỉ hoạt động với XPath 2+. Bất kỳ thứ gì bên dưới sẽ phải sử dụng hàm đếm 'kỳ lạ'.
Dan Atkinson

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

3

Không giống như đã nêu trước đây 'anh chị em' thực sự là trục để sử dụng, không phải '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 các nút tổ tiên. Đừng tin tưởng vào 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ó phần tử nào đứng trước các phần tử b có liên quan khác với tổ tiên, nó mỏng manh hơn so với trước đó. OTOH, OP đã không cho chúng tôi biết bối cảnh nào mà ông ấy muốn biết vị trí bên trong, vì vậy có khả năng trước :: có thể đúng.
LarsH

2

Chỉ là một ghi chú cho câu trả lời do James Sulak thực hiện.

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 là XPATH, thì hãy thử cách sau 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']))

0

Vấn đề là vị trí của nút không có nhiều ý nghĩa nếu không có ngữ cảnh.

Đoạn mã sau sẽ cung cấp cho bạn vị trí của nút trong các nút con cha 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, bây giờ không thực sự là một công cụ tìm XPath, mà là một công cụ tìm C #.
jamesh 29/10/08

0

Tôi thực hiện rất nhiều thứ trong Novell Identity Manager và XPATH trong bối cảnh đó trông hơi khác một chút.

Giả sử giá trị bạn đang tìm kiếm nằm trong một biến chuỗi, được gọi là TARGET, thì XPATH sẽ là:

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

Ngoài ra, nó được chỉ ra rằng để tiết kiệm một vài ký tự không gian, những điều sau đây cũng sẽ hoạt động:

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

Tôi cũng đã đăng một phiên bản đẹp hơn của cái này tại Novell's Cool Solutions: Sử dụng XPATH để lấy nút vị trí

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.