亚洲kkk4444在线观看,亚洲Aⅴ在线无码播放毛片一线天 亚洲avav天堂av在线网毛片 ,亚洲女同成av人片在线观看http://www.tkk7.com/scud/category/3187.html山谷里鳥語(yǔ)花香,溪水潺潺zh-cnSat, 06 Nov 2010 15:45:19 GMTSat, 06 Nov 2010 15:45:19 GMT60MAVEN:如何為開發(fā)和生產(chǎn)環(huán)境建立不同的配置文件 --我的簡(jiǎn)潔方案http://www.tkk7.com/scud/archive/2010/10/27/336326.htmlScud(飛云小俠)Scud(飛云小俠)Wed, 27 Oct 2010 14:31:00 GMThttp://www.tkk7.com/scud/archive/2010/10/27/336326.htmlhttp://www.tkk7.com/scud/comments/336326.htmlhttp://www.tkk7.com/scud/archive/2010/10/27/336326.html#Feedback2http://www.tkk7.com/scud/comments/commentRss/336326.htmlhttp://www.tkk7.com/scud/services/trackbacks/336326.html閱讀全文

Scud(飛云小俠) 2010-10-27 22:31 發(fā)表評(píng)論
]]>
對(duì)搜索引擎同義詞支持的實(shí)驗(yàn), 分析模擬http://www.tkk7.com/scud/archive/2010/08/16/328950.htmlScud(飛云小俠)Scud(飛云小俠)Mon, 16 Aug 2010 01:26:00 GMThttp://www.tkk7.com/scud/archive/2010/08/16/328950.htmlhttp://www.tkk7.com/scud/comments/328950.htmlhttp://www.tkk7.com/scud/archive/2010/08/16/328950.html#Feedback1http://www.tkk7.com/scud/comments/commentRss/328950.htmlhttp://www.tkk7.com/scud/services/trackbacks/328950.html 今天偶爾看到一個(gè)同義詞庫(kù), 想到這個(gè)有什么用途哪? 肯定是用來(lái)判斷2句話, 2篇文章的相似性的.

它對(duì)搜索引擎,對(duì)論文抄襲鑒定系統(tǒng)肯定有用, 于是去搜索引擎試了試, 結(jié)果大失所望失望, 貌似google,bing,baidu對(duì)同義詞沒(méi)有做處理, 感覺(jué)是很簡(jiǎn)單的東西, 竟然沒(méi)有做相關(guān)處理.

而且不僅僅是沒(méi)有做同義詞處理, 相關(guān)度方面也很差, 真是很奇怪的事情.


我們隨便找一句話: (從google的桌面工具文檔里)

A: "我們十分關(guān)注您的安全并為此推出了一項(xiàng)功能",

對(duì)應(yīng)樣本為:

B: "我們非常關(guān)注您的安全并為此推出了一項(xiàng)功能"


我們搜索一下, 可以發(fā)現(xiàn) A 可以匹配的很好, 如果改成B, 發(fā)現(xiàn)和A匹配的第一項(xiàng)不見了, 按照正常猜想即使改了一個(gè)詞 相關(guān)度應(yīng)該還是很高, 不知道為什么會(huì)這樣.




替換其中一個(gè)同義詞: (發(fā)現(xiàn)原來(lái)的網(wǎng)頁(yè)不在前面了, 翻了幾頁(yè)也沒(méi)有找到)





我們暫且不考慮 "大勝美國(guó)隊(duì)" 和 "大敗美國(guó)隊(duì)"的語(yǔ)義分析, 但是上面的結(jié)果肯定不盡人意, 因?yàn)槟憧赡苄枰紤]所有同義詞, 否則可能就錯(cuò)過(guò)你想要的結(jié)果.



下面我們做一個(gè)簡(jiǎn)單的分析和模擬來(lái)實(shí)現(xiàn)同義詞的相關(guān)邏輯, 假設(shè)的流程如下:
  •     首先我們要有同義詞對(duì)應(yīng)表(多對(duì)多,可以有權(quán)重)
  •     收錄網(wǎng)頁(yè)時(shí)把相應(yīng)同義詞映射到同一個(gè)詞, 當(dāng)然可以映射多個(gè)
  •     在搜索時(shí)先預(yù)處理用戶輸入的內(nèi)容
  •     根據(jù)匹配算法計(jì)算


1. 同義詞表結(jié)構(gòu)如下

一百分 -->滿分, 0.8
十分 --> 滿分, 0.8

十分 --> 非常, 0.95
特別 --> 非常, 0.9
格外 --> 非常, 0.9

關(guān)心 --> 關(guān)注, 0.95
注意 --> 關(guān)注, 0.85

......

所有同義詞映射到同一個(gè)詞語(yǔ), 并賦予一個(gè)權(quán)重. 當(dāng)然還有多義詞的問(wèn)題, 會(huì)出現(xiàn)多個(gè)映射.

當(dāng)然同義詞的整理也是個(gè)巨大的工作量, 網(wǎng)上也有一些詞庫(kù).


2. 根據(jù)同義詞庫(kù)的映射

    原內(nèi)容: 我們十分關(guān)注您的安全并為此推出了一項(xiàng)功能
    映射后: 我們 滿分*0.8|非常*0.95|(十分) 關(guān)注您的安全并為此推出了一項(xiàng)功能

    "|"表示有多個(gè)選擇, "()"表示為原內(nèi)容.

3. 對(duì)輸入內(nèi)容的分析映射

    用戶輸入: 我們非常關(guān)心您的安全并為此推出了一項(xiàng)功能    
    分析映射: 我們非常 關(guān)注*0.95|(關(guān)心) 您的安全并為此推出了一項(xiàng)功能

4. 匹配查找
   
   匹配查找就是搜索引擎核心的邏輯了, 當(dāng)然在遇到 "滿分*0.8|非常*0.95|(十分)" 需要增加同義詞判斷邏輯, 根據(jù)2個(gè)權(quán)重可以得出一個(gè)同義詞的匹配度, 然后繼續(xù)分析即可.



以上只是一個(gè)非常簡(jiǎn)單的分析模擬, 和實(shí)際的搜索引擎邏輯差別非常大, 僅供參考.



Scud(飛云小俠) 2010-08-16 09:26 發(fā)表評(píng)論
]]>
不重復(fù)的排列組合示例http://www.tkk7.com/scud/archive/2010/07/29/327395.htmlScud(飛云小俠)Scud(飛云小俠)Thu, 29 Jul 2010 01:55:00 GMThttp://www.tkk7.com/scud/archive/2010/07/29/327395.htmlhttp://www.tkk7.com/scud/comments/327395.htmlhttp://www.tkk7.com/scud/archive/2010/07/29/327395.html#Feedback0http://www.tkk7.com/scud/comments/commentRss/327395.htmlhttp://www.tkk7.com/scud/services/trackbacks/327395.html
 1 /**
 2  * 各字符不重復(fù)的組合, 組合數(shù)小于等于最大可能性(否則就重復(fù)了).
 3  * 
 4  * @author scud(飛云)
 5  */
 6 public class ShortCombineTest
 7 {
 8     static int count = 0;
 9 
10     public static void main(String[] args)
11     {
12         String s = "123456"//all items content
13         int howmany = 3//how many object
14 
15         char[] c = s.toCharArray();
16         char[] dest = new char[howmany];
17 
18         combine(c, dest, howmany, s.length(), 0);
19 
20         System.out.println("max combine:" + count);
21     }
22 
23     public static void combine(char[] array, char[] dest, int howmany, int maxitem, int index)
24     {
25         //break & end
26         if (index == howmany)
27         {
28             System.out.println(dest);
29             count++;
30             return;
31         }
32 
33         while(array.length>0)
34         {
35             dest[index] = array[0];
36             char[] nextarray = getLeftChar(array, 0);
37             array = nextarray;
38             combine(nextarray, dest, howmany, maxitem, index + 1);
39         }
40     }
41 
42     public static char[] getLeftChar(char[] c, int index)
43     {
44         char[] left = new char[c.length - 1];
45 
46         for (int i = 0, j = 0; i < c.length; i++)
47         {
48             if (i != index)
49             {
50                 left[j] = c[i];
51                 j++;
52             }
53         }
54 
55         return left;
56     }
57 
58 
59 }
60 




Scud(飛云小俠) 2010-07-29 09:55 發(fā)表評(píng)論
]]>
最近在編寫DBHelper的文檔http://www.tkk7.com/scud/archive/2006/02/20/31634.htmlScud(飛云小俠)Scud(飛云小俠)Mon, 20 Feb 2006 05:54:00 GMThttp://www.tkk7.com/scud/archive/2006/02/20/31634.htmlhttp://www.tkk7.com/scud/comments/31634.htmlhttp://www.tkk7.com/scud/archive/2006/02/20/31634.html#Feedback0http://www.tkk7.com/scud/comments/commentRss/31634.htmlhttp://www.tkk7.com/scud/services/trackbacks/31634.html  閱讀全文

Scud(飛云小俠) 2006-02-20 13:54 發(fā)表評(píng)論
]]>
讀"Under the Hood of J2EE Clustering" J2EE集群http://www.tkk7.com/scud/archive/2005/09/28/14362.htmlScud(飛云小俠)Scud(飛云小俠)Wed, 28 Sep 2005 15:53:00 GMThttp://www.tkk7.com/scud/archive/2005/09/28/14362.htmlhttp://www.tkk7.com/scud/comments/14362.htmlhttp://www.tkk7.com/scud/archive/2005/09/28/14362.html#Feedback0http://www.tkk7.com/scud/comments/commentRss/14362.htmlhttp://www.tkk7.com/scud/services/trackbacks/14362.html閱讀全文

