2012-05-30 2 views
2

XPath를 사용하여 C#의 일부 HTML 파일을 쿼리 할 때 약간의 문제가 발생했습니다. 1,2,3,4 (내가 할 노력하고있어하면 B와 C 노드 사이 만 요소를 얻는 것입니다, 지금XPath - 두 노드 사이의 첫 번째 형제 그룹 선택

<table id="theTable"> 
    <tbody> 
     <tr class="theClass">A</tr> 
     <tr class="theClass">B</tr> 
     <tr>1</tr> 
     <tr>2</tr> 
     <tr>3</tr> 
     <tr>4</tr> 
     <tr>5</tr> 
     <tr class="theClass">C</tr> 
     <tr class="theClass">D</tr> 
     <tr>6</tr> 
     <tr>7</tr> 
     <tr>8</tr> 
     <tr>9</tr> 
     <tr>10</tr> 
     <tr>11</tr> 
     <tr>12</tr> 
     <tr>13</tr> 
     <tr>14</tr> 
     <tr>15</tr> 
     <tr class="theClass">E</tr> 
     <tr class="theClass">F</tr> 
     <tr>16</tr> 
     <tr>17</tr> 
     <tr>18</tr> 
     <tr>19</tr> 
     <tr>20</tr> 
     <tr>21</tr> 
     <tr>22</tr> 
    </tbody> 
</table> 

:

좋아, 먼저 여기 샘플 HTML의 , 5,). 여기

는 지금까지 시도 내용은 다음과 같습니다,

using System; 
using System.Xml.XPath; 

namespace Test 
{ 
    class Test 
    { 
     static void Main(string[] args) 
     { 
      XPathDocument doc = new XPathDocument("Test.xml"); 
      XPathNavigator nav = doc.CreateNavigator(); 

      Console.WriteLine(nav.Select("//table[@id='theTable']/tbody/tr[preceding-sibling::tr[@class='theClass'] and following-sibling::tr[@class='theClass']]").Count); 
      Console.WriteLine(nav.Select("//table[@id='theTable']/tbody/tr[preceding-sibling::tr[@class='theClass'][2] and following-sibling::tr[@class='theClass'][4]]").Count); 

      Console.ReadKey(true); 
     } 
    } 
} 

이 코드는, 위의 HTML을 통해 실행 (19)와 5 그래서에만 두 번째 XPath 식을 출력 작동하지만이이 요소를 검색 때문 두 요소 앞에 class=theClass이 있고 그 뒤에 4 개가 있습니다.

지금부터 문제가 시작됩니다. 얼마나 많은 그룹이 그것을 따르더라도, <td class="theClass"></td> 태그 뒤에 오는 첫 번째 요소 그룹 만 반환하는 단일 식을 작성하고 싶습니다. 나는이 HTML

<table id="theTable"> 
    <tbody> 
     <tr class="theClass">A</tr> 
     <tr class="theClass">B</tr> 
     <tr>1</tr> 
     <tr>2</tr> 
     <tr>3</tr> 
     <tr>4</tr> 
     <tr>5</tr> 
     <tr>6</tr> 
    </tbody> 
</table> 

을 통해 내 코드를 실행하면

는 출력 0, 0

은 그래서 더 좋은하지 않습니다.

아무도 아이디어가 있습니까?

감사합니다.

+0

본 적이 없습니다. 예상되는 결과는 무엇입니까? –

+0

@ChuckSavage 첫 번째 HTML의 경우 1,2,3,4,5 요소가 반환되고 두 번째 HTML의 경우 elemenets 1,2,3,4,5,6이 반환됩니다. –

답변

6
이제

, 난 할 노력하고있어하는 사이 을 만 이러한 요소를 얻는 것입니다 BC 노드

사용이 하나의 XPath 식 :

여기
/*/*/tr[.='B'] 
      /following-sibling::* 
      [count(.|/*/*/tr[. ='C']/preceding-sibling::*) 
      = 
       count(/*/*/tr[. ='C']/preceding-sibling::*) 
      ] 

51,515,는 XSLT 인 - 대조 : XPath 식을 평가

<table id="theTable"> 
    <tbody> 
     <tr class="theClass">A</tr> 
     <tr class="theClass">B</tr> 
     <tr>1</tr> 
     <tr>2</tr> 
     <tr>3</tr> 
     <tr>4</tr> 
     <tr>5</tr> 
     <tr class="theClass">C</tr> 
     <tr class="theClass">D</tr> 
     <tr>6</tr> 
     <tr>7</tr> 
     <tr>8</tr> 
     <tr>9</tr> 
     <tr>10</tr> 
     <tr>11</tr> 
     <tr>12</tr> 
     <tr>13</tr> 
     <tr>14</tr> 
     <tr>15</tr> 
     <tr class="theClass">E</tr> 
     <tr class="theClass">F</tr> 
     <tr>16</tr> 
     <tr>17</tr> 
     <tr>18</tr> 
     <tr>19</tr> 
     <tr>20</tr> 
     <tr>21</tr> 
     <tr>22</tr> 
    </tbody> 
