xpath를 사용하여 노드 위치 찾기


86

누구나 xpath를 사용하여 노드의 위치를 ​​얻는 방법을 알고 있습니까?

다음 xml이 있다고 가정하십시오.

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

다음 xpath 쿼리를 사용하여 세 번째 <b> 노드 (<b> tsr </ b>)를 선택할 수 있습니다.

a/b[.='tsr']

모두 훌륭하고 좋지만 다음과 같이 해당 노드의 서수 위치 를 반환 하고 싶습니다.

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

(하지만 조금 더 작동합니다!)

가능할까요?

편집 : .net 2를 사용하고 있다는 것을 언급하는 것을 잊었으므로 xpath 1.0입니다!


업데이트 : James Sulak훌륭한 답변을 사용하여 끝났습니다 . 관심있는 사람들을 위해 여기에 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);
}

질문에 대한 답변을 게시하지 않도록 노력하십시오 -> 더 나은 것 다음 대답으로이를 게시 할 가능성이 질문에서 연결.
theMayer

답변:


94

시험:

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

1
'Coz 나는 .net을 사용하고 있거나 내가 함께했던 힘을 처리 할 수 ​​없습니다 : int position = doc.SelectNodes ( "a / b [. ='tsr '] / preceding-Sibling :: b") .Count + 1; if (position> 1 || doc.SelectSingleNode ( "a / b [. = 'tsr']")! = null) // 노드가 실제로 존재하는지 확인합니다 {// 여기서 마술을합니다}
Wilfred Knievel

제로 인덱스 언어로 당신은 일 필요가 없습니다
JonnyRaa

9

XSLT로 이것을 할 수 있지만 곧은 XPath에 대해 잘 모르겠습니다.

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

게시물이 고대라는 건 알지만 ..

별표를 노드 이름으로 바꾸면 더 나은 결과를 얻을 수 있습니다.

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

대신에

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

4

XPath 2.0으로 업그레이드 한 경우 index-of 함수를 제공 하므로 다음과 같이 문제가 해결됩니다.

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

어디:

  • 첫 번째 매개 변수는 검색 순서입니다.
  • 두 번째는 무엇을 검색 할 것인가

이것은 XPath 2+에서만 작동합니다. 그 아래의 모든 것은 '이상한'카운트 기능을 사용해야합니다.
Dan Atkinson 2015

1
@Dan, 원본 문서에 대한 링크에 명시되었으며 명시적인 알림이 추가되었습니다. 감사합니다!
CroWell 2015

3

앞서 언급 한 'preceding-sibling'은 완전히 다른 일을하는 'preceding'이 아니라 실제로 사용할 축이며, 현재 노드의 시작 태그 앞에있는 문서의 모든 것을 선택합니다. ( http://www.w3schools.com/xpath/xpath_axes.asp 참조 )


4
조상 노드를 포함하지 않습니다. 세부 사항에 대해 w3schools를 신뢰하지 마십시오! 하지만 동의합니다 ... prior ::이 경우에 작동합니다. a 조상 이외의 관련 b 요소 앞에 요소가 없기 때문에 선행 형제보다 더 취약합니다. OTOH, OP는 그가 내 위치를 알고 싶어하는 컨텍스트를 알려주지 않았으므로 잠재적으로 선행 ::이 옳을 수 있습니다.
LarsH

2

James Sulak의 답변에 대한 메모입니다.

노드가 존재하지 않을 수 있다는 것을 고려하고 순수하게 XPATH를 유지하려면 노드가 존재하지 않으면 0을 반환하는 다음을 시도하십시오.

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

0

문제는 노드의 위치가 컨텍스트 없이는 그다지 의미가 없다는 것입니다.

다음 코드는 부모 자식 노드에서 노드의 위치를 ​​제공합니다.

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
이제 실제로 XPath 파인더가 아니라 C # 파인더입니다.
jamesh

0

저는 Novell Identity Manager 작업을 많이하는데, 그 맥락에서 XPATH는 약간 다릅니다.

찾고있는 값이 TARGET이라는 문자열 변수에 있다고 가정하면 XPATH는 다음과 같습니다.

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

또한 몇 글자의 공간을 절약하려면 다음과 같은 방법도 사용할 수 있습니다.

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

나는 또한 Novell의 Cool Solutions : Using XPATH to get the position node에 더 예쁜 버전을 게시했습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.