현재 컨텍스트 노드에서 가장 근접한 일치를 찾는 방법

c# html-agility-pack xpath

문제

C # 응용 프로그램과 HtmlAgilityPack을 사용하여 구문 분석하려고하는 다소 큰 XML 파일이 있습니다. XML은 다음과 같이 보입니다.

...
<tr>
<td><b>ABC-123</b></td>
<td>15</td>
<td>4</td>
</tr>
<tr>
<td>AB-4-320</td>
<td>11</td>
<td>2</td>
</tr>
<tr>
<td><b>ABC-123</b></td>
<td>15</td>
<td>4</td>
</tr>
<tr>
<td>AB-4-320</td>
<td>11</td>
<td>2</td>
</tr>
<tr>
<td>CONTROLLER1</td>
<td>4</td>
<td>3</td>
</tr>
<td>CONTROLLER2</td>
<td>4</td>
<td>3</td>
</tr>
...

기본적으로 일련의 테이블 행과 열이 반복됩니다. 먼저 컨트롤러를 검색하려면 다음을 사용하십시오.

string xPath = @"//tr/td[starts-with(.,'CONTROLLER2')]";
HtmlNodeCollection nodes = doc.DocumentNode.SelectNodes(xPath);
foreach (HtmlNode link in nodes) { ... }

올바른 노드를 반환합니다. 이제 텍스트 "ABC"로 시작하는 첫 번째 (가장 가까운) 일치하는 <td> 노드를 거꾸로 (위로) 검색하려고합니다.

string xPath = @link.XPath + @"/parent::tr/preceding-sibling::tr/td[starts-with(.,'ABC-')]";

가장 가까운 노드뿐만 아니라 모든 일치하는 노드를 반환합니다. [1]을이 XPath 문자열의 끝 부분에 추가하려고 시도했을 때 작동하지 않는 것 같았고 이와 같은 축 기능과 함께 사용되는 술어를 보여주는 예는 발견하지 못했습니다. 아니면, 내가 그 일을 잘못하고있는 것 같습니다. 어떤 제안?

수락 된 답변

이 XPath를 사용할 수 있습니다.

/parent::tr/preceding-sibling::tr[td[starts-with(.,'ABC-')]][1]/td[starts-with(.,'ABC-')]

그러면 ' <td> ABC-'로 시작하는 하위 <td> 가있는 가장 가까운 선행 <tr> 이 검색됩니다. 그런 다음 특정 <td> 요소를 가져옵니다.

HtmlAgilityPack을 사용할 때 선택할 수있는 방법은 최소한 두 가지가 있습니다.

foreach (HtmlNode link in nodes)
{
    //approach 1 : notice dot(.) at the beginning of the XPath
    string xPath1 = 
        @"./parent::tr/preceding-sibling::tr[td[starts-with(.,'ABC-')]][1]/td[starts-with(.,'ABC-')]";
    var n1 = node.SelectSingleNode(xPath1);
    Console.WriteLine(n1.InnerHtml);

    //approach 2 : appending to XPath of current link
    string xPath2 = 
        @"/parent::tr/preceding-sibling::tr[td[starts-with(.,'ABC-')]][1]/td[starts-with(.,'ABC-')]";
    var n2 = node.SelectSingleNode(link.XPath + xPath2);
    Console.WriteLine(n2.InnerHtml);
}

인기 답변

HAP 대신 LINQ-to-XML을 사용할 수 있다면 다음과 같이 작동합니다.

var node = xml.Root.Elements("tr")
    .TakeWhile(tr => !tr.Elements("td")
        .Any(td => td.Value.StartsWith("CONTROLLER2")))
    .SelectMany(tr => tr.Elements("td"))
    .Where(td => td.Value.StartsWith("ABC-"))
    .Last();

나는이 결과를 얻었다 :

<td>
  <b>ABC-123</b>
</td>

(어느 쪽이 먼저 샘플이 아니라 두 번째 일치하는 노드인지 확인했습니다.)



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.