Scud(飛云小俠) 2005-09-28 23:53 發(fā)表評(píng)論
]]>
幾個(gè)提高代碼質(zhì)量,檢查代碼規(guī)范的工具http://www.tkk7.com/scud/archive/2005/08/29/11422.htmlScud(飛云小俠)Scud(飛云小俠)Mon, 29 Aug 2005 03:49:00 GMThttp://www.tkk7.com/scud/archive/2005/08/29/11422.htmlhttp://www.tkk7.com/scud/comments/11422.htmlhttp://www.tkk7.com/scud/archive/2005/08/29/11422.html#Feedback0http://www.tkk7.com/scud/comments/commentRss/11422.htmlhttp://www.tkk7.com/scud/services/trackbacks/11422.html
1.FindBugs:查錯(cuò)
 目前版本0.9.1,有for eclipse的插件. 網(wǎng)址是http://findbugs.sourceforge.net.
 
 工作原理:檢查程序生成的class的工具.
 
 界面:獨(dú)立運(yùn)行的提供圖形界面,很友好,有bug報(bào)告.
 
 可用性:大多數(shù)提示有用,值得改
 
 插件:
  可以設(shè)置基本和檢查的錯(cuò)誤類別.
  插件保存設(shè)置有問(wèn)題,我是關(guān)閉項(xiàng)目后臺(tái)修改了配置文件,在裝入才成功改了配置的.
  bug臨時(shí)解決: 使用獨(dú)立的findbugs設(shè)置規(guī)則,然后到C:\Documents and Settings\XXX\下找.Findbugs_prefs,然后改名覆蓋eclipse project下的.fbprefs (先關(guān)閉你的project)
 
 配置沒(méi)有查找功能,不過(guò)縮寫能讓我們很快找到某個(gè)規(guī)則
 
2.PMD:主要是查錯(cuò)
 目前版本3.2,有for eclipse以及其他ide的插件.網(wǎng)址是http://pmd.sourceforge.net
 工作原理:檢查源碼
 可用性:一部分值得修改,有些過(guò)于嚴(yán)格
 界面:獨(dú)立運(yùn)行的是命令行界面,命令比較簡(jiǎn)單.
 插件:可以配置規(guī)則,有一個(gè)獨(dú)立的窗口顯示提示,分5級(jí)提示,很友好
 
 使用:建立自己的規(guī)范,然后用于實(shí)際使用中.
 
3.CheckStyle:主要查代碼規(guī)范
 目前版本4.0 beta 5,有for eclipse的插件.網(wǎng)址是http://checkstyle.sourceforge.net.
 工作原理:檢查源碼,對(duì)javadoc,書寫格式等進(jìn)行檢查.
 規(guī)則定義:默認(rèn)的規(guī)則是sun的編碼規(guī)范.不過(guò)按照sun的規(guī)則則過(guò)于嚴(yán)格,而且每個(gè)公司也有自己的規(guī)范,和sun的不同,所以需要自定義規(guī)范. 

4.JTest 重量級(jí)的商業(yè)工具
 目前版本7.0.7,有for eclipse的插件.網(wǎng)址是http://www.parasoft.com/
 
 不推薦使用,不過(guò)功能強(qiáng)大,可以進(jìn)行代碼檢查,可以自動(dòng)生成單元測(cè)試和進(jìn)行單元測(cè)試.(不過(guò)就是太慢了,而且生成的單元測(cè)試沒(méi)太大用途)
 
 
 

使用感覺(jué):

 安裝上插件后,對(duì)自己的項(xiàng)目進(jìn)行檢查,發(fā)現(xiàn)警告太多了,有點(diǎn)發(fā)蒙的感覺(jué).不過(guò)把警告看一遍,覺(jué)得都很有道理,有些也確實(shí)是一些錯(cuò)誤.
 當(dāng)然PMD和CheckStyle的規(guī)范太嚴(yán)格,最后還是配置了一下.
 
 通過(guò)改正警告,感覺(jué)還是不錯(cuò),至少可以說(shuō)自己的代碼可以通過(guò)工具的檢測(cè)了.
 
 當(dāng)然基礎(chǔ)代碼和項(xiàng)目代碼還是不一樣的,基礎(chǔ)代碼往往比較復(fù)雜,所以和普通項(xiàng)目代碼的規(guī)范應(yīng)該有所不同.有些規(guī)則只能用在普通代碼上,用在基礎(chǔ)類代碼上往往沒(méi)法處理.
 
其他

代碼查錯(cuò)推薦使用Findbugs和PMD,代碼書寫規(guī)范推薦使用CheckStyle進(jìn)行檢查.這樣不僅能查出一些基本的錯(cuò)誤,也能提高項(xiàng)目的代碼質(zhì)量.對(duì)提高自己的代碼水平也是非常好.

推薦項(xiàng)目組建立統(tǒng)一的規(guī)則,代碼復(fù)查的時(shí)候就使用這些工具,省時(shí)省力.

實(shí)乃居家旅行,殺人越貨必備之工具也.(因?yàn)榭隙ㄓ腥艘R你,呵呵,也是你找"差"的工具)


 
 



Scud(飛云小俠) 2005-08-29 11:49 發(fā)表評(píng)論
]]>
分析XML中的CDATA類型在RSS中的使用http://www.tkk7.com/scud/archive/2005/08/22/10723.htmlScud(飛云小俠)Scud(飛云小俠)Mon, 22 Aug 2005 10:49:00 GMThttp://www.tkk7.com/scud/archive/2005/08/22/10723.htmlhttp://www.tkk7.com/scud/comments/10723.htmlhttp://www.tkk7.com/scud/archive/2005/08/22/10723.html#Feedback0http://www.tkk7.com/scud/comments/commentRss/10723.htmlhttp://www.tkk7.com/scud/services/trackbacks/10723.html除經(jīng)特別注明外,本站文章版權(quán)歸JScud Develop團(tuán)隊(duì)或其原作者所有.
轉(zhuǎn)載請(qǐng)注明作者和來(lái)源.  scud(飛云小俠)    歡迎訪問(wèn) JScud Develop



根據(jù)XML中CDATA類型的規(guī)范可以知道:"&"和"<"不需要也不能被轉(zhuǎn)換. ">" 如果出現(xiàn)在"]]>" 的內(nèi)容而不是表示結(jié)束時(shí),必須被轉(zhuǎn)義為&gt;

但是這樣就存在一個(gè)問(wèn)題,如果我需要輸入"]]>",正確的處理是保存為"]]&gt;",但是如果我想輸入"]]&gt;",那么應(yīng)該如何保存哪? 我想了很久,除非加空格或者采用特殊的辦法,否則是沒(méi)有辦法解決的.

1.如果我們不考慮輸入"]]&gt;"的問(wèn)題,來(lái)考慮一下"]]>"的處理,看看各種XML解析器是如何處理的?

xml解析器的測(cè)試包含2個(gè)部分:設(shè)置cdata類型的數(shù)據(jù)和讀出cdata類型的數(shù)據(jù).

首先我們寫一個(gè)測(cè)試的例子,計(jì)劃使用JDom 1.0和Dom4j來(lái)測(cè)試一下:

 package com.jscud.test;
 
 public class XmlTestBase
 { 
     public static String xmlpart =
      "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"+
         "<xml>" +
         "<test>"+
         "<hello><![CDATA[ hello ]]&gt; ]]></hello>" +
         "</test>" +
         "</xml>";       
    
     public static void print(String str)
     {
         System.out.println(str);
     }    
 } 


JDom測(cè)試的例子如下:

package com.jscud.test;
 
 import java.io.*;
 import org.jdom.*;
 import org.jdom.input.SAXBuilder;
 import org.jdom.output.*;
 
 //@author scud http://www.jscud.com
 
 public class JDomXmlFileTest extends XmlTestBase
 {
 
     public static void main(String[] args) throws Exception
     {
         readDocument();
         print("===========================");
         createDocument();
     }
    
     public static void readDocument() throws Exception
     {
         Reader reader = new StringReader(xmlpart);
         SAXBuilder builder = new SAXBuilder();
        
         Document doc = builder.build(reader);
 
         Element aRoot = doc.getRootElement();
        
         Element anode = aRoot.getChild("test").getChild("hello");
        
         print(anode.getText());       
     }
 
     public static void createDocument() throws Exception
     {       
         Document doc = new Document();
        
         doc.setRootElement(new Element("root"));
        
         CDATA node = new CDATA("hello alt=]]&gt;");
        
         //throw Exception
         //node.setText("hello]]>");
        
         Element ele = new Element("hello");
        
         ele.setContent(node);
        
         Element root = doc.getRootElement();
        
         root.getChildren().add(ele);
        
         XMLOutputter outputter = new XMLOutputter();
         Format aFormat = Format.getCompactFormat();
         aFormat.setEncoding("GB2312");
        
         String sResult = outputter.outputString(doc.getRootElement().getChildren());
        
        print(sResult);
        
     }
 } 

 編譯并運(yùn)行上面的代碼結(jié)果,我們可以看到JDom無(wú)法設(shè)置Cdata的值為"]]>",會(huì)報(bào)異常.從xml字符串讀出cdata的結(jié)果也沒(méi)有把字串"]]&gt;"翻譯為"]]>".

接著再來(lái)測(cè)試Dom4J:

