日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Jsoup代码解读之二-DOM相关对象

發布時間:2023/12/3 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Jsoup代码解读之二-DOM相关对象 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉載自??Jsoup代碼解讀之二-DOM相關對象

之前在文章中說到,Jsoup使用了一套自己的DOM對象體系,和Java XML API互不兼容。這樣做的好處是從XML的API里解脫出來,使得代碼精煉了很多。這篇文章會說明Jsoup的DOM結構,DOM的遍歷方式。在下一篇文章,我會并結合這兩個基礎,分析一下Jsoup的HTML輸出功能。

DOM結構相關類

我們先來看看nodes包的類圖:

這里可以看到,核心無疑是Node類。

Node類是一個抽象類,它代表DOM樹中的一個節點,它包含:

  • 父節點parentNode以及子節點childNodes的引用
  • 屬性值集合attributes
  • 頁面的uribaseUri,用于修正相對地址為絕對地址
  • 在兄弟節點中的位置siblingIndex,用于進行DOM操作

Node里面包含一些獲取屬性、父子節點、修改元素的方法,其中比較有意思的是absUrl()。我們知道,在很多html頁面里,鏈接會使用相對地址,我們有時會需要將其轉變為絕對地址。Jsoup的解決方案是在attr()的參數開始加"abs:",例如attr("abs:href"),而absUrl()就是其實現方式。我寫的爬蟲框架webmagic里也用到了類似功能,當時是自己手寫的,看到Jsoup的實現,才發現自己是白費勁了,代碼如下:

<!-- lang: java --> URL base; try {try {base = new URL(baseUri);} catch (MalformedURLException e) {// the base is unsuitable, but the attribute may be abs on its own, so try thatURL abs = new URL(relUrl);return abs.toExternalForm();}// workaround: java resolves '//path/file + ?foo' to '//path/?foo', not '//path/file?foo' as desiredif (relUrl.startsWith("?"))relUrl = base.getPath() + relUrl;// java URL自帶的相對路徑解析 URL abs = new URL(base, relUrl);return abs.toExternalForm(); } catch (MalformedURLException e) {return ""; }

Node還有一個比較值得一提的方法是abstract String nodeName(),這個相當于定義了節點的類型名(例如Document是'#Document',Element則是對應的TagName)。

Element也是一個重要的類,它代表的是一個HTML元素。它包含一個字段tag和classNames。classNames是"class"屬性解析出來的集合,因為CSS規范里,"class"屬性允許設置多個,并用空格隔開,而在用Selector選擇的時候,即使只指定其中一個,也能夠選中其中的元素。所以這里就把"class"屬性展開了。Element還有選取元素的入口,例如select、getElementByXXX,這些都用到了select包中的內容,這個留到下篇文章select再說。

Document是代表整個文檔,它也是一個特殊的Element,即根節點。Document除了Element的內容,還包括一些輸出的方法。

Document還有一個屬性quirksMode,大致意思是定義處理非標準HTML的幾個級別,這個留到以后分析parser的時候再說。

DOM樹的遍歷

Node還有一些方法,例如outerHtml(),用作節點及文檔HTML的輸出,用到了樹的遍歷。在DOM樹的遍歷上,用到了NodeVisitor和NodeTraversor來對樹的進行遍歷。NodeVisitor在上一篇文章提到過了,head()和tail()分別是遍歷開始和結束時的方法,而NodeTraversor的核心代碼如下:

<!-- lang: java --> public void traverse(Node root) {Node node = root;int depth = 0;//這里對樹進行后序(深度優先)遍歷while (node != null) {//開始遍歷nodevisitor.head(node, depth);if (node.childNodeSize() > 0) {node = node.childNode(0);depth++;} else {//沒有下一個兄弟節點,退棧while (node.nextSibling() == null && depth > 0) {visitor.tail(node, depth);node = node.parent();depth--;}//結束遍歷visitor.tail(node, depth);if (node == root)break;node = node.nextSibling();}} }

這里使用循環+回溯來替換掉了我們常用的遞歸方式,從而避免了棧溢出的風險。

實際上,Jsoup的Selector機制也是基于NodeVisitor來實現的,可以說NodeVisitor是更加底層和靈活的API。

在下一篇博客我會講講Document的輸出。


總結

以上是生活随笔為你收集整理的Jsoup代码解读之二-DOM相关对象的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。