</table> 

:이 변환은 제 제공된 XML 문서에 적용

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/"> 
    <xsl:copy-of select= 
    "/*/*/tr[.='B'] 
      /following-sibling::* 
      [count(.|/*/*/tr[. ='C']/preceding-sibling::*) 
      = 
       count(/*/*/tr[. ='C']/preceding-sibling::*) 
      ] 
    "/> 
</xsl:template> 
</xsl:stylesheet> 

선택된 노드가 출력으로 복사됩니다.

,
<tr>1</tr> 
<tr>2</tr> 
<tr>3</tr> 
<tr>4</tr> 
<tr>5</tr> 

설명는 :

/*/*/tr[.='B'] 
       /following-sibling::* 

하고 :

$ns1[count(.|$ns2) = count($ns2)] 

우리가 $ns1 치환 :

여기

우리는 단순히 노드 집합 교차 대한 Kayessian 수식을 사용 우리는

/*/*/tr[. ='C']/preceding-sibling::* 

두 번째 문제 :와 $ns2 대체

내 문제는 이제 시작됩니다. 이 <td class="theClass"></td> 태그 다음에 나오는 첫 번째 그룹 만 반환하는 단일 식을 쓰고 싶습니다. 얼마나 많은 그룹이 더 뒤에 있든간에 다음에 오는 표현식을 작성하고 싶습니다.

는 다시 이러한 요소를 선택하는 하나의 XPath 식은 존재 :

/*/*/tr[@class='theClass' 
     and 
      following-sibling::*[1][self::tr[not(@*)] ] 
      ][1] 
      /following-sibling::tr 
       [not(@*) 
       and 
       count(preceding-sibling::tr 
         [@class='theClass' 
         and 
         following-sibling::*[1][self::tr[not(@*)] ] 
         ] 
        ) 
       = 1 
       ] 

설명이 모든 다음 형제 께의 tr 요소 (즉, 다수의 조건을 만족하는)을 선택

먼저 */*/tr 요소의 class 속성이 문자열 값이 "theClass"이고 첫 번째 엘 형제는 특성이없는 tr입니다.

이 선택된 tr 요소가 만족하는 조건은 2 가지입니다. 1) 속성이 없습니다. 2) 동등한 형제가 하나만있는 tr 요소가 있으며 그 중 class 속성의 문자열 값은 "theClass"입니다.

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 

<xsl:template match="/"> 
    <xsl:copy-of select= 
    "/*/*/tr[@class='theClass' 
     and 
      following-sibling::*[1][self::tr[not(@*)] ] 
      ][1] 
      /following-sibling::tr 
       [not(@*) 
       and 
       count(preceding-sibling::tr 
         [@class='theClass' 
         and 
         following-sibling::*[1][self::tr[not(@*)] ] 
         ] 
        ) 
       = 1 
       ] 
    "/> 
</xsl:template> 
</xsl:stylesheet> 
두 번째 제공하는 XML 문서
에 적용

: 원하는 올바르게 선택 요소는 출력이 다시

<table id="theTable"> 
    <tbody> 
     <tr class="theClass">A</tr> 
     <tr class="theClass">B</tr> 
     <tr>1</tr> 
     <tr>2</tr> 
     <tr>3</tr> 
     <tr>4</tr> 
     <tr>5</tr> 
     <tr>6</tr> 
    </tbody> 
</table> 

있는 기반 검증 - 여기

그리고

는 XSLT이다 :

<tr>1</tr> 
<tr>2</tr> 
<tr>3</tr> 
<tr>4</tr> 
<tr>5</tr> 
<tr>6</tr> 
+0

고맙습니다. 작동합니다. 최종 표현에 대한 설명을 남길 수도 있습니까? 나는 그것을 이해하고 있는지 확신 할 수 없다. 감사합니다. –

+0

@LeifLazar : 천만에요. 답변을 편집하고 두 표현에 대한 설명을 추가했습니다. –

1

XPath를 사용할 필요가없는 경우 LINQ를 사용하기가 쉽고 읽기 쉽습니다.귀하의 경우 건너 뛰기의 조합 다음 의사 코드와 유사 TakeWhile에서

는 일할 수 :

nav.Select("//table[@id='theTable']/tbody/tr") // whatever to get list of all TR 
    .Skip("theClass is B") // some condition to skip up to first node 
    .TakeWhile("theClass is C"); // some condition to take upto second node.