package com.xml.test;
 
 import java.io.StringReader;
 
 import org.dom4j.*;
 import org.dom4j.io.SAXReader;
 import org.dom4j.tree.DefaultCDATA;
 
 /**
  * 測(cè)試XML的CData數(shù)據(jù)類型.
  *
  * @author scud http://www.jscud.com
  *
  */
 
 public class Dom4jXmlTest extends XmlTestBase
 {   
 
     public static void main(String[] args) throws Exception
     {
         readDocument();
         print("===========================");
         createDocument();       
     }
    
     public static void createDocument()
     {
         Document document = DocumentHelper.createDocument();
         Element root = document.addElement( "root" );
        
         DefaultCDATA cdata = new DefaultCDATA("sample]]>");
         DefaultCDATA cdata2 = new DefaultCDATA("sample]]&gt;");
        
         Element anode = root.addElement("cdata");
         anode.add(cdata);
        
         print(anode.getText());       
         print(anode.asXML());
        
         Element anode2 = root.addElement("cdata2");
         anode2.add(cdata2);
        
         print(anode2.getText());       
         print(anode2.asXML());
     }
    
     public static void readDocument() throws Exception
     {
         StringReader strreader = new StringReader(xmlpart);
        
         SAXReader reader = new SAXReader();
         Document document = reader.read(strreader);
        
         Node node = document.selectSingleNode( "http://test/hello" );
        
         print(node.getText());
        
         print(node.getStringValue());
     }
    
 } 

 
 我們可以看到Dom4j也是沒(méi)有做任何處理,輸入的時(shí)候不作任何轉(zhuǎn)換,原樣輸出,這樣必然導(dǎo)致xml錯(cuò)誤.讀出的時(shí)候也沒(méi)有做轉(zhuǎn)換.

根據(jù)上面的測(cè)試我們可以得出結(jié)論:很多xml解析器沒(méi)有正確解析cdata的數(shù)據(jù),(jdom和dom4j用的人比較多),不要太相信這些解析器.

 

2.我們?cè)賮?lái)看看閱讀RSS的RSS閱讀器吧,例如FeedDemon和POTU,我們準(zhǔn)備了一個(gè)CData類型的description字段,來(lái)進(jìn)行測(cè)試.

內(nèi)容:

<?xml version="1.0" encoding="GB2312" ?>
 <rss version="2.0">
 <channel>
  <title>Some Where</title>
  <link>http://www.jscud.com/</link>
  <description />
 <item>
  <title>Test</title>
  <link>http://www.jscud.com</link>
  <author>scud</author>
  <pubDate>Mon, 22 Aug 2005 10:22:22 GMT</pubDate>
  <description><![CDATA[
  &lt;hr&gt;
  ]]&gt;
  ]]></description>
  </item>
  </channel>
  </rss>


結(jié)果
 1.POTU沒(méi)有做任何處理
 2.FeedDemon做了處理,不過(guò)同時(shí)也把其他的&gt; &lt;等等都翻譯了,這就更不對(duì)了..
 

本來(lái)我是打算在RSS里使用CDATA類型的description字段的,經(jīng)過(guò)幾番試驗(yàn)和測(cè)試,最后決定還是使用普通的description字段了,不在使用CDATA了.

CDATA? 雞肋乎? 呵呵

 



Scud(飛云小俠) 2005-08-22 18:49 發(fā)表評(píng)論
]]>
使用FreeMarker/Jsp(webwork)生成靜態(tài)/動(dòng)態(tài)RSS文件http://www.tkk7.com/scud/archive/2005/08/19/10510.htmlScud(飛云小俠)Scud(飛云小俠)Fri, 19 Aug 2005 06:11:00 GMThttp://www.tkk7.com/scud/archive/2005/08/19/10510.htmlhttp://www.tkk7.com/scud/comments/10510.htmlhttp://www.tkk7.com/scud/archive/2005/08/19/10510.html#Feedback0http://www.tkk7.com/scud/comments/commentRss/10510.htmlhttp://www.tkk7.com/scud/services/trackbacks/10510.htmlscud(飛云小俠)  http://www.jscud.com 轉(zhuǎn)載請(qǐng)注明作者/來(lái)源

關(guān)鍵字:rss,freemarker,rss.xml,webwork2

RSS在網(wǎng)絡(luò)上大行其道,各種網(wǎng)站都加上RSS支持,我最近也研究了一下,給我的文章也加上了RSS訂閱.

RSS目前用的也有幾個(gè)版本,很是混亂,下面以RSS2.0為例來(lái)說(shuō)明.

網(wǎng)絡(luò)上有個(gè)rsslibj庫(kù),是用來(lái)生成rss支持文件的,不過(guò)已經(jīng)好久沒(méi)有更新了,它是用xml的方式生成的.本文的例子不用到任何xml解析器,不過(guò)當(dāng)然要知道最后生成的XML文件的格式才行,關(guān)于RSS規(guī)范,可以瀏覽一下 http://blogs.law.harvard.edu/tech/rss .

在計(jì)劃生成RSS文件的時(shí)候,順便搜索了一下JIRA和Confluence的程序,發(fā)現(xiàn)它們分別是用模板方式和JSP動(dòng)態(tài)頁(yè)面來(lái)展示的.于是我也想到兩種方式:
1.用FreeMarker生成靜態(tài)文件,適用于更新不是很頻繁的內(nèi)容.
2.用JSP動(dòng)態(tài)展示,適合更新頻率高,種類繁多的內(nèi)容.

還是以本站的新聞舉例,其中的新聞信息類參考 http://www.jscud.com/srun/news/viewhtml/3_2005_8/76.htm ,此處不在列出.

(一) 先說(shuō)FreeMarker方式.

根據(jù)RSS的規(guī)范,得到模板如下:

<?xml version="1.0" encoding="UTF-8" ?>
 <rss version="2.0">
 <channel>
  <title>JScud Develop</title>
  <link>http://www.jscud.com/</link>
  <language>zh-cn</language>
  <description >JScud Develop By Scud</description>
  <webMaster>xxx@21cn.com(scud)</webMaster>
  <lastBuildDate>${rssutil.formatRssDate(now)}</lastBuildDate>
   
   <#list newslist as onenews>
  <item>
   <title>${onenews.title?xml}</title>
   <link>http://www.jscud.com/srun/news/viewhtml/${onenews.htmlFilePath}/${onenews.nid}.htm</link>
   <pubDate>${rssutil.formatRssDate(onenews.addtime)}</pubDate>
   <description><![CDATA[
  ${rssutil.formatRssCData(onenews.showContent)}
   ]]>
   </description>
   </item>
 </#list>
  </channel>
 </rss>

其中的網(wǎng)址和網(wǎng)站名稱可以根據(jù)自己的實(shí)際情況修改.

我每次取出最新的20條文章來(lái)生成RSS,不過(guò)內(nèi)容比較多,生成的RSS文件比較大,看到有的網(wǎng)站的description只是放了文章摘要的內(nèi)容,這樣文件就小多了.總之是根據(jù)自己的需求設(shè)計(jì)吧.

其中用到的RssUtil函數(shù)庫(kù)的函數(shù)如下(日期的函數(shù)參考上一篇文章):

    /**
     * 把]]>替換為]]&gt;
     * @param content 內(nèi)容
     * @return 格式化后的內(nèi)容
     */
    public static String formatRssCData(String content)
    {
        String result = StringFunc.replace(content,"\\]\\]>","]]&gt;");
       
        return result;
    }
   
    /**
     * 格式化為xml需要的字符串
     * @param field 內(nèi)容
     * @return 格式化后的串
     */
    public static String formatString2XML(String field)
    {
        return StringFunc.str2TextXML(field);
    }
   
    public static String getNowDateTime()
    {
        return formatRssDate(DateTime.getNowTimestamp());
    }

利用FreeMarker生成靜態(tài)文件的代碼如下:

 private Configuration freemarker_cfg = null;
 
    protected Configuration getFreeMarkerCFG()
    {
        if (null == freemarker_cfg)
        {
            // Initialize the FreeMarker configuration;
            // - Create a configuration instance
            freemarker_cfg = new Configuration();

            freemarker_cfg.setClassForTemplateLoading(this.getClass(), "/htmlskin");

            freemarker_cfg.setDefaultEncoding("GBK");
        }

        return freemarker_cfg;
    }

    public boolean geneFileByFreeMarker(String templateFileName, Map propMap, String filePath,
                    String fileName, String encode)
    {
        try
        {
            Template t = getFreeMarkerCFG().getTemplate(templateFileName);

            File afile = new File(filePath + "/" + fileName);

            Writer out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(afile),
                            encode));

            propMap.put("baseurl", PropSet.getStringProp("url.root"));

            t.process(propMap, out);
        }
        catch (TemplateException e)
        {
            LogMan.error("Error while processing FreeMarker template " + templateFileName, e);
            return false;
        }
        catch (IOException e)
        {
            LogMan.error("Error while generate File " + fileName, e);
            return false;
        }

        return true;
    }


新聞系統(tǒng)中調(diào)用重新生成RSS文件的代碼如下:

    /**
     * 重新生成RSS文件.
     *
     * @param nid 更新的新聞的id,如果不包含在最新的新聞里,則不更新RSS.nid <1則更新
     *
     * @return 是否成功
     */
    private boolean renewRSS(int nid)
    {
        List newsList = 裝載新聞的代碼

        boolean shouldUpdate = false;
        if (nid > 0)
        {
            for (int i = 0; i < newsList.size(); i++)
            {
                NewsItem aNews = (NewsItem) newsList.get(i);
                if (aNews.getNid() == nid)
                {
                    shouldUpdate = true;
                    break;
                }
            }
        }
        else
        {
            shouldUpdate = true;
        }

        //不更新,則返回
        if (!shouldUpdate)
        {
            return true;
        }

        Map root = new HashMap();
       
        root.put("rssutil",new RSSUtil());

        root.put("newslist", newsList);
       
        root.put("now",DateTime.getNowTimestamp());

        geneFileByFreeMarker("/news/rss.ftl", root, PropSet.getStringProp("rss.rssdir"), PropSet
                        .getStringProp("rss.rssfile"), "UTF-8");

        return true;
    }



在增加或者更新/刪除新聞的地方需要調(diào)用這個(gè)renewRSS函數(shù).

(二)JSP動(dòng)態(tài)方式

相對(duì)靜態(tài)方式而言,簡(jiǎn)單的多,不過(guò)效率上可能就不太好了.

