2014-04-23 22 views
5

Tôi đang viết chương trình cào màn hình đơn giản trong C#, mà tôi cần chọn tất cả các đầu vào được đặt bên trong một biểu mẫu có tên "aspnetForm" (có 2 biểu mẫu trên trang , và tôi không muốn đầu vào từ một cái khác), và tất cả các đầu vào trong biểu mẫu này được đặt bên trong các bảng khác nhau, của div, hoặc chỉ ở cấp độ con đầu tiên của biểu mẫu này.Chọn XPath trong HTMLAgilityPack không hoạt động như mong đợi

Vì vậy, tôi viết truy vấn XPath thực sự đơn giản:

//form[@id='aspnetForm']//input 

Đó là công trình như mong đợi trong tất cả các trình duyệt mà tôi thử nghiệm (Chrome, IE, Firefox) - nó sẽ trả về những gì tôi muốn.

Nhưng trong HTMLAgilityPack nó không hoạt động chút nào - SelectNodes luôn trả về NULL.

Truy vấn này tôi đã viết cho các thử nghiệm hoạt động tốt, nhưng không trả về những gì tôi muốn. Trước tiên hãy chọn tất cả các đầu vào của đó là lần đầu tiên Childs cho hình thức của tôi, và hình thức thứ hai chỉ trở lại của:

//form[@id='aspnetForm']/input 
//form[@id='aspnetForm'] 

Vâng, tôi biết rằng tôi chỉ có thể liệt kê trên các nút từ truy vấn cuối cùng, hoặc thực hiện một SelectNodes trên kết quả của nó, nhưng tôi không thực sự muốn làm điều này. Tôi muốn sử dụng cùng một truy vấn như trong các trình duyệt.

XPath hiện có bị hỏng trong HTMLAgilityPack không? Có bất kỳ triển khai XPath thay thế cho C#?

CẬP NHẬT: Mã kiểm tra:

using HtmlAgilityPack; 
using Microsoft.VisualStudio.TestTools.UnitTesting; 

namespace HtmlAGPTests 
{ 
    [TestClass] 
    public class XPathTests 
    { 
     private const string html = 
       "<form id=\"aspnetForm\">" + 
       "<input name=\"first\" value=\"first\" />" + 
       "<div>" + 
        "<input name=\"second\" value=\"second\" />" + 
       "</div>" + 
       "</form>"; 

     private static HtmlNode GetHtmlDocumentNode() 
     { 
      var document = new HtmlDocument(); 
      document.LoadHtml(html); 
      return document.DocumentNode; 
     } 

     [TestMethod] 
     public void TwoLevelXpathTest()  // fail - nodes is NULL actually. 
     { 
      var query = "//form[@id='aspnetForm']//input"; // what i want 
      var documentNode = GetHtmlDocumentNode(); 

      var inputNodes = documentNode.SelectNodes(query); 

      Assert.IsTrue(inputNodes.Count == 2); 
     } 

     [TestMethod] 
     public void TwoSingleLevelXpathsTest()  // works 
     { 
      var formQuery = "//form[@id='aspnetForm']"; 
      var inputQuery = "//input"; 
      var documentNode = GetHtmlDocumentNode(); 

      var formNode = documentNode.SelectSingleNode(formQuery); 
      var inputNodes = formNode.SelectNodes(inputQuery); 

      Assert.IsTrue(inputNodes.Count == 2); 
     } 

     [TestMethod] 
     public void SingleLevelXpathTest()  // works 
     { 
      var query = "//form[@id='aspnetForm']"; 
      var documentNode = GetHtmlDocumentNode(); 

      var formNode = documentNode.SelectSingleNode(query); 

      Assert.IsNotNull(formNode); 
     } 

    } 
} 
+0

.NET đã xây dựng trong việc triển khai XPath được sử dụng bởi HtmlAgilityPack (HAP không triển khai công cụ XPath riêng). Và thực ra XPath của HAP đã từng làm việc tốt cho tôi, nên tôi đề nghị nghi ngờ điều gì khác trước. – har07

+0

Cố gắng lưu 'HtmlDocument', sau đó kiểm tra xem tệp đã lưu có chứa định dạng HTML dự kiến ​​hay không. – har07

+1

@ har07, nó chứa - tôi đã thử nghiệm trước khi đăng câu hỏi. Các phương thức "workaround" cũng hoạt động, vì vậy nó hoàn toàn không phải là vấn đề với đầu vào. Đã thêm mã kiểm tra vào câu hỏi, vì vậy bạn có thể tự kiểm tra nó - nó KHÔNG hoạt động như mong đợi. – rufanov

Trả lời

4

Các hành vi bất ngờ trong thử nghiệm của bạn xảy ra vì html chứa <form> phần tử. thảo luận ở đây có liên quan:

Ariman:. "Tôi đã tìm thấy rằng sau khi phân tích bất kỳ nút không có bất kỳ nút con Tất cả các nút cần được bên trong các hình thức (,, vv) được tạo ra vì nó là . anh chị em chứ không phải sau đó trẻ em

VikciaR: "Trong Html dạng đặc điểm kỹ thuật thẻ có thể chồng chéo lên nhau, vì vậy HtmlAgilityPack xử lý nút này hơi khác một chút ..."

[CodePlex discussion : No child nodes for FORM objects]

Và theo đề nghị của VikciaR ở đó, cố gắng sửa đổi mã khởi tạo thử nghiệm của bạn như thế này:

private static HtmlNode GetHtmlDocumentNode() 
{ 
    var document = new HtmlDocument(); 
    document.LoadHtml(html); 

    //execute this line once 
    HtmlNode.ElementsFlags.Remove("form"); 

    return document.DocumentNode; 
} 

Side lưu ý:inputQuery giá trị trong phương pháp thử nghiệm TwoSingleLevelXpathsTest() nên .//input. Chú ý dấu chấm (.) ngay từ đầu để cho biết rằng truy vấn này liên quan đến nút hiện tại. Nếu không, nó sẽ tìm kiếm từ gốc, bỏ qua formQuery trước đây (không có dấu chấm, bạn có thể thay đổi formQuery thành bất kỳ thứ gì miễn là nó không trả lại giá trị rỗng, inputQuery sẽ luôn trả về cùng một kết quả).

+2

Hành vi lạ lẫm theo mặc định .. Nhưng dù sao, cảm ơn bạn! Nó hoạt động! – rufanov

Các vấn đề liên quan