2011-07-26 56 views
12

Tôi đang cố gắng tạo bộ chọn CSS cho các phần tử ngẫu nhiên trên trang web bằng C#. Một số nền:HtmlElement.Parent trả về false parent

Tôi sử dụng biểu mẫu có điều khiển WebBrowser. Trong khi điều hướng người ta có thể yêu cầu bộ chọn CSS của phần tử bên dưới con trỏ. Bắt html phần tử là tầm thường, tất nhiên, bằng các phương tiện:

WebBrowser.Document.GetElementFromPoint(<Point>); 

Tham vọng là tạo ra một selector 'khắt khe' css dẫn đến yếu tố dưới con trỏ, a-la:

html > body > span:eq(2) > li:eq(5) > div > div:eq(3) > span > a 

Bộ chọn này dựa trên: các toán tử eq vì nó có nghĩa là được xử lý bởi jQuery và/hoặc SizzleJS (hai hỗ trợ này: eq - bộ chọn CSS gốc không. Thumbs up @BoltClock để giúp tôi làm rõ điều này). Vì vậy, bạn có được hình ảnh. Để đạt được mục tiêu này, chúng tôi cung cấp các phần tử html lấy ra để phương pháp dưới đây và bắt đầu tăng dần lên cây DOM bằng cách yêu cầu các phụ huynh của mỗi yếu tố chúng tôi đi qua:

private static List<String> GetStrictCssForHtmlElement(HtmlElement element) 
    { 
     List<String> familyTree; 
     for (familyTree = new List<String>(); element != null; element = element.Parent) 
     { 
      string ordinalString = CalculateOrdinalPositionAmongSameTagSimblings(element); 
      if (ordinalString == null) return null; 

      familyTree.Add(element.TagName.ToLower() + ordinalString); 
     } 
     familyTree.Reverse(); 

     return familyTree; 
    } 

    private static string CalculateOrdinalPositionAmongSameTagSimblings(HtmlElement element, bool simplifyEq0 = true) 
    { 
     int count = 0; 
     int positionAmongSameTagSimblings = -1; 
     if (element.Parent != null) 
     { 
      foreach (HtmlElement child in element.Parent.Children) 
      { 
       if (element.TagName.ToLower() == child.TagName.ToLower()) 
       { 
        count++; 
        if (element == child) 
        { 
         positionAmongSameTagSimblings = count - 1; 
        } 
       } 
      } 

      if (positionAmongSameTagSimblings == -1) return null; // Couldn't find child in parent's offsprings!? 
     } 

     return ((count > 1) ? (":eq(" + positionAmongSameTagSimblings + ")") : ((simplifyEq0) ? ("") : (":eq(0)"))); 
    } 

Phương pháp này đã làm việc đáng tin cậy cho một loạt của các trang. Tuy nhiên, có một trang cụ thể mà làm cho đầu của tôi trong:

http://www.delicious.com/recent

Đang cố gắng để lấy bộ chọn CSS của bất kỳ phần tử trong danh sách (ở trung tâm của trang) thất bại vì một lý do rất đơn giản:

Sau khi số lần truy cập tăng phần tử SPAN đầu tiên theo cách của nó (bạn có thể phát hiện nó bằng cách kiểm tra trang bằng các công cụ web-dev của IE9 để xác minh) nó cố gắng xử lý nó bằng cách tính vị trí thứ tự trong số đó là anh chị em cùng một thẻ. Để làm điều đó, chúng ta cần phải hỏi nó là nút cha mẹ cho anh chị em ruột. Đây là nơi mọi thứ trở nên kỳ lạ. Phần tử SPAN báo cáo rằng đó là Parent là một phần tử DIV với id = "index-index". Tuy nhiên, đó là không phảingay lập tức cha mẹ của SPAN (cha mẹ trực tiếp là LI class = "wrap isAdv"). Điều này làm cho phương pháp thất bại bởi vì - không ngạc nhiên - nó không phát hiện SPAN trong số các trẻ em.

Nhưng nó thậm chí còn trở nên kỳ lạ hơn. Tôi lấy ra và cô lập HtmlElement của chính SPAN. Sau đó, tôi đã nhận nó là mẹ và sử dụng nó để lại xuống trở lại xuống tới phần tử SPAN sử dụng:

HtmlElement regetSpanElement = spanElement.Parent.Children[0].Children[1].Children[1].Children[0].Children[2].Children[0]; 

này dẫn chúng ta trở lại nút SPAN chúng tôi bắt đầu ... với tuy nhiên một twist:

regetSpanElement.Parent.TagName; 

Điều này giờ đây báo cáo LI là phụ huynh XX. Làm sao có thể? Có cái nhìn sâu sắc nào không?

Cảm ơn bạn trước.