webwork2的Action代碼如下:

        newsList = 裝載新聞代碼
        return SUCCESS; 


視圖Jsp如下:


<%@ page contentType="text/xml; charset=UTF-8"%>
<%@ taglib uri="jscud" prefix="jscud" %>
<%@ taglib uri="webwork" prefix="ww" %>
<ww:bean name="’com.jscud.www.util.RSSUtil’" id="rssUtil" />
<?xml version="1.0" encoding="UTF-8" ?>
 <rss version="2.0">
 <channel>
  <title>JScud Develop</title>
  <link>http://www.jscud.com/</link>
  <language>zh-cn</language>
  <description >JScud Develop By Scud</description>
  <webMaster>xxx@21cn.com(scud)</webMaster>
  <lastBuildDate><ww:property value="#rssUtil.nowDateTime" /></lastBuildDate>
   
   <ww:iterator value="newsList">
  <item>
   <title><ww:property value="#rssUtil.formatString2XML(title)"/></title>
   <link>http://www.jscud.com/srun/news/viewhtml/<ww:property  value="htmlFilePath" />/<ww:property  value="nid" />.htm</link>
   <pubDate><ww:property  value="#rssUtil.formatRssDate(addtime)" /></pubDate>
   <description><![CDATA[
  <ww:property value="#rssUtil.formatRssCData(showContent)"/>
   ]]>
   </description>
   </item>
 </ww:iterator>
  </channel>
 </rss>

jsp的方式簡(jiǎn)單多了,上面的jsp里面還演示了ww:bean的使用 :)


上面的類里面引用了很多其他的工具類,這里不一一列出,可以自己實(shí)現(xiàn)它們,都是很簡(jiǎn)單的類. :)



Scud(飛云小俠) 2005-08-19 14:11 發(fā)表評(píng)論
]]>
Rss 中日期格式的研究http://www.tkk7.com/scud/archive/2005/08/17/10370.htmlScud(飛云小俠)Scud(飛云小俠)Wed, 17 Aug 2005 10:11:00 GMThttp://www.tkk7.com/scud/archive/2005/08/17/10370.htmlhttp://www.tkk7.com/scud/comments/10370.htmlhttp://www.tkk7.com/scud/archive/2005/08/17/10370.html#Feedback1http://www.tkk7.com/scud/comments/commentRss/10370.htmlhttp://www.tkk7.com/scud/services/trackbacks/10370.htmlscud(飛云小俠) http://www.jscud.com 轉(zhuǎn)載請(qǐng)注明來(lái)源/作者

 

rss中日期格式要求遵守rfc822規(guī)范,其中是這么寫的:

     date-time   =  [ day "," ] date time        ; dd mm yy
                                                 ;  hh:mm:ss zzz

     day         =  "Mon"  / "Tue" /  "Wed"  / "Thu"
                 /  "Fri"  / "Sat" /  "Sun"

     date        =  1*2DIGIT month 2DIGIT        ; day month year
                                                 ;  e.g. 20 Jun 82

     month       =  "Jan"  /  "Feb" /  "Mar"  /  "Apr"
                 /  "May"  /  "Jun" /  "Jul"  /  "Aug"
                 /  "Sep"  /  "Oct" /  "Nov"  /  "Dec"

     time        =  hour zone                    ; ANSI and Military

     hour        =  2DIGIT ":" 2DIGIT [":" 2DIGIT]
                                                 ; 00:00:00 - 23:59:59

     zone        =  "UT"  / "GMT"                ; Universal Time
                                                 ; North American : UT
                 /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4
                 /  "CST" / "CDT"                ;  Central:  - 6/ - 5
                 /  "MST" / "MDT"                ;  Mountain: - 7/ - 6
                 /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7
                 /  1ALPHA                       ; Military: Z = UT;
                                                 ;  A:-1; (J not used)
                                                 ;  M:-12; N:+1; Y:+12
                 / ( ("+" / "-") 4DIGIT )        ; Local differential
                                                 ;  hours+min. (HHMM)

 



可以看出,前面的星期X是可以省略的,后面的時(shí)間是要求有時(shí)區(qū)的.

示例如下(以在中國(guó)的中文操作系統(tǒng)機(jī)器為例):


 1.Tue, 16 Aug 2005 15:33:33 GMT
 2.Tue, 16 Aug 2005 23:33:33 +0800

其實(shí)這個(gè)rfc822應(yīng)該也是電子郵件內(nèi)容格式的規(guī)范,找一個(gè)郵件看看內(nèi)容,也可以看出,郵件的時(shí)間格式也是遵循這個(gè)規(guī)范的.

要輸入第一種格式,使用SimpleDateFormat格式化即可,代碼如下

    public static void test1(Date date)
    {
        SimpleDateFormat sdfTemp = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss z",Locale.US);
       
        SimpleTimeZone aZone = new SimpleTimeZone(8,"GMT");       
        sdfTemp.setTimeZone(aZone);
       
        System.out.println(sdfTemp.format(date));       
    } 

注意,其中設(shè)置了時(shí)區(qū)為GMT,否則會(huì)輸出:

 Tue, 16 Aug 2005 23:33:33 CST

這里的CST意思是代表"中國(guó)時(shí)間",但是一經(jīng)搜索,發(fā)現(xiàn)CST代表了好幾個(gè)時(shí)區(qū),太讓人混亂了.而在RTF822里面,CST僅代表美國(guó)中部時(shí)間.所以如果使用SimpleDateFormat,要設(shè)置時(shí)區(qū)以GMT表示,否則容易讓人迷惑而且不知道是那個(gè)時(shí)區(qū).

假設(shè)你在中國(guó),想根據(jù)當(dāng)?shù)貢r(shí)間輸入復(fù)合當(dāng)?shù)貢r(shí)間的字符串,讓人一看就能明白文章的日期,那么就使用第二種格式.(我推薦使用第二種方式,當(dāng)然你的頻道主要給外國(guó)朋友瀏覽登除外)

上面說(shuō)到和郵件有關(guān),于是我們看看JavaMail包里面的javax.mail.internet.MailDateFormat,可以用來(lái)格式化日期:
(MyEclipse 3.8.4附帶的J2EE 1.3中的JavaMail包)

        MailDateFormat mdf = new MailDateFormat();
       
        SimpleTimeZone aZone = new SimpleTimeZone(8,"GMT");       
        //mdf.setTimeZone(aZone);      
       
        System.out.println(mdf.format(date));        

輸出結(jié)果為:

 Tue, 16 Aug 2005 23:33:33 +0800 (CST)
 
如果設(shè)置了時(shí)區(qū)為GMT,則輸出:

 Tue, 16 Aug 2005 15:33:33 +0000 (GMT) 
 
 
 
可以看到相對(duì)RTF822而言,好像多了一個(gè)后面的時(shí)區(qū)的說(shuō)明及其括號(hào).不知道這到底是怎么回事?

在硬盤上查找一番,發(fā)現(xiàn)在JIRA程序和Confluence中的RSS里都使用了這個(gè)日期格式. 

注意到這個(gè)不同,我瀏覽了一下outlook Express里面的郵件,發(fā)現(xiàn)兩種時(shí)間格式的郵件都存在,真是讓人迷惑,或許都可以吧,呵呵 :)

如果不想使用MailDateFormat的格式,那么就自己寫一個(gè)類來(lái)實(shí)現(xiàn)吧,例如

 public class RssDateFormat extends MailDateFormat
 {
     public RssDateFormat()
     {
         applyPattern("EEE, d MMM yyyy HH:mm:ss ’XXXXX’");       
     }
 
 } 

 
這是最簡(jiǎn)單的了,當(dāng)然可以把MailDateFormat的源碼拿過(guò)來(lái)改改更好一點(diǎn),還不用依賴JavaMail了. :)

至此,我的RSS中的日期終于正確而且讓我滿意了. :)

 


 



Scud(飛云小俠) 2005-08-17 18:11 發(fā)表評(píng)論
]]>
使用Lucene進(jìn)行全文檢索(三)---進(jìn)行搜索http://www.tkk7.com/scud/archive/2005/08/12/9981.htmlScud(飛云小俠)Scud(飛云小俠)Fri, 12 Aug 2005 09:34:00 GMThttp://www.tkk7.com/scud/archive/2005/08/12/9981.htmlhttp://www.tkk7.com/scud/comments/9981.htmlhttp://www.tkk7.com/scud/archive/2005/08/12/9981.html#Feedback0http://www.tkk7.com/scud/comments/commentRss/9981.htmlhttp://www.tkk7.com/scud/services/trackbacks/9981.htmlscud(飛云小俠) http://www.jscud.com 轉(zhuǎn)載請(qǐng)注明來(lái)源/作者

