Htmlparser 源代码分析
一.根目录下的类
1.Attribute.java
属性类,四个field:mName,mAssignment,mValue,mQuote;
空白标签时:mName=null
除了 ' , " 两引号和自定义参数字符表示的分隔号外,mQuote 的值都以 char 类型的0 字符表示。
其中的getName(StringBuffer buffer)等方法,意思是将所获得的结果存入buffer内。
如果使用setRawValue()方法进行对mQuote,和,mValue赋值的时候,首尾都是双引号或者单引号则将单引号或双引号作为mQuote,字符串的其他部分作为mValue.如果首尾不同时为一种引号则对mQuote用双引号赋值,字符其他部分作为mValue.如果字符串中没有引号,并且所有字符都是由-,_,:,.和字母与数字组成,则mQuote会被用char类型的0赋值。即为空
例如:
"abcdefg" --------------------> mQuote : " mValue: abcdefg
'abcdefg' ----------------------> mQuote: ' mValue: abcdefg
'abcdefg"----------------------> mQuote:" mValue: 'abcdefg"
abc-defg----------------------> mQuote:(空格) mValue: abc-defg
如果字符串中有非首尾的引号或者只有首或者尾的引号,或者有除了-,_,:,.这几个符号以及数字和字母外的其他符号会被补上引号(字符串中没有单引号就补单引号,没有双引号就补双引号,如果都有则补双引号,并且字符串中的双引号被替换为")。
例如:
abc'de"fg---------------------->mQuote: " mValue: abc'de"fg
&abcdefg---------------------> mQuote: " mValue: &abcdefg
%a'bcd"efg--------------------> mQuote: " mValue: %a'bcd"efg
%abcd"efg---------------------> mQuote: ' mValue: %abcd"efg
2.Node.java (interface) extends Cloneable
String toPlainTextString();
String toHtml();
String toHtml(boolean verbatim); //如果verbatim为true相比上面一个会更接近源 page。但是通过这个工具库对这个方法的实现情况来看,以上三个方法完全一致verbatim并不起到任何作用。
void collectInto(NodeList list,NodeFilter filter);
//将这个Node以及它的所有子Node都用filter过滤器过滤后放入list.中
int getStartPosition(); // 获取该node的起始mPosition
void setStartPosition(); //设置
void accept(NodeVisitor visitor);//为这个node添加一个visitor
void setParent();
void setChildren(NodeList children); //还可以通过getLastChildren等等获取第一个或者最后一个child,但是设置就不可以。可以通过getPreviousSibling()这个node前后的兄弟姐妹node。
void doSemanticAction ();//Perform the meaning of this tag.执行这个标签的所表达的意思。执行该node(TagNode)的语义动作。
3.NodeFactory (interface) This interface defines the methods needed to create new nodes.
Text creatStringNode(Page page,int start,int end); //创建textnode
Remark creatRemarkNode(Page page,int start,int end);//创建remarknode
Tag creatTagNode(Page page,int start,int end,Vector attributes);//创建tagnode
Attributes为这个标签的所有属性
4.PrototypicalNodeFactory
这个类实现了NodeFactory接口,具备创建原型node的能力,这个类还有一个Map用来存储注册的各种Tag.
5.Remark(interface)
6.Text(interface)
这个接口比较复杂,内容较多.因为html里面大都是Tag
7.Tag (interface)
这3个接口用来确定3种node的行为特征
8.NodeFilter(interface) extends Serializable,Cloneable
可序列化
唯一一个方法boolean accept(Node node);决定是否保留所给的这个node
即过滤器!
9.Parser implements Serializable,ConnectionMonitor
语义分析核心类,也是这个工具库的核心应用类
二.http目录
1.HttpHeader Utility methods to display HTTP headers.
所有方法都是静态的。
获取要发送请求的header:getRequestHeader(HttpURLConnection connection);static
获取接受到的请求的header getResponseHeader(HttpURLConnection conn);static
三.Lexer目录
1.Page Represents the contents of an HTML page.
用Source作为buffer存储结构用来存储数据
Source 与Reader类似。InputStreamSource 与 InputStreamReader类似。
StringSource 与 StringReader类似。
2.Cursor A bookmark in a page.
implements Serializable,Ordered,Cloneable 接口
总共有2个Field:int mPosition; Page mPage;后者表示所在的页面,前者表示所在该页面中的具体position。Ordered接口排序是通过mPosition大小进行排序。
这个类除了这两个Field的set/get方法外还有以下几个方法,功能如下:
Void advance() ; //mPosition++;向前进一步
Void retreat() ; //mPosition--;后撤一步,当mPosition小于0的时候则令mPosition=0;
Cursor dup() ; //返回Cursor的克隆实例。如果不支持克隆就创建一个新的Cursor实例Field值与源实例相同。
3.PageIndex A sorted array of integers, the positions of the first characters of each line.
这个类的核心字段int[] mIndices;用来存储对应Page的 每行的index 和 该行末尾字符的mPosition的值之间的对应关系
除了一些对这个数组元素的普通操作方法之外还有row();和column();方法用来获取位置具体信息。elementAt(index);能够获取index表示的那一行最后一个字符的mPosition信息。
4.PageAttribute (extends Attribute)
比Attribute多了5个Field,分别为mNameStart,mNameEnd mValueStart mValueEnd;这4个字段作用于自身的Page字段。相对于Attribute类,我们可以通过mNameStart,mNameEnd来获取某个Attribute的name信息,我们可以通过mNameEnd,mValueStart来获取Attribute的Assignment信息,我们还可以通过mValueStart,mValueEnd来获取Attribute的value信息,当然这都是建立在Page存在的基础之上。如果page为null那么自然就无法根据这些字段来获取相应信息了。大体方法与Attribute一致。只不过在内部调用了super()而已。
5.lexer This class parses the HTML stream into nodes (three type of nodes).{Remark,Text,Tag}
四.Util目录
1.NodeIterator
接口,节点迭代器。有2个未实现方法
boolean hasMoreNodes();
Node nextNode();
该迭代器的实现类:IteratorImpl
该迭代器的继承接口:SimpleNodeIterator
2.IteratorImpl
3.ParserFeedback
接口,Parser的反馈机制
Info,error,warning
4.DefaultParserFeedback
ParserFeedback的默认实现类,可序列化。
能表示3种模式,分别为 QUIET,NORMAL,DEBUG
无参数构造器默认构造为NORMAL模型
5.FeedbackManager
DefaultParserFeedback的一个代理
6.Sort
提供快速排序以及2分查找。
7.CharacterReference
实现序列化接口。实现Ordered接口,可用Sort进行排序和查找
8.Translate
Translate numeric character references and character entity references to unicode characters.)
Lookup();2分查找。decode()解码。encode()编码
都为static 方法。
9.NodeList
主要字段nodeData[] ,这个List中Node是存在数组中的
添加node时可以选择add();也可以选择prepend();前者添加在尾部,后者添加在头部。可以获取部分Node:extractAllNodesThatMatch(NodeFilter, boolean);也可以保留一部分Node(源List中删除一些Node):keepAllNodesThatMatch(NodeFilter).
10.NodeTreeWalker
可以将Node集合构建成树形然后通过树形的方法来获取Node
11.ParserUtil
静态实用工具类
1.removeChars(String, char),移除指定字符串中的字符
2.removeEscapeCharacters(String inputString);移除指定字符串中的'\t','\n','\r'字符
3.removeTrailingBlanks(String);移除指定字符串末尾的空白符
4.findTypeInNode(Node, Class);返回指定Node中所有符合Class的子类的数组
5.splitButDigits(String, String);
6.trimButDigits(String, String);除了数字和需要的字符集合以外的字符都清空
7.trimButDigitsBeginEnd(String, String);和上一个差不多,只不过是取出头尾部分
8.splitSpaces(String, String);trimSpaces(String, String);第二个参数是需要删除的而不 是保留的
9.其他的和之前两个差不多,方法里面有But则第二个参数为需要保留的,否则为需 要删除的
10.createParserParsingAnInputString(String);根据字符串返回parser
五.Nodes目录
1.AbstractNode (abstract) implements Node,Serializable
对Node接口中的抽象方法部分进行了简单实现。
除了一下几个:
String toPlainTextString ();
String toHtml (boolean verbatim);
String toString ();
void accept (NodeVisitor visitor);
2.TextNode extends AbstractNode implements Text
对AbstractNode抽象类中的上述没有实现的方法进行了实现,其中toPlainTextString();与toHtml(boolean verbatim)与toHtml();3个方法等价。Verbatim
不起作用
主要方法:setText();getText();accept();
3.RemarkNode extends AbstractNode implements Remark
继承了AbstractNode 实现了其中toPlainTextString();方法,但是只是返回一个空字符串;实现了toHtml(boolean verbatim)方法,verbatim仍然不起作用,这个方法返回的是html的注释形式:<!——mText——> 其中mText为这个类的Field
Accept()方法也被实现了,与TextNode实现之前的区别是visitor使用了与Text,Remark对应的不同的方法。
4.TagNode extends AbstractNode implements Tag
Field:
A).final static String[] NONE;
a) //An empty set of tag names.
B).Scanner mScanner;
a) //这个标签的扫描器
C).final static Scanner mDefaultScanner = new TagScanne();
a) //非复合标签的默认扫描器
D).Vector mAttributes;
a) //这个Tag的属性集合
E).static Hashtable breakTags;
a) //Hashtable<K,V>,用来记录标签:
static
{
breakTags = new Hashtable (30);
breakTags.put ("BLOCKQUOTE", Boolean.TRUE);
breakTags.put ("BODY", Boolean.TRUE);
breakTags.put ("BR", Boolean.TRUE);
breakTags.put ("CENTER", Boolean.TRUE);
breakTags.put ("DD", Boolean.TRUE);
breakTags.put ("DIR", Boolean.TRUE);
breakTags.put ("DIV", Boolean.TRUE);
breakTags.put ("DL", Boolean.TRUE);
breakTags.put ("DT", Boolean.TRUE);
breakTags.put ("FORM", Boolean.TRUE);
breakTags.put ("H1", Boolean.TRUE);
breakTags.put ("H2", Boolean.TRUE);
breakTags.put ("H3", Boolean.TRUE);
breakTags.put ("H4", Boolean.TRUE);
breakTags.put ("H5", Boolean.TRUE);
breakTags.put ("H6", Boolean.TRUE);
breakTags.put ("HEAD", Boolean.TRUE);
breakTags.put ("HR", Boolean.TRUE);
breakTags.put ("HTML", Boolean.TRUE);
breakTags.put ("ISINDEX", Boolean.TRUE);
breakTags.put ("LI", Boolean.TRUE);
breakTags.put ("MENU", Boolean.TRUE);
breakTags.put ("NOFRAMES", Boolean.TRUE);
breakTags.put ("OL", Boolean.TRUE);
breakTags.put ("P", Boolean.TRUE);
breakTags.put ("PRE", Boolean.TRUE);
breakTags.put ("TD", Boolean.TRUE);
breakTags.put ("TH", Boolean.TRUE);
breakTags.put ("TITLE", Boolean.TRUE);
breakTags.put ("UL", Boolean.TRUE);
}
toPlainTextString();方法返回的是空字符串,和RemarkNode一样。toHtml()
中的参数也和RemarkNode一样不起作用。这里有几个方法是需要注意区分
getAttribute (String name);//通过属性名获取这个属性的值。
getAttributeEx (String name)//通过属性名获取整个属性对象Attribute
getAttributesEx();//获取所有属性对象Attributes,返回值是Vector
------------------------------------------------------------------------------------------
String[] getIds ();
String[] getEnders ();
String[] getEndTagEnders ();
3者一致,返回的都是NONE字段,以后具体Tag类型的继承TagNode的时候会用各自的方法把它们覆盖掉。
六.Tags目录
1.CompositeTag extends TagNode
The base class for tags that have an end tag.
这个类囊括了Tag标签的几乎所有操作。除了一般的获取孩子标签:children();getChild();;getChildrenAsNodeArray();elements();移除孩子标签:removeChild();将所有孩子以字符串形式返回toPlainTextString();或者以字符串形式导入到缓存buffer:putChildrenInto();获取具体位置的子标签Node:childAt();以及将所有孩子标签通过filter过滤器存入NodeList中:collectInto( NodeList, NodeFilter);等等方法外,还有些比较重要的方法:
A).Tag searchByName(String name);
//用来在孩子标签中查找拥有name(这个name是参数)属性的第一个标签。
B).NodeList searchFor(String searchString, boolean caseSensitive, Locale locale);
//在孩子标签中查找包含searchString字符串的Node,并将这些Node都放入NodeList中,然后返回NodeList;
C).int findPositionOf(String text,Locale locale);
//返回在孩子标签中第一个包含text字符串的标签的具体位置(在NodeList中的Index位置,而不是Cursor类中那样的mPosition位置)
D).Text[] digupStringNode(String searchText);
//首先通过searchText找出子标签中包换这个字符串的所有标签。然后再从这些标签中挑出属于Text的节点组成Text[]返回
这个类算是Tags目录中最重要的一个类。所有的复合标签都需要继承这个类。
1.BodyTag ===========>"BODY";//getBody();内部调用额是toPlainTextString();
2.Bullet==============>"LI"
3.BulletList===========>"UL","OL"
4.Div===============>"DIV"
5.HeadingTag=========>"H1","H2","H3","H4","H5","H6"
6.HeadTag===========>"HEAD"
7.Html==============>"HTML"
8.InputTag===========>"INPUT"
9.JspTag============>"%","%=","%@"
10.LabelTag===========>"LABEL"
11.ParagraphTag========>"P"
12.ProcessingInstructionTag==>"?"
13.SelectTag===========>"SELECT"
14.Span===============>"SPAN"
15.StyleTag============>"STYLE"
16.TableColumn=========>"TD"
17.TableHeader==========>"TH"
18.TableRow============>"TR"
19.TableTag===============>"TABLE"
20.TextAreaTag============>"TEXTAREA"
21.TitleTag================>"TITLE"
22.DoctypeTag=============>"!DOCTYPE"
23.DefinitionListBullet========>"DD","DT"
24.DefinitionList=============>"DL"
以上的24个标签都相对比较简单。内部有2个或者3个字段,之中一个String[] ids就是箭头右边的那个字符串。另外一个或者2个字段是终结各自的终结符。
----------------------------------------------------------------------------------------------------
1.BaseHrefTag "BASE";
//setBaseUrl();getBaseUrl();对href属性取赋值
//对doSemanticAction()的实现也是如此:page.setBaseUrl(getBaseUrl());
2.OptionTag "OPTION"
//setValue();getValue();对value属性取赋值
//getOptionText();通过调用toPlainTextString()实现
3.FrameTag "FRAME"
//setFrameLocation();getFrameLocation();对src属性取赋值
4.FormTag "FORM"
//有POST,GET两静态字段来表示FORM传递数据的方式
//getFormInputs();抓取子标签中的所有InputTag并打包以NodeList返回。
//getFormTextareas();抓取子标签中的所有TextAreaTag并打包以NodeList返回。
//getFormMethod();对method属性取值
//getFormName();对name属性取值
//setFormLocation();getFormLocation();extractFormLocn()对action属性取赋值
//getInputTag(String name);找出name属性为提供参数的InputTag.
5.ImageTag "IMG"
//字段imageUrl表示String类型的image地址
//extractImageLocn();获取相对/绝对地址SRC的属性取值
//getImageUrl();获取绝对地址SRC的属性取值
//setImageUrl();设置绝对地址SRC的属性赋值
6.FrameSetTag "FRAMESET"
//getFrames(),setFrames();对该标签的孩子标签取赋值
//getFrame(String name,Locale locale);通过名字从Tag孩子中找出符合要求的//FrameTag
7.MetaTag "META"
//setHttpEquiv();getHttpEquiv();对HTTP-EQUIV属性的取赋值
//setMetaTagContents();getMetaContent();对CONTENT属性的取赋值
//setMetaTagName();getMetaTagName();对NAME属性的取赋值
//doSemanticAction();的实现:(设置了一下编码)
//if ("Content-Type".equalsIgnoreCase (httpEquiv)){
// charset = getPage ().getCharset (getAttribute ("CONTENT"));
// getPage ().setEncoding (charset);
//}
8.ScriptTag "SCRIPT"
//字段mCode表示Script的编码
//getLanguage();setLanguage();对LANGUAGE属性的取赋值
//setType();getType();对TYPE属性的取赋值
//putChildrenInto(StringBuffer sb,boolean verbatim);把所有孩子节点都存入sb中.
9.LinkTag "A"
//字段mLink;表示这个link的URL值
//字段mailLink,如果为true,则表示这个link为邮件地址
//字段javascriptLink,如果为true,则表示这个link为javascript文件地址
//getAccessKeyt();对ACCESSKEY属性的取值
//extractLink();获取URL值
//getLink();获取URL值,与上一个方法的区别是这个值将会把"mailto:","javascript:"
//去掉。并且对mailLink或者javascriptLink字段进行设置。setLink();对href赋值
//getLinkText();如果标签有孩子,就会返回所有孩子的字符串形式。
//isFTPLink();isIRCLink();isHTTPLink();isHTTPSLink();isHTTPLikeLink();按字面意//思理解实现的话都是通过字符串匹配实现的。
//其中isHTTPSLikeLink()=isHTTPSLink()||isHTTPLink();
10.AppletTag "APPLET"
//Hashtable createAppletParamsTable ();param标签的name属性和value属性
//setAppletClass();getAppletClass();对CODE属性取赋值
//setArchive();getArchive();对ARCHIVE属性取赋值
//setCodeBase();getCodeBase();对CODEBASE属性取赋值
11.ObjectTag"OBJECT"
//setObjectClassId();getObjectClassId();对CLASSID属性的取赋值
//setObjectCodeBase();getObjectCodeBase();对CODEBASE属性的取赋值
//setObjectCodeType();getObjectCodeType();对CODETYPE属性的取赋值
//setObjectData();getObjectData();对DATA属性的取赋值
//setObjectHeight();getObjectHeight();对HEIGHT属性的取赋值
//setObjectStandby();getObjectStandby();对STANDBY属性的取赋值
//setObjectType();getObjectType();对TYPE属性的取赋值
//setObjectWidth();getObjectWidth();对WIDTH属性的取赋值
//setObjectParams();设置对象属性;
七.filters目录
这个目录中的类都实现了NodeFilter接口。这个接口只有一个方法accept(Node node);
1.IsEqualFilter This class accepts only one specific node.
boolean accept(Node node);如果相等返回true,不相等返回false
2.AndFilter Accepts nodes matching all of its predicate filters (AND operation).
//字段mPredicates存放被用于过滤的所有过滤器,这个类其实就是多个过滤
//器的集合,只不过通过它需要通过所有mPredicates存放的过滤器而已。
//当然他提供了相应的方法来获取和设置存储的过滤器
3.OrFilter Accepts nodes matching any of its predicates filters (OR operation).
//与AndFilter过滤器基本一致。只是accept()的实现中把false改成了true。功能显 //而易见
4.NotFilter Accepts all nodes not acceptable to it's predicate filter.
//字段mPredicate 存放过滤器
//accept();实现return ((null != mPredicate) && !mPredicate.accept (node));
5.XorFilter
//和or基本一致,只是or是只需在所有filter里面有一个匹配就行,而xor则是需//要奇数个匹配。
6.HasChildFilter //这个Node的孩子能够通过指定Filter
7.HasParentFilter //这个Node的父亲能够通过指定Filter
8.HasSiblingFilter //这个Node的兄弟能够通过指定Filter
9.HasAttributeFilter //这个Node需要有指定的Attribute包括name,value
10.NodeClassFilter
//这个Node需要与指定class相关,就是说class可能是这个Node的父类//或者父接口的class,或者是这个类本身的class
11.TagNameFilter
//这个Node只有是TagNode,并且不是EndTag,并且是指定名字的才能通过
12.LinkStringFilter
//这个Node只有是LinkTag或者继承LinkTag的类,并且URL中需要包含指定字 //符串才能通过,可以设定大小写敏感
13.LinkRegexFilter
//有个Pattern mRegex字段,存放需要匹配的Pattern
//这个Node只有是LinkTag或者继承LinkTag的类,并且URL必须与给定的Pattern //匹配才能通过(部分匹配,使用的是Matcher的find()方法)。可以设置大小写敏感
14.StringFilter
//这个Node只有是Text,并且内容必须包含指定字符串才能通过,可以设置大小 //写敏感
15.RegexFilter
//有3中策略MATCH,LOOKINGAT,FIND.分别代表Matcher类的3个方法
//Matcher.matches();匹配整个字符串
//Matcher.lookingAt();从头开始匹配,如果匹配则true,不用扫描整个字符串
//Matcher.find();只要有子序列匹配返回true
16.CssSelectorNodeFilter
//css选择器过滤器比较复杂,用到的时候再看。
//原创地址:http://hi.csdn.net/space-8079523.html;转载请注明出处,蛰伏神兽
八.visitors 这些visitor意思就是在给定的字符序列或者数组中查找需要的内容并且 记录找到的个数
1.NodeVisitor
//这个包的基础Visitor定义visitor的基本动作:
//void beginParsing ()
//void visitTag (Tag tag)
//void visitEndTag (Tag tag)
//void visitStringNode (Text string)
//void visitRemarkNode (Remark remark)
//void finishedParsing ()
//以及两个递归的执行与否
2.TagFindingVisitor
//一个参数的构造器默认不检查结束标签(endTag)
//在传入的一个待查找TagName数组中找出指定Tag以及这个Tag的个数(指定后//endTag也可以查)
3.StringFindingVisitor
//Field:
//String stringToFind;
//boolean multipleSearchesWithinStrings;
//visitorStringNode(Text stringNode);
//在TextNode的text中查找stringToFind的个数
//如果multipleSearchesWithinStrings字段为false那么一次只能查到一个,查到后立//即返回了.如果为True那么一次visitor就能把text包含的stringToFind都招出来例//如:stringToFind=aaa;
Text=aaaaaaaaa;
那么能找到3个。(注意不是7个)
4.ObjectFindVisitor
//查找与指定class一直的tag对象;一次比较一个tag对象
5.LinkFindVisitor
//和StringFindVisitor差不多只不过只能访问Tag对象
6.TextExtractingVisitor
//在Text中提取text内容
7.UrlModifyingVisitor
//给相应Node添加url前缀。
8.HtmlPage
//
九.scanner目录
1.Scanner (interface)
public Tag scan (Tag tag, Lexer lexer, NodeList stack) throws ParserException;
2.TagScanner
//scan的实现:
//tag.doSemanticAction();
//return tag;
3.JspScanner (extends) TagScanner
//比前者多了一个无参数构造器
4.StyleScanner
//
5.ScriptDecoder
//为script解码
因为小弟是初次使用htmlparser所有职能简单的分析源代码,也没有什么创新的见解。权当备案,以后用多了在来补充编辑。大家勿喷