Ghi chú:

  1. tôi lưu mã Html (khi nó được trình bày bên WebBrowser.Document.Html) và kiểm tra nó bản thân mình phải chắc chắn 100% rằng không có gì hài hước đang diễn ra (mã aka khác nhau phục vụ cho Kiểm soát trình duyệt Web hơn so với cái tôi thấy trong IE9 - nhưng điều đó không xảy ra với cấu trúc khớp với 100% cho đường dẫn có liên quan).

  2. Tôi đang chạy điều khiển WebBrowser trong IE9 chế độ sử dụng các hướng dẫn được nêu ở đây:

    http://www.west-wind.com/weblog/posts/2011/May/21/Web-Browser-Control-Specifying-the-IE-Version

    Đang cố gắng để có được điều khiển WebBrowser và IE9 chạy như tương tự càng tốt.

  3. Tôi nghi ngờ rằng các hiệu ứng được quan sát có thể là do một số tập lệnh chạy sau lưng tôi. Tuy nhiên, kiến ​​thức của tôi không phải là cho đến nay tiếp cận về lập trình web để pin nó xuống.

Edit: Typos

+0

': eq()' không phải là bộ chọn CSS hợp lệ. Tôi đoán bạn có nghĩa là 'html> body> span: nth-child (3)> li: nth-child (6)> div> div: nth-child (4)> span> a'? – BoltClock

+0

Cảm ơn đã cho tôi cơ hội để làm rõ - Tôi có nghĩa là để nói sels css dự định sẽ được giao cho jQuery và/hoặc SizzleJS. Tôi sẽ cập nhật từ ngữ trong bài viết gốc. Để phản ánh điều này. Cảm ơn một lần nữa;) – xDisruptor

+0

Xin chào, tôi chưa có câu trả lời nhưng tôi muốn nói một vài điều; Thứ nhất, cảm ơn các chi tiết trong câu hỏi của bạn và lịch sự của bạn cho các thành viên của trang web này, +1 cho điều đó! Thứ hai; Tôi bị cuốn hút bởi bối cảnh của câu hỏi; Tôi hiểu những gì bạn muốn làm, bạn có thể giúp điền chúng tôi vào phần Tại sao không? bạn đang xây dựng một hệ thống phân cấp cây hoặc một số loại đường dẫn đường dẫn? –

Trả lời

2

Dựa vào: eq() là khó khăn! Rất khó để chọn lại một cách đáng tin cậy một DOM là động. Chắc chắn nó có thể hoạt động trên các trang rất tĩnh, nhưng mọi thứ chỉ trở nên năng động hơn mỗi ngày. Bạn có thể xem xét thay đổi chiến lược một chút. Hãy thử sử dụng bộ chọn linh hoạt hơn thông minh hơn. Có lẽ bật trong một số javascript như sau:

predictCss = function(s, noid, noclass, noarrow) { 
    var path, node = s; 
    var psep = noarrow ? ' ' : ' > '; 
    if (s.length != 1) return path; //throw 'Requires one element.'; 
    while (node.length) { 
     var realNode = node[0]; 
     var name = (realNode.localName || realNode.tagName || realNode.nodeName); 
     if (!name || name == '#document') break; 
     name = name.toLowerCase(); 
     if(node.parent().children(name).length > 1){ 
      if (realNode.id && !noid) { 
       try { 
        var idtest = $(name + '#' + realNode.id); 
        if (idtest.length == 1) return name + '#' + realNode.id + (path ? '>' + path : ''); 
       } catch (ex) {} // just ignore the exception, it was a bad ID 
      } else if (realNode.className && !noclass) { 
       name += '.' + realNode.className.split(/\s+/).join('.'); 
      } 
     } 
     var parent = node.parent(); 
     if (name[name.length - 1] == '.') { 
      name = name.substring(0, name.length - 1); 
     } 
     siblings = parent.children(name); 
     //// If you really want to use eq: 
     //if (siblings.length > 1) name += ':eq(' + siblings.index(node) + ')'; 
     path = name + (path ? psep + path : ''); 
     node = parent; 
    } 
    return path 
} 

Và sử dụng nó để tạo ra một loạt các selectors:

var elem = $('#someelement'); 
var epath = self.model.util.predictCss(elem, true, true, false); 
var epathclass = self.model.util.predictCss(elem, true, false, false); 
var epathclassid = self.model.util.predictCss(elem, false, false, false); 

Sau đó sử dụng mỗi:

var relem= $(epathclassid); 
if(relem.length === 0){ 
    relem = $(epathclass); 
    if(relem.length === 0){ 
     relem = $(epath); 
    } 
} 

Và nếu chọn tốt nhất của bạn vẫn đúng với nhiều hơn một phần tử, bạn sẽ phải sáng tạo về cách bạn kết hợp một phần tử dom - có lẽ là levenshtein hoặc có lẽ có một số văn bản cụ thể hoặc bạn có thể dự phòng với eq. Hy vọng rằng sẽ giúp!

Btw, tôi cho rằng bạn có jQuery - do tham chiếu sizzle. Bạn có thể chèn vào ở trên trong một chức năng nặc danh tự thực hiện trong một thẻ script được nối thêm vào phần tử con cuối cùng của ví dụ.

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