關(guān)鍵字:lucene,html parser,全文檢索,IndexReader,Document,Field,IndexWriter,Term,HTMLPAGE


 無(wú)論是建立索引還是分析內(nèi)容,都是為了用戶的搜索服務(wù).
 
 在Lucene中,如果需要使用搜索,需要使用Searcher類,這是一個(gè)抽象類,它有2個(gè)子類:IndexSearcher和MultiSearcher.
 
 IndexSearcher是對(duì)一個(gè)索引進(jìn)行搜索,如果你需要對(duì)多個(gè)索引進(jìn)行搜索,可以使用MultiSearcher.下面的內(nèi)容只介紹了IndexSearcher.
 
 搜索涉及到幾個(gè)問(wèn)題:分頁(yè),組合條件,根據(jù)條件過(guò)濾,排序等等.
 
 分頁(yè):分頁(yè)在記錄列表的地方都會(huì)遇到,這里不在贅述,我也實(shí)現(xiàn)過(guò)一個(gè)保存分頁(yè)結(jié)果和顯示結(jié)果的類,用于自己的實(shí)際工作,下面也會(huì)用到保存分頁(yè)結(jié)果的類,代碼如下:

  package com.jscud.support;
  
  
  /**
   * 分頁(yè)顯示用的參數(shù).
   *
   * @author scud(飛云小俠) http://www.jscud.com
   * 
   */
  
  public class DivPageInfo
  {
  
      //開始記錄數(shù)
      private int recStart;
  
      //結(jié)束記錄數(shù)
      private int recEnd;
  
      //總頁(yè)數(shù)
      private int pageCount;
  
      //當(dāng)前頁(yè)
      private int page;
  
      //記錄總數(shù)
      private int recCount;
     
      //每頁(yè)記錄數(shù)
      private int perPageRows;
  
      public int getNicePageCount()
      {
          return getNicePageNum(pageCount);
      }
     
      //get,set等,不在列出
      //......
  
     
      /**
       * 得到友好的頁(yè)數(shù)數(shù)字,頁(yè)數(shù)為0時(shí),返回1.
       *
       * @return 得到友好的頁(yè)數(shù)
       */
      public static int getNicePageNum(int nPage)
      {
              if (nPage == 0)
              {
                      return 1;
              }
              else
              {
                      return nPage;
              }
      }   
  } 

 顯示分頁(yè)結(jié)果的類就需要大家根據(jù)自己使用的框架來(lái)具體實(shí)現(xiàn)了.我使用的是WebWork.
 
 組合條件:在Lucene中,搜索的條件可以組合的很復(fù)雜,相關(guān)的類有BooleanQuery, FilteredQuery, MultiTermQuery, PhrasePrefixQuery, PhraseQuery, PrefixQuery, RangeQuery, SpanQuery, TermQuery 等等,從而可以組合出很復(fù)雜的條件用于查詢.
 另外QueryParser可以根據(jù)用戶輸入的字符串和設(shè)定的解析器和字段設(shè)置等,可以自動(dòng)產(chǎn)生新的組合條件用于查詢,例如用戶輸入"john AND black",QueryParser可以自己分析出用戶是需要查詢字段中同時(shí)包含"john"和"black"的結(jié)果.
 
 過(guò)濾條件:有時(shí)候根據(jù)具體的用戶需求,有些記錄對(duì)于一些用戶是不可見的,此時(shí)就要使用過(guò)濾器來(lái)防止不合法的用戶看到不應(yīng)該看到的記錄.過(guò)濾器同時(shí)也可以根據(jù)一些具體的條件來(lái)過(guò)濾掉一些用戶不想看到的記錄.如果需要實(shí)現(xiàn)自己的filter,只要參考QueryFilter,DateFilter實(shí)現(xiàn)Filter即可.
 
 排序:有時(shí)候,可能需要根據(jù)某個(gè)字段進(jìn)行排序,例如按照時(shí)間排序.當(dāng)然更多的時(shí)候是按照搜索結(jié)果的符合度進(jìn)行排序,lucene默認(rèn)的排序就是按照符合度來(lái)進(jìn)行排序的.
 
 進(jìn)行搜索的代碼如下,根據(jù)自己的需要進(jìn)行代碼的修改:
 

 /**
 * 進(jìn)行搜索.
 *
 * 參數(shù)依次為:搜索內(nèi)容(支持lucene語(yǔ)法),當(dāng)前頁(yè),每頁(yè)記錄數(shù),分頁(yè)信息對(duì)象
 *
 */
    public static List search(String searchText, int page, int perpage, final DivPageInfo pageinfo)
    {
        List docs = new ArrayList();
       
        if(!LuceneSearch.indexExist(indexDir)) { return docs; }

        Searcher searcher = null;
        try
        {
            StandardAnalyzer analyzer = new StandardAnalyzer();

            //處理檢索條件
            Query titleQuery = QueryParser.parse(searchText, "title", analyzer);
            Query contextQuery = QueryParser.parse(searchText, "content", analyzer);
            Query otherQuery = QueryParser.parse(searchText, "other", analyzer);

            BooleanQuery query = new BooleanQuery();
            query.add(titleQuery, false, false);
            query.add(contextQuery, false, false);
            query.add(otherQuery, false, false);

            //分頁(yè)檢索
            searcher = new IndexSearcher(indexDir);
            Hits hits = searcher.search(query);

            DivPageInfo.divPage(hits.length(), perpage, page, pageinfo);

            //取出當(dāng)前頁(yè)的記錄
            for (int i = pageinfo.getRecStart(); i <= pageinfo.getRecEnd(); i++)
            {
                docs.add(LuceneDocument.getDocument(hits.doc(i - 1)));
            }
        }
        catch (IOException e)
        {
            LogMan.error("Error occur When Search Lucene", e);
        }
        catch (ParseException e)
        {
            LogMan.error("Error occur When Search Lucene", e);
        }
        finally
        {
            try
            {
                if (null != searcher)
                {
                    searcher.close();
                }
            }
            catch (IOException e)
            {
                LogMan.warn("Close searcher Error");
            }
        }

        return docs;
    }



 
 代碼中出現(xiàn)了一個(gè)新的類Hits,Hits是lucene的搜索結(jié)果集,是lazy load的結(jié)果集,只有你真正訪問(wèn)它,它才去裝載真正的數(shù)據(jù).
 
 代碼中還出現(xiàn)了一個(gè)LuceneDocument,這是為了在頁(yè)面中顯示而寫的一個(gè)輔助類,因?yàn)閘ucene的Document是final的,無(wú)法進(jìn)行擴(kuò)展,而要顯示時(shí)間字段必須要調(diào)用DateField中的函數(shù),這樣在頁(yè)面中顯示就不太直觀了,所以寫了這個(gè)輔助類,代碼如下:
 

  package com.jscud.www.support.search;
  
  import java.sql.Timestamp;
  import java.util.Date;
  
  import org.apache.lucene.document.DateField;
  import org.apache.lucene.document.Document;
  import org.apache.lucene.document.Field;
  
  /**
   * 對(duì)Lucene的Document的封裝,用于顯示目的.
   *
   * @author scud(飛云小俠) http://www.jscud.com
   *
   */
  public class LuceneDocument
  {
      private Document doc;
     
      public LuceneDocument(Document doc)
      {
          this.doc = doc;
      }
     
      public static LuceneDocument getDocument(Document doc)
      {
          return new LuceneDocument(doc);
      }
     
      public String getValue(String name)
      {
          return doc.get(name);
      }
     
      public Field getField(String name)
      {
          return doc.getField(name);
      }
     
      public Timestamp getDateTime(String name)
      {
          String value = doc.get(name);
          return new Timestamp( DateField.stringToTime(value));
      }
     
      public Date getDate(String name)
      {
          String value = doc.get(name);
          return  DateField.stringToDate(value);       
      }    
  }


 
 使用WebWork對(duì)結(jié)果集進(jìn)行了顯示,代碼如下:

          <ww:iterator value="docs">
          <tr >         
          <td>
          <a href="<jscud:contextpath /><ww:property  value="getValue('visiturl')" />"  target="_blank" >
          <ww:property value="getValue('title')" escape="true" />
          </a> &nbsp; (<jscud:datetime value="getDateTime('addtime')" />)
          </td>
          </tr>
          </ww:iterator> 
  



 然后調(diào)用分頁(yè)信息顯示tag即可.
 
 
 通過(guò)以上的應(yīng)用,可以看到,其實(shí)使用lucene很簡(jiǎn)單,以前總覺(jué)得很神秘,所以一直沒(méi)有使用過(guò),用過(guò)之后才覺(jué)得如此簡(jiǎn)單.
 
 
 當(dāng)然,對(duì)于大容量數(shù)據(jù)下,群集情況下,在網(wǎng)上都有很多解決方案,在此不一一提出,感興趣的讀者可以自己去搜索. :)
 



Scud(飛云小俠) 2005-08-12 17:34 發(fā)表評(píng)論
]]>
使用Lucene進(jìn)行全文檢索(二)---得到有效的內(nèi)容http://www.tkk7.com/scud/archive/2005/08/12/9980.htmlScud(飛云小俠)Scud(飛云小俠)Fri, 12 Aug 2005 09:33:00 GMThttp://www.tkk7.com/scud/archive/2005/08/12/9980.htmlhttp://www.tkk7.com/scud/comments/9980.htmlhttp://www.tkk7.com/scud/archive/2005/08/12/9980.html#Feedback0http://www.tkk7.com/scud/comments/commentRss/9980.htmlhttp://www.tkk7.com/scud/services/trackbacks/9980.html

scud(飛云小俠) http://www.jscud.com 轉(zhuǎn)載請(qǐng)注明來(lái)源/作者

關(guān)鍵字:lucene,html parser,全文檢索,IndexReader,Document,Field,IndexWriter,Term,HTMLPAGE


  在使用lucene對(duì)相關(guān)內(nèi)容進(jìn)行索引時(shí),會(huì)遇到各種格式的內(nèi)容,例如Html,PDF,Word等等,那么我們?nèi)绾螐倪@么文檔中得到我們需要的內(nèi)容哪?例如Html的內(nèi)容,一般我們不需要對(duì)Html標(biāo)簽建立索引,因?yàn)槟遣皇俏覀冃枰阉鞯膬?nèi)容.這個(gè)時(shí)候,我們就需要從Html內(nèi)容中解析出我們所需要的內(nèi)容.對(duì)于PDF,Word文檔,也是類似的要求.
 
  總之,我們只需要從內(nèi)容中提取出我們需要的文本來(lái)建立索引,這樣用戶就能搜索到需要的內(nèi)容,然后訪問(wèn)對(duì)應(yīng)的資源即可.

  Lucene本身帶的例子中有一個(gè)解析Html的代碼,不過(guò)不是純JAVA的,所以在網(wǎng)上我又找到了另外一個(gè)Html解析器,網(wǎng)址如下:http://htmlparser.sourceforge.net.
 
  對(duì)PDF解析的相關(guān)項(xiàng)目有很多,例如PDFBox.在PDFBox里面提出pdf的文本內(nèi)容只需要一句話即可:  
  
   
