2013-07-17 33 views
1

我使用jQuery Xpath插件瀏覽HTML文檔的層次結構。我不使用選擇器的原因是我需要處理服務器端框架的信息,它告訴我Xpath指向一個特定的元素。HTML上的Xpath:HTML源和DOM模型之間的區別

現在我觀察到DOM不一定代表HTML文檔的層次結構,並在此處找到解決此問題的解決方案:Why does firebug add <tbody> to <table>?。這意味着,如果我的HTML文檔不包含例如下面的代碼:

<table> 
    <tr> 
    <td>Hello</td> 
    </tr> 
</table> 

我的DOM將代表這樣後者:

<table> 
    <tbody> 
    <tr> 
     <td>Hello</td> 
    </tr> 
    </tbody> 
</table> 

我Xpath查詢

jQuery(document).xpath('//table[1]/tr[1]/td[1]') 

做因此不再產生結果。

有沒有辦法避免DOM表示的合成元素?還是一種調整Xpath的方法,使其包含合成元素?謝謝你的幫助。

+0

要麼給XPath的框架有問題,要麼你的文檔在服務器上被當作XML/XHTML,在瀏覽器上被當作HTML。 – Alohci

+0

好吧,框架在服務器端,並操縱和分析文檔的源代碼。我嘗試以在客戶端使用這些路徑位置的方式擴展框架。 –

回答

1

好,用jQuery的幫助我編寫了這個替代XPath解析器,適用於我的用例場景。解析器試圖停留在由我的輸入指定的XPath上,但是如果DOM模型在路徑的中間部分添加了一個新標籤,其中路徑的其餘部分包含在這個單個元素中,解析器會識別此添加幷包含此單個元素進入路徑。這當然不適用於每個人和每個用例場景,但它適用於我的。也許這個解決方案是幫助別人,至少要經過一些擴展:

var SloppyXPathParser = (function() { 

    function childExists($cursor, element) { 
     assertSelection($cursor); 
     var $movedCursor = $cursor.children(element.name); 
     if ($movedCursor.size() > element.index) { 
      return jQuery($movedCursor.get(element.index)); 
     } else if ($cursor.children().size() == 1) { 
      return childExists(jQuery($cursor.children().get(0)), element); 
     } else { 
      throw 'Cannot browse to \'' + element.name + '\' at index ' + element.index + '\''; 
     } 
    } 

    function assertSelection($cursor) { 
     if (!($cursor instanceof jQuery) || $cursor.size() != 1) { 
      throw 'Selection is invalid: ' + $cursor.size(); 
     } 
    } 

    function parsePath(rawPath) { 
     var nodes = rawPath.split('/'); 
     var regex = new RegExp('([a-zA-Z]+)\\[([0-9]+)\\]'); 
     var elements = []; 
     var index = 0; 
     jQuery(nodes).each(function (key, element) { 
      if (element.length == 0) { 
       return true; 
      } 
      if (!regex.test(element)) { 
       throw 'Path element does not match regex: ' + element; 
      } 
      var matched = regex.exec(element); 
      elements[index++] = { name: matched[1], index: matched[2] }; 
     }); 
     return elements; 
    } 

    function findElement(input) { 

     var elements = parsePath(input); 
     var $cursor = jQuery(document); 
     jQuery(elements).each(function (key, element) { 
      $cursor = childExists($cursor, element); 
     }); 

     try { 
      assertSelection($cursor); 
     } catch (cause) { 
      console.log('Exception: ' + cause); 
      return false; 
     } 

     return $cursor.get(0); 
    } 

    return { 
     find: function (input) { 
      return findElement(input); 
     } 
    } 
})(); 

var input = '/html[0]/body[0]/table[0]/tr[1]/td[1]'; 
SloppyXPathParser.find(input); 

與HTML源爲:

<html> 
    <body> 
    <table> 
     <tr> 
     <td>wrong</td> 
     <td>wrong</td> 
     </tr> 
     <tr> 
     <td>wrong</td> 
     <td>right</td> 
     </tr> 
    </table> 
    </body> 
</html> 

可以通過例如檢查瀏覽器添加了一個tbody元素到DOM的Firebug。解析器會識別它並跳過該條目。

0

如果您沒有任何嵌套表格,jQuery(document).xpath('//table[1]//tr[1]/td[1]')應該在兩種情況下都能正常工作。

在更一般的情況下,可以從答案適應How do you select child-or-self (children + self)

在XPath 1.0,這將轉化jQuery(document).xpath('(//table|//table/tbody)/tr[1]/td[1]')甚至更​​普遍地jQuery(document).xpath('(//table|//table/node())/tr[1]/td[1]「)

+0

這將適用於這一特定情況,但不適用於一般性輸入。 –

+0

編輯解決方案改編自http://stackoverflow.com/questions/4311470/how-do-you-select-child-or-self-children-self –

0

只需打開一個/成雙您tr

//table[1]/tr[1]/td[1] - >//table[1]//tr[1]/td[1]

這將在初始表標籤下方的任何深度匹配錶行,所以你可以添加儘可能多的<tbody>標籤,只要你喜歡。

+0

那麼,如果文檔包含嵌套表呢?這會增加含糊性。 –

+0

假設您不再僅僅匹配第一個「」和「​​」,那麼是的。您可以考慮添加一個類屬性來幫助確定哪個「​​」標籤處於哪個級別,但我想這可能有點骯髒。 – Tro

相關問題