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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

XmlParser和HtmlParser

發布時間:2023/12/9 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 XmlParser和HtmlParser 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

經常要用的Xml和Html解決,實際上這個領域也有非常好的解決方案。

相對來說現在各種開源的Xml解析功能比較豐富,機制也比較靈活,但是由于他功能比較完善,干的事情比較多,所以性能方面也慢一點;另外,由于Xml天生是有嚴格格式的,所以問題不大,但是Html文件的內容是良莠不齊,有的網站經常缺少關閉標簽,有的開始是大寫,關閉是小寫等等,沒有嚴格遵守規范的時候,連Dom結構也解不正確,對于數據抓取程序來說,這就會嚴重影響正確性。

另外,一個重要的問題是數據遍歷,一般來說在數據遍歷方面,開源框架沒有在性能做過充分優化,因此,如果要進行高速檢索,就需要進行程序擴展。為此,本人編寫一套XmlParser和HtmlParser,在數據校驗方面做了刪減,不支持進行數據校驗,在容錯性方面做了擴充,在Html解決時,即使格式不正確,在大多數情況下也可以返回正確的結果。最壞的情況也,也可以解決出Dom,但是Dom結構不一定正確,而不會出現崩潰或解析異常的問題。

還有一個是簡體中文標簽的支持能力,比如: <中文 屬性1="1" 屬性2="b" />

OK,費話少說,看看調用代碼。

?
1 2 XmlStringParser parser = new XmlStringParser(); XmlDocument xmlDocument = parser.parse("<aa a=\"1\"><!--aa --><a a=\"aa\"></a></aa>");
上面就已經把xml解析好了。 ?
1 2 HtmlStringParser parser = new HtmlStringParser(); HtmlDocument xmlDocument = parser.parse("<aa a=\"1\"><!--aa --><a a=\"aa\"></a></aa>");
上面就已經把html解析好了。

由于Xml及Html都是用得統一的接口,所以,會了Xml解析,Html也是一樣樣的。

解析出的Node,都實現了下面的接口,因此遍歷方面也是非常方便的。

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 public interface Node<T extends Node<T>> extends ForEachProcessor<T> { ????/** ?????* 獲取結點頭標簽相關內容 ?????* ?????* @return StringBuffer ?????*/ ????void getHeader(StringBuffer sb); ????/** ?????* 返回子節點 ?????* ?????* @param name ?????* @return ?????*/ ????List<T> getSubNodes(String name); ????/** ?????* 添加內容節點 ?????* ?????* @param content ?????*/ ????void addContent(String content); ????/** ?????* 設置結點名稱 ?????* ?????* @param name ?????*/ ????void setNodeName(String name); ????/** ?????* 獲取結尾標簽 ?????* ?????* @return StringBuffer ?????*/ ????void getFooter(StringBuffer sb); ????/** ?????* 獲取根結點 ?????* ?????* @return T ?????*/ ????T getRoot(); ????/** ?????* 設置父親節點 ?????* ?????* @param parent ?????*/ ????void setParent(T parent); ????/** ?????* 返回節點名稱 ?????* ?????* @return ?????*/ ????String getNodeName(); ????/** ?????* 返回父親節點 ?????* ?????* @return ?????*/ ????T getParent(); ????/** ?????* 返回中間內容 ?????* ?????* @return ?????*/ ????StringBuffer getBody(); ????/** ?????* 寫出數據 ?????* ?????* @param stream ?????* @throws IOException ?????*/ ????void write(OutputStream stream) throws IOException; ????/** ?????* 返回節點類型 ?????* ?????* @return ?????*/ ????NodeType getNodeType(); ????/** ?????* 返回屬性 ?????* ?????* @param attributeName ?????* @return ?????*/ ????String getAttribute(String attributeName); ????/** ?????* 刪除屬性 ?????* ?????* @param attributeName ?????*/ ????void removeAttrivute(String attributeName); ????/** ?????* 設置屬性值 ?????* ?????* @param attributeName ?????* @param value ?????*/ ????void setAttribute(String attributeName, String value); ????/** ?????* 添加節點 ?????* ?????* @param node ?????*??????????? 要增加的節點 ?????* @return 如果增加成功,則返回node節點,否則返回null ?????*/ ????T addNode(T node); ????/** ?????* 刪除節點 ?????* ?????* @param node ?????* @return 刪除的節點,如果當前節點中不包含node節點,則返回null ?????*/ ????T removeNode(T node); ????/** ?????* 刪除指定節點 ?????* ?????* @param nodeName ?????* @return ?????*/ ????List<T> removeNode(String nodeName); ????/** ?????* 獲取內容 ?????* ?????* @return ?????*/ ????String getContent(); ????/** ?????* 變成StreamBuffer ?????* ?????* @return ?????*/ ????StringBuffer toStringBuffer(); ????/** ?????* 設置內容 ?????* ?????* @param content ?????*/ ????void setContent(String content); ????/** ?????* 返回屬屬性 ?????* ?????* @return ?????*/ ????Map<String, String> getAttributes(); ????/** ?????* 返回子節點 ?????* ?????* @return ?????*/ ????List<T> getSubNodes(); ????/** ?????* 是否單節點 ?????* ?????* @return ?????*/ ????boolean isSingleNode(); ????/** ?????* 是否大小寫敏感 ?????* ?????* @return ?????*/ ????boolean isCaseSensitive(); ????/** ?????* 根據大小寫相關返回名字 ?????* ?????* @param name ?????* @return ?????*/ ????String getCaseSensitiveName(String name); ????/** ?????* 返回純文本內容 ?????* ?????* @return ?????*/ ????String getPureText(); }
為了避免接口太過龐大,因此把格式化的處理放在獨立的結構中進行處理。 ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public interface NodeFormater<E extends Node<E>, T extends Document<E>> { ????/** ?????* 格式化文檔 ?????* ?????* @param doc ?????* @return String ?????*/ ????String format(T doc); ????void setEncode(String encode); ????/** ?????* 格式化文檔、 并在指定的輸出流中輸出 ?????* ?????* @param doc ?????* @param out ?????* @return void ?????* @throws IOException ?????*/ ????String format(E node); ????void format(T doc, OutputStream out) throws IOException; ????void format(E node, OutputStream out) throws IOException; }
要格式化輸入的話,下面的代碼就可以了: ?
1 2 3 HtmlDocument doc= new XmlStringParser().parse("<html 中='文'><head><title>aaa</title></head></html>"); HtmlFormater f = new HtmlFormater(); System.out.println(f.format(doc));
輸出結果如下:

?
1 2 3 4 5 6 7 <html 中="文"> ??<head> ????<title> ??????aaa ????</title> ??</head> </html>
上面已經演示了解析和格式化以及遍歷,下面看看檢索。

首先構建60*60*60,三層的Dom結構,也就是現在有216000個Dom節點

?
1 2 3 4 5 6 7 8 9 10 XmlNode node = new XmlNode("root"); for (int i = 0; i < 60; i++) { ????XmlNode a = node.addNode(new XmlNode("a" + i)); ????for (int j = 0; j < 60; j++) { ????????XmlNode b = a.addNode(new XmlNode("b" + j)); ????????for (int k = 0; k < 60; k++) { ????????????b.addNode(new XmlNode("c" + k)); ????????} ????} }
然后對其進行節點查找,用兩種方法進行10000次節點過濾: ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public void testSpeed() { ????long t21 = System.currentTimeMillis(); ????QuickNameFilter quick = new QuickNameFilter(node); ????long t22 = System.currentTimeMillis(); ????System.out.println("quick初始化用時" + (t22 - t21)); ????long t1 = System.currentTimeMillis(); ????String nodeName = null; ????for (int x = 0; x < 10000; x++) { ????????nodeName = quick.findNode("b6").toString(); ????} ????long t2 = System.currentTimeMillis(); ????System.out.println("QuickNameFilter用時" + (t2 - t1)); } public void testSpeed1() { ????long t21 = System.currentTimeMillis(); ????FastNameFilter fast = new FastNameFilter(node); ????long t22 = System.currentTimeMillis(); ????System.out.println("fast初始化<span></span><span></span>用時" + (t22 - t21)); ????long t1 = System.currentTimeMillis(); ????String nodeName = null; ????for (int x = 0; x < 10000; x++) { ????????nodeName = fast.findNode("b6").toString(); ????} ????long t2 = System.currentTimeMillis(); ????System.out.println("FastNameFilter用時" + (t2 - t1)); }

下面看看時間耗費情況:

?
1 2 3 4 quick初始化用時385 QuickNameFilter用時376 fast初始化用時122 FastNameFilter用時330
可以看到fast的初始化時間及查找用時,都是最快的;而quick的初始化時間和查找用時相比要慢一些。但是請注意,這都是在216000個節點中查找10000次所耗費的時間。

那么再用傳統的方式試一下---一般的開源方式也差不多在這個量級。

?
1 2 3 4 5 6 7 8 9 10 11 12 13 public void testSpeed2() { ????long t11 = System.currentTimeMillis(); ????NameFilter filter = new NameFilter(node); ????long t12 = System.currentTimeMillis(); ????System.out.println("Name初始化用時" + (t12 - t11)); ????long t1 = System.currentTimeMillis(); ????String nodeName = null; ????for (int x = 0; x < 10; x++) { ????????nodeName = filter.findNode("b6").toString(); ????} ????long t2 = System.currentTimeMillis(); ????System.out.println("NameFilter用時" + (t2 - t1)); }
運行結果: ?
1 2 Name初始化用時12 NameFilter用時83
但是,請注意,他的查詢次數是10次,如果變成10000次,就是83000ms,也就是83秒之多。與Fast過濾方式相差了680倍之多。

小結:我們實現的Xml及HtmlParser確實是有自己獨特的優點(學習成本低,Html和Xml解析方法一致,格式化輸出,緊湊輸出,容錯性,查詢效率高等等),也有不足(不支持DTD,XSD校驗),在不需要校驗的場景,需要容錯性好及過濾性能高的場景下,是非常有優勢的。

總結

以上是生活随笔為你收集整理的XmlParser和HtmlParser的全部內容,希望文章能夠幫你解決所遇到的問題。

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