Document doc = LucenePDFDocument.getDocument( file );  

  
  當(dāng)然如果需要更高級(jí)的設(shè)置,就要使用PDFBox中PDFTextStripper等類來(lái)實(shí)現(xiàn)更高級(jí)的操作了.
 
 
  對(duì)Word文檔解析的相關(guān)有POI,網(wǎng)址是 http://jakarta.apache.org/poi/.
 
  HtmlParser本身提供的功能很強(qiáng)大,我們下面主要來(lái)關(guān)注我們需要的功能.首先給出幾個(gè)函數(shù)如下:
 

 /**
 * 解析一個(gè)Html頁(yè)面,返回一個(gè)Html頁(yè)面類.
 *
 * @param resource 文件路徑或者網(wǎng)址
 */
    public static SearchHtmlPage parseHtmlPage(String resource)
    {
        String title = "";
        String body = "";
        try
        {
            Parser myParser = new Parser(resource);

            //設(shè)置編碼:根據(jù)實(shí)際情況修改
            myParser.setEncoding("GBK");

            HtmlPage visitor = new HtmlPage(myParser);

            myParser.visitAllNodesWith(visitor);

            title = visitor.getTitle();

            body = combineNodeText(visitor.getBody().toNodeArray());
        }
        catch (ParserException e)
        {
            LogMan.error("Parse Html Page " + resource + " Error!");
        }

        SearchHtmlPage result = new SearchHtmlPage(title, body);

        return result;
    }

    /**
     * 解析Html內(nèi)容,得到普通文本和鏈接的內(nèi)容.
     *
     * @param content 要解析的內(nèi)容
     * @return 返回解析后的內(nèi)容
     */
    public static String parseHtmlContent(String content)
    {
        Parser myParser;
        NodeList nodeList = null;

        myParser = Parser.createParser(content, "GBK");

        NodeFilter textFilter = new NodeClassFilter(TextNode.class);
        NodeFilter linkFilter = new NodeClassFilter(LinkTag.class);

        //暫時(shí)不處理 meta
        //NodeFilter metaFilter = new NodeClassFilter(MetaTag.class);

        OrFilter lastFilter = new OrFilter();
        lastFilter.setPredicates(new NodeFilter[] { textFilter, linkFilter });

        try
        {
            nodeList = myParser.parse(lastFilter);
        }
        catch (ParserException e)
        {
            LogMan.warn("Parse Content Error", e);
        }

        //中場(chǎng)退出了
        if (null == nodeList)
        {
            return "";
        }

        Node[] nodes = nodeList.toNodeArray();

        String result = combineNodeText(nodes);
        return result;
    }

 //合并節(jié)點(diǎn)的有效內(nèi)容
    private static String combineNodeText(Node[] nodes)
    {
        StringBuffer result = new StringBuffer();

        for (int i = 0; i < nodes.length; i++)
        {
            Node anode = (Node) nodes[i];

            String line = "";
            if (anode instanceof TextNode)
            {
                TextNode textnode = (TextNode) anode;
                //line = textnode.toPlainTextString().trim();
                line = textnode.getText();
            }
            else if (anode instanceof LinkTag)
            {
                LinkTag linknode = (LinkTag) anode;

                line = linknode.getLink();
                //過(guò)濾jsp標(biāo)簽
                line = StringFunc.replace(line, "<%.*%>", "");
            }

            if (StringFunc.isTrimEmpty(line)) continue;

            result.append(" ").append(line);
        }

        return result.toString();
    }


  
  其中SearchHtmlPage類是表示一個(gè)Html頁(yè)面的模型,包含標(biāo)題和內(nèi)容,代碼如下:
  
 package com.jscud.www.support.search;
 
 /**
  * 搜索時(shí)解析Html后返回的頁(yè)面模型.
  *
  * @author scud(飛云小俠) http://www.jscud.com
  * 
  */
 public class SearchHtmlPage
 {
     /**標(biāo)題*/
     private String title;
 
     /**內(nèi)容*/
     private String body;
    
     public SearchHtmlPage(String title, String body)
     {
         this.title = title;
         this.body = body;
     }
    
     public String getBody()
     {
         return body;
     }
 
     public void setBody(String body)
     {
         this.body = body;
     }
 
     public String getTitle()
     {
         return title;
     }
 
     public void setTitle(String title)
     {
         this.title = title;
     }
 }
 


 
  當(dāng)然,使用HtmlParser解析Html資源還有很多其他的方法,可以設(shè)置很多的條件來(lái)滿足用戶的解析要求,用戶可以閱讀其他的文章或者HtmlParser的文檔來(lái)了解,在此不多介紹.
 
  下一節(jié)講解如何進(jìn)行搜索.

 



Scud(飛云小俠) 2005-08-12 17:33 發(fā)表評(píng)論
]]>
使用Lucene進(jìn)行全文檢索(一)---處理索引http://www.tkk7.com/scud/archive/2005/08/12/9979.htmlScud(飛云小俠)Scud(飛云小俠)Fri, 12 Aug 2005 09:31:00 GMThttp://www.tkk7.com/scud/archive/2005/08/12/9979.htmlhttp://www.tkk7.com/scud/comments/9979.htmlhttp://www.tkk7.com/scud/archive/2005/08/12/9979.html#Feedback1http://www.tkk7.com/scud/comments/commentRss/9979.htmlhttp://www.tkk7.com/scud/services/trackbacks/9979.htmlscud(飛云小俠) http://www.jscud.com 轉(zhuǎn)載請(qǐng)注明來(lái)源/作者

