Xpath kullanarak bir düğümün konumunu bulun


86

Xpath kullanarak bir düğümün konumunu nasıl alacağını bilen var mı?

Aşağıdaki xml'ye sahip olduğumu varsayalım:

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

Üçüncü <b> düğümünü (<b> tsr </b>) seçmek için aşağıdaki xpath sorgusunu kullanabilirim:

a/b[.='tsr']

Hepsi iyi ve güzel ama bu düğümün sıra konumunu döndürmek istiyorum , şöyle bir şey:

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

(ama biraz daha çalışıyor!)

Hatta mümkün mü?

düzenleme : .net 2 kullandığımı söylemeyi unuttum, bu yüzden xpath 1.0!


Güncelleme : kullanarak sona erdi James Sulak 'ın mükemmel bir cevap . İlgilenenler için işte benim C # uygulamam:

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);
}

Lütfen soruya cevap göndermemeye çalışın -> bunu bir cevap olarak göndermeniz, ardından muhtemelen sorudan ona bağlantı vermeniz daha iyi olur.
theMayer

Yanıtlar:


95

Deneyin:

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

1
Çünkü .net kullanıyorum ve ya kullandığım gücü kaldıramıyorum: int position = doc.SelectNodes ("a / b [. = 'Tsr'] / preceding-Sibling :: b") . + 1 sayısı; if (position> 1 || doc.SelectSingleNode ("a / b [. = 'tsr']")! = null) // Düğümün gerçekten var olup olmadığını kontrol edin {// Burada sihir yapın}
Wilfred Knievel

sıfır endeksli dillerde +1
JonnyRaa

9

Bunu XSLT ile yapabilirsiniz, ancak düz XPath hakkında emin değilim.

<?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

Gönderinin eski olduğunun farkındayım .. ama ..

yıldız işaretini nodename ile değiştirmek size daha iyi sonuçlar verecektir

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

onun yerine

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

5

XPath 2.0'a yükseltme yaparsanız, fonksiyon indeksi sağladığına dikkat edin, sorunu şu şekilde çözer:

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

Nerede:

  • 1. parametre arama dizisidir
  • 2. ne aranacak

Bunun yalnızca XPath 2+ ile çalışacağına dikkat edilmelidir. Bunun altındaki herhangi bir şeyin 'garip' sayma işlevini kullanması gerekecektir.
Dan Atkinson

1
@Dan, orijinal belgelerin bağlantısında not edildi, açık uyarı eklendi, teşekkürler!
CroWell

3

Daha önce belirtildiği gibi 'önceki-kardeş' gerçekten kullanılacak eksendir, tamamen farklı bir şey yapan 'önceki' değil, belgedeki mevcut düğümün başlangıç ​​etiketinden önceki her şeyi seçer. (bkz. http://www.w3schools.com/xpath/xpath_axes.asp )


4
Üst düğümler dahil değil. Ayrıntılar konusunda w3schools'a güvenmeyin! Ama katılıyorum ... bu durumda önceki :: işe yarasa da, ilgili b öğelerinden önce a atadan başka öğe bulunmadığından, önceki kardeşten daha kırılgandır. OTOH, OP bize içindeki pozisyonu hangi bağlamda bilmek istediğini söylemedi, bu yüzden potansiyel olarak önceki doğru olabilirdi.
LarsH

2

James Sulak'ın verdiği cevaba sadece bir not.

Düğümün mevcut olmayabileceğini dikkate almak ve onu tamamen XPATH olarak tutmak istiyorsanız, o zaman düğüm yoksa 0 döndüren aşağıdakileri deneyin.

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

0

Sorun, düğümün konumunun bağlam olmadan pek bir anlamı olmamasıdır.

Aşağıdaki kod, düğümün üst alt düğümlerindeki konumunu size verecektir.

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
Yani artık gerçekten bir XPath bulucu değil, bir C # bulucu.
jamesh

0

Pek çok Novell Kimlik Yöneticisi işi yapıyorum ve bu bağlamda XPATH biraz farklı görünüyor.

Aradığınız değerin HEDEF adlı bir dize değişkeninde olduğunu varsayın, sonra XPATH şöyle olur:

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

Ek olarak, birkaç karakterlik boşluktan tasarruf etmek için aşağıdakilerin de işe yarayacağı belirtildi:

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

Novell's Cool Solutions'da bunun daha güzel bir versiyonunu da yayınladım: Konum düğümünü almak için XPATH kullanma

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.