關(guān)鍵字:lucene,html parser,全文檢索,IndexReader,Document,Field,IndexWriter,Term,HTMLPAGE


 Lucene是一個(gè)全文檢索的引擎,目前有Java和.Net 等幾個(gè)版本.Java版本的網(wǎng)址是http://lucene.apache.org.相關(guān)的一個(gè)項(xiàng)目是車東的WebLucene: http://sourceforge.net/projects/weblucene.

 首先,基于一個(gè)簡(jiǎn)單的新聞系統(tǒng),要想做全文檢索.新聞系統(tǒng)的管理等在這里不在具體提出,下面列出新聞對(duì)象的類:
 
 注:程序用會(huì)到一些工具類,不在此列出,用戶可以自己實(shí)現(xiàn).
 
 

  package com.jscud.website.newsinfo.bean;
  
  
  import java.sql.Timestamp;
  
  import com.jscud.util.DateTime;
  import com.jscud.util.StringFunc;
  import com.jscud.website.newsinfo.NewsConst;
  
  
  /**
   * 一個(gè)新聞.
   *
   * @author scud(飛云小俠) http://www.jscud.com
   * 
   */
  public class NewsItem
  {
  
      private int nid; //新聞編號(hào)
  
      private int cid; //類別編號(hào)
  
      private String title;//標(biāo)題
  
      private int showtype; //內(nèi)容類型:目前支持url和html
  
      private String content;//內(nèi)容
  
      private String url;//對(duì)應(yīng)網(wǎng)址,如果內(nèi)容類型是url的話
  
      private Timestamp addtime; //增加時(shí)間
  
      private int click; //點(diǎn)擊數(shù)
     
      //對(duì)應(yīng)的get,set函數(shù),較多不在列出,可以使用工具生成
      //......
  
     
      /**
       * 按照類型格式化
       */
      public String getShowContent()
      {
          String sRes = content;
          if(showtype == NewsConst.ShowType_HTML)
          {
          }  
          return sRes;
      }
     
      public String getTarget()
      {
          if(showtype == NewsConst.ShowType_URL)
          {
              return "_blank";
          }
          else
              return "";       
      }
     
      /**
       * 靜態(tài)Html文件的路徑及其名字
       */
      public String getHtmlFileName()
      {
          int nYear = DateTime.getYear_Date(getAddtime());
          int nMonth =  DateTime.getMonth_Date(getAddtime());
             
          String sGeneFileName =
             "/news/" + getCid() + "/" + nYear + "/" + nMonth +"/" + getNid() + ".htm";
         
          return sGeneFileName;
      }
     
      /**
       * 靜態(tài)Html文件的路徑
       */
      public String getHtmlFilePath()
      {
          int nYear = DateTime.getYear_Date(getAddtime());
          int nMonth =  DateTime.getMonth_Date(getAddtime());
             
          String sGeneFilePath =
             getCid() + "_" + nYear + "_" + nMonth;
         
          return sGeneFilePath;
      }     
  } 


 
 可以看到,我們需要對(duì)標(biāo)題和內(nèi)容進(jìn)行檢索,為了這個(gè)目的,我們首先需要來(lái)研究一下lucene.
 
 在Lucene中,如果要進(jìn)行全文檢索,必須要先建立索引然后才能進(jìn)行檢索,當(dāng)然實(shí)際工作中還會(huì)有刪除索引和更新索引的工作.
 
 在此之前,介紹一個(gè)最基本的類(摘抄自http://www.tkk7.com/cap/archive/2005/07/17/7849.html):
 
 Analyzer 文件的分析器(聽起來(lái)別扭,還是叫Analyzer好了)的抽象,這個(gè)類用來(lái)處理分詞(對(duì)中文尤其重要,轉(zhuǎn)換大小寫(Computer->computer,實(shí)現(xiàn)查詢大小寫無(wú)關(guān)),轉(zhuǎn)換詞根(computers->computer),消除stop words等,還負(fù)責(zé)把其他格式文檔轉(zhuǎn)換為純文本等.
 
 在lucene中,一般會(huì)使用StandardAnalyzer來(lái)分析內(nèi)容,它支持中文等多字節(jié)語(yǔ)言,當(dāng)然可以自己實(shí)現(xiàn)特殊的解析器.StandardAnalyzer目前對(duì)中文的處理是按照單字來(lái)處理的,這是最簡(jiǎn)單的辦法,但是也有缺點(diǎn),會(huì)組合出一些沒(méi)有意義的結(jié)果來(lái). 
 
 
 首先我們來(lái)了解建立索引,建立索引包含2種情況,一種是給一條新聞建立索引,另外的情況是在開始或者一定的時(shí)間給批量的新聞建立索引,所以為了通用,我們寫一個(gè)通用的建立索引的函數(shù):
 
 (一般一類的索引都放在一個(gè)目錄下,這個(gè)配置可以在函數(shù)中定義,也可以寫在配置文件中,通過(guò)參數(shù)傳遞給函數(shù).)

    /**
     * 生成索引.
     *
     * @param doc 目標(biāo)文檔
     * @param indexDir 索引目錄
     */
    public static void makeIndex(Document doc, String indexDir)
    {
        List aList = new ArrayList();
        aList.add(doc);
        makeIndex(aList, indexDir);
    }
 
    /**
     * 生成索引.
     *
     * @param doc 生成的document.
     * @param indexDir 索引目錄
     */
    public static void makeIndex(List docs, String indexDir)
    {
        if (null == docs)
        {
            return;
        }       
        boolean indexExist = indexExist(indexDir);

        IndexWriter writer = null;
        try
        {
            StandardAnalyzer analyzer = new StandardAnalyzer();
           
            //如果索引存在,就追加.如果不存在,就建立新的索引.lucene要是自動(dòng)判決就好了.
            if(indexExist)
            {
                writer = new IndexWriter(indexDir, analyzer, false);
            }
            else
            {
                writer = new IndexWriter(indexDir, analyzer, true);
            }

            //添加一條文檔
            for (int i = 0; i < docs.size(); i++)
            {
                Document doc = (Document) docs.get(i);
                if (null != doc)
                {
                    writer.addDocument(doc);
                }
            }

            //索引完成后的處理
            writer.optimize();
        }
        catch (IOException e)
        {
            LogMan.warn("Error in Make Index", e);
        }
        finally
        {
            try
            {
                if (null != writer)
                {
                    writer.close();
                }
            }
            catch (IOException e)
            {
                LogMan.warn("Close writer Error");
            }
        }
    }



 可以看到,建立索引用到類是IndexWrite,它可以新建索引或者追加索引,但是需要自己判斷.判斷是通過(guò)IndexReader這個(gè)類來(lái)實(shí)現(xiàn)的,函數(shù)如下:

 

  /**
     * 檢查索引是否存在.
     * @param indexDir
     * @return
     */
    public static boolean indexExist(String indexDir)
    {
        return IndexReader.indexExists(indexDir);
    }
 


 如果每次都是新建索引的話,會(huì)把原來(lái)的記錄刪除,我在使用的時(shí)候一開始就沒(méi)有注意到,后來(lái)觀察了一下索引文件,才發(fā)現(xiàn)這個(gè)問(wèn)題.
 
 
 還可以看到,建立索引是給用戶的Document對(duì)象建立索引,Document表示索引中的一條文檔記錄.那么我們?nèi)绾谓⒁粋€(gè)文檔那?以新聞系統(tǒng)為例,代碼如下:
 

     /**
      * 生成新聞的Document.
      *
      * @param aNews 一條新聞.
      *
      * @return lucene的文檔對(duì)象
      */
     public static Document makeNewsSearchDocument(NewsItem aNews)
     {
         Document doc = new Document();
 
         doc.add(Field.Keyword("nid", String.valueOf(aNews.getNid())));
 
         doc.add(Field.Text("title", aNews.getTitle()));
        
         //對(duì)Html進(jìn)行解析,如果不是html,則不需要解析.或者根據(jù)格式調(diào)用自己的解析方法
         String content = parseHtmlContent(aNews.getContent());
 
         doc.add(Field.UnStored("content", content));
 
         doc.add(Field.Keyword("addtime", aNews.getAddtime()));
 
         //可以加入其他的內(nèi)容:例如新聞的評(píng)論等
         doc.add(Field.UnStored("other", ""));
 
         //訪問(wèn)url
         String newsUrl = "/srun/news/viewhtml/" + aNews.getHtmlFilePath() + "/" + aNews.getNid()
                         + ".htm";
 
         doc.add(Field.UnIndexed("visiturl", newsUrl));
 
         return doc;
     }


 
 通過(guò)上面的代碼,我們把一條新聞轉(zhuǎn)換為lucene的Document對(duì)象,從而進(jìn)行索引工作.在上面的代碼中,我們又引入了lucene中的Field(字段)類.Document文檔就像數(shù)據(jù)庫(kù)中的一條記錄,它有很多字段,每個(gè)字段是一個(gè)Field對(duì)象.
 
 從別的文章摘抄一段關(guān)于Field的說(shuō)明(摘抄自http://www.tkk7.com/cap/archive/2005/07/17/7849.html):
 [quote]
    類型                               Analyzed Indexed Stored 說(shuō)明
    Field.Keyword(String,String/Date)  N Y Y                    這個(gè)Field用來(lái)儲(chǔ)存會(huì)直接用來(lái)檢索的比如(編號(hào),姓名,日期等)
    Field.UnIndexed(String,String)     N N Y                    不會(huì)用來(lái)檢索的信息,但是檢索后需要顯示的,比如,硬件序列號(hào),文檔的url地址
    Field.UnStored(String,String)      Y Y N                    大段文本內(nèi)容,會(huì)用來(lái)檢索,但是檢索后不需要從index中取內(nèi)容,可以根據(jù)url去load真實(shí)的內(nèi)容
    Field.Text(String,String)          Y Y Y                    檢索,獲取都需要的內(nèi)容,直接放index中,不過(guò)這樣會(huì)增大index
    Field.Text(String,Reader)          Y Y N                    如果是一個(gè)Reader, lucene猜測(cè)內(nèi)容比較多,會(huì)采用Unstored的策略.
 [/quote]
 
 我們可以看到新聞的編號(hào)是直接用來(lái)檢索的,所以是Keyword類型的字段,新聞的標(biāo)題是需要檢索和顯示用的,所以是Text類型,而新聞的內(nèi)容因?yàn)槭荋tml格式的,所以在經(jīng)過(guò)解析器的處理用,使用的UnStored的格式,而新聞的時(shí)間是直接用來(lái)檢索的,所以是KeyWord類型.為了在新聞索引后用戶可以訪問(wèn)到完整的新聞頁(yè)面,還設(shè)置了一個(gè)UnIndexed類型的訪問(wèn)地址字段.
 
 (對(duì)Html進(jìn)行解析的處理稍后在進(jìn)行講解)
 
 為一條新聞建立索引需要兩個(gè)步驟:獲取Document,傳給makeIndex函數(shù),代碼如下:

    public static void makeNewsInfoIndex(NewsItem aNews)
    {
        if (null == aNews)
        {
            return;
        }
        makeIndex(makeNewsSearchDocument(aNews),indexDir);
    }  


 

 
 
 建立索引的工作就進(jìn)行完了,只要在增加新聞后調(diào)用 makeNewsInfoIndex(newsitem); 就可以建立索引了.
 
 如果需要?jiǎng)h除新聞,那么也要?jiǎng)h除對(duì)應(yīng)的索引,刪除索引是通過(guò)IndexReader類來(lái)完成的:
 


    /**
     * 刪除索引.
     * @param aTerm 索引刪除條件
     * @param indexDir 索引目錄
     */
    public static void deleteIndex(Term aTerm, String indexDir)
    {
        List aList = new ArrayList();
        aList.add(aTerm);
        deleteIndex(aList, indexDir);
    }

    /**
     * 刪除索引.
     *
     * @param aTerm 索引刪除條件.
     * @param indexDir 索引目錄
     * 
     */
    public static void deleteIndex(List terms, String indexDir)
    {
        if (null == terms)
        {
            return;
        }
       
        if(!indexExist(indexDir)) { return; }

        IndexReader reader = null;
        try
        {
            reader = IndexReader.open(indexDir);
            for (int i = 0; i < terms.size(); i++)
            {
                Term aTerm = (Term) terms.get(i);
                if (null != aTerm)
                {
                    reader.delete(aTerm);
                }
            }
        }
        catch (IOException e)
        {
            LogMan.warn("Error in Delete Index", e);
        }
        finally
        {
            try
            {
                if (null != reader)
                {
                    reader.close();
                }
            }
            catch (IOException e)
            {
                LogMan.warn("Close reader Error");
            }
        }
    } 


 
 刪除索引需要一個(gè)條件,類似數(shù)據(jù)庫(kù)中的字段條件,例如刪除一條新聞的代碼如下:
 

     public static void deleteNewsInfoIndex(int nid)
     {
         Term aTerm = new Term("nid", String.valueOf(nid));
         deleteIndex(aTerm,indexDir);
     }   




 通過(guò)新聞的ID,就可以刪除一條新聞.
 
 如果需要更新新聞,如何更新索引哪? 更新索引需要先刪除索引然后新建索引2個(gè)步驟,其實(shí)就是把上面的代碼組合起來(lái),例如更新一條新聞:

     public static void updateNewsInfoIndex(NewsItem aNews)
     {
         if (null == aNews)
         {
             return;
         }
         deleteNewsInfoIndex(aNews.getNid());
         makeNewsInfoIndex(aNews);
     } 
 



 
 至此,索引的建立更新和刪除就告一段落了.其中批量更新新聞的代碼如下:
 (批量更新應(yīng)該在訪問(wèn)人數(shù)少或者后臺(tái)程序在夜間執(zhí)行)

    public static void makeAllNewsInfoIndex(List newsList)
    {
        List terms = new ArrayList();
        List docs = new ArrayList();

        for (int i = 0; i < newsList.size(); i++)
        {
            NewsItem aitem = (NewsItem) newsList.get(i);
            if (null != aitem)
            {
                terms.add(new Term("nid", String.valueOf(aitem.getNid())));
                docs.add(makeNewsSearchDocument(aitem));
            }
        }

        deleteIndex(terms,indexDir);
        makeIndex(docs,indexDir);
    } 



 
 
 下一節(jié)講解如何對(duì)要建立索引的內(nèi)容進(jìn)行解析,例如解析Html等內(nèi)容.



Scud(飛云小俠) 2005-08-12 17:31 發(fā)表評(píng)論
]]>
分析/解析Html頁(yè)面:HTML Parser的試用 http://www.tkk7.com/scud/archive/2005/08/11/9846.htmlScud(飛云小俠)Scud(飛云小俠)Thu, 11 Aug 2005 14:31:00 GMThttp://www.tkk7.com/scud/archive/2005/08/11/9846.htmlhttp://www.tkk7.com/scud/comments/9846.htmlhttp://www.tkk7.com/scud/archive/2005/08/11/9846.html#Feedback4http://www.tkk7.com/scud/comments/commentRss/9846.htmlhttp://www.tkk7.com/scud/services/trackbacks/9846.html作者:scud(飛云小俠)  http://www.jscud.com  轉(zhuǎn)載請(qǐng)注明作者來(lái)源.否則請(qǐng)勿轉(zhuǎn)載,謝謝.

最近在研究lucene的全文檢索,在很多地方需要解析或者說(shuō)分析Html內(nèi)容或者Html頁(yè)面,Lucene本身的演示程序中也提供了一個(gè)Html Parser,但是不是純Java的解決方案.于是到處搜索,在網(wǎng)上找到了一個(gè)"HTMLParser".

網(wǎng)址是: http://htmlparser.sourceforge.net ,當(dāng)前版本為1.5.

下載下來(lái),試用一番,感覺(jué)不錯(cuò),完全能滿足lucene解析Html的需求.

過(guò)幾天貼出lucene進(jìn)行全文檢索的代碼.(檢索本站的文章等).

試用代碼如下,供大家參考:

package com.jscud.test;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStreamReader;

import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.nodes.TextNode;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;
import org.htmlparser.visitors.HtmlPage;
import org.htmlparser.visitors.TextExtractingVisitor;

import com.jscud.util.LogMan; //一個(gè)日志記錄類

/**
 * 演示了Html Parse的應(yīng)用.
 *
 * @author scud http://www.jscud.com
 */

public class ParseHtmlTest
{

    public static void main(String[] args) throws Exception
    {
        String aFile = "e:/jscud/temp/test.htm";

        String content = readTextFile(aFile, "GBK");

        test1(content);
        System.out.println("====================================");

        test2(content);
        System.out.println("====================================");

        test3(content);
        System.out.println("====================================");

        test4(content);
        System.out.println("====================================");

        test5(aFile);
        System.out.println("====================================");

        //訪問(wèn)外部資源,相對(duì)慢
        test5("        System.out.println("====================================");

    }

    /**
     * 讀取文件的方式來(lái)分析內(nèi)容.
     * filePath也可以是一個(gè)Url.
     *
     * @param resource 文件/Url
     */
    public static void test5(String resource) throws Exception
    {
        Parser myParser = new Parser(resource);

        //設(shè)置編碼
        myParser.setEncoding("GBK");

        HtmlPage visitor = new HtmlPage(myParser);

        myParser.visitAllNodesWith(visitor);

        String textInPage = visitor.getTitle();

        System.out.println(textInPage);
    }

    /**
     * 按頁(yè)面方式處理.對(duì)一個(gè)標(biāo)準(zhǔn)的Html頁(yè)面,推薦使用此種方式.
     */
    public static void test4(String content) throws Exception
    {
        Parser myParser;
        myParser = Parser.createParser(content, "GBK");

        HtmlPage visitor = new HtmlPage(myParser);

        myParser.visitAllNodesWith(visitor);

        String textInPage = visitor.getTitle();

        System.out.println(textInPage);
    }

    /**
     * 利用Visitor模式解析html頁(yè)面.
     *
     * 小優(yōu)點(diǎn):翻譯了<>等符號(hào)
     * 缺點(diǎn):好多空格,無(wú)法提取link
     *  
     */
    public static void test3(String content) throws Exception
    {
        Parser myParser;
        myParser = Parser.createParser(content, "GBK");

        TextExtractingVisitor visitor = new TextExtractingVisitor();

        myParser.visitAllNodesWith(visitor);

        String textInPage = visitor.getExtractedText();

        System.out.println(textInPage);
    }

    /**
     * 得到普通文本和鏈接的內(nèi)容.
     *
     * 使用了過(guò)濾條件.
     */
    public static void test2(String content) throws ParserException
    {
        Parser myParser;
        NodeList nodeList = null;

        myParser = Parser.createParser(content, "GBK");

        NodeFilter textFilter = new NodeClassFilter(TextNode.class);
        NodeFilter linkFilter = new NodeClassFilter(LinkTag.class);

        //暫時(shí)不處理 meta
        //NodeFilter metaFilter = new NodeClassFilter(MetaTag.class);

        OrFilter lastFilter = new OrFilter();
        lastFilter.setPredicates(new NodeFilter[] { textFilter, linkFilter });

        nodeList = myParser.parse(lastFilter);

        Node[] nodes = nodeList.toNodeArray();

        for (int i = 0; i < nodes.length; i++)
        {
            Node anode = (Node) nodes[i];

            String line = "";
            if (anode instanceof TextNode)
            {
                TextNode textnode = (TextNode) anode;
                //line = textnode.toPlainTextString().trim();
                line = textnode.getText();
            }
            else if (anode instanceof LinkTag)
            {
                LinkTag linknode = (LinkTag) anode;

                line = linknode.getLink();
               
//@todo 過(guò)濾jsp標(biāo)簽:可以自己實(shí)現(xiàn)這個(gè)函數(shù)
                //line = StringFunc.replace(line, "<%.*%>", "");
            }

            if (isTrimEmpty(line))
                continue;

            System.out.println(line);
        }
    }

    /**
     * 解析普通文本節(jié)點(diǎn).
     *
     * @param content
     * @throws ParserException
     */
    public static void test1(String content) throws ParserException
    {
        Parser myParser;
        Node[] nodes = null;

        myParser = Parser.createParser(content, null);

        nodes = myParser.extractAllNodesThatAre(TextNode.class); //exception could be thrown here

        for (int i = 0; i < nodes.length; i++)
        {
            TextNode textnode = (TextNode) nodes[i];
            String line = textnode.toPlainTextString().trim();
            if (line.equals(""))
                continue;
            System.out.println(line);
        }

    }

    /**
     * 讀取一個(gè)文件到字符串里.
     *
     * @param sFileName  文件名
     * @param sEncode   String
     * @return 文件內(nèi)容
     */
    public static String readTextFile(String sFileName, String sEncode)
    {
        StringBuffer sbStr = new StringBuffer();

        try
        {
            File ff = new File(sFileName);
            InputStreamReader read = new InputStreamReader(new FileInputStream(ff),
                    sEncode);
            BufferedReader ins = new BufferedReader(read);

            String dataLine = "";
            while (null != (dataLine = ins.readLine()))
            {
                sbStr.append(dataLine);
                sbStr.append("\r\n");
            }

            ins.close();
        }
        catch (Exception e)
        {
            LogMan.error("read Text File Error", e);
        }

        return sbStr.toString();
    }

    /**
     * 去掉左右空格后字符串是否為空
     * @param astr String
     * @return boolean
     */
    public static boolean isTrimEmpty(String astr)
    {
        if ((null == astr) || (astr.length() == 0))
        {
            return true;
        }
        if (isBlank(astr.trim()))
        {
            return true;
        }
        return false;
    }

    /**
     * 字符串是否為空:null或者長(zhǎng)度為0.
     * @param astr 源字符串.
     * @return boolean
     */
    public static boolean isBlank(String astr)
    {
        if ((null == astr) || (astr.length() == 0))
        {
            return true;
        }
        else
        {
            return false;
        }
    }

}

 




Scud(飛云小俠) 2005-08-11 22:31 發(fā)表評(píng)論
]]>
主站蜘蛛池模板: 亚洲AV无码乱码国产麻豆| 国产精品日本亚洲777| GOGOGO免费观看国语| 日韩电影免费在线| 亚洲精品视频专区| 国内精品99亚洲免费高清| 国产在线观看免费视频播放器| 亚洲第一香蕉视频| a级毛片在线免费观看| 夜色阁亚洲一区二区三区| 国产午夜亚洲精品| 久久九九兔免费精品6| 亚洲精品成人片在线观看精品字幕 | 久久久久高潮毛片免费全部播放 | 亚洲成aⅴ人在线观看| 精品成人免费自拍视频| 亚洲精品国精品久久99热| 亚洲日本一线产区和二线| 国产免费不卡视频| 精品日韩亚洲AV无码一区二区三区 | jlzzjlzz亚洲乱熟在线播放| 亚洲av最新在线观看网址| 国产成人精品久久免费动漫| 久久亚洲一区二区| 在线观看片免费人成视频播放| 亚洲精品tv久久久久久久久久| 亚洲av无码成人精品国产 | 99蜜桃在线观看免费视频网站| 亚洲中文字幕不卡无码| 一区二区三区免费看| 免费99热在线观看| 黄色毛片视频免费| 国产亚洲福利一区二区免费看| 亚洲综合在线一区二区三区| 免费a级毛片无码a∨蜜芽试看| 亚洲明星合成图综合区在线| 中文字幕在线观看免费视频| 亚洲人成网站影音先锋播放| 日本免费人成视频在线观看| 亚洲成熟xxxxx电影| 日韩在线不卡免费视频一区|