PS:一说到DOM,我第一印象就是js处理html的节点数据.最近在编写采集程序的时候,同事向我推荐从属于PHP5内核的的DOM扩展解析html,经过四天查找php手册和文档了解使用DOM扩展完成采集程序后,对待采集我思路开阔了好多,以后不用再为写麻烦的正则解析表达式而烦恼了,DOM扩展能解决所有问题!而且速度也快了好多!下面就把总结的一些知识分享保留下来
-
XML介绍
-
XML文档实例分析 :xmldata.xml
<?xml version="1.0" encoding="UTF-8" ?>
bookTitle1 author1 bookTitle2 author2 -
XML文档-XML声明
XML声明一般是XML文档的第一行
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
XML声明由以下几个部分组成:
version – -文档符合XML1.0规范,现在只有1.0
encoding – -文档字符编码,默认为”UTF-8″
standalone – -文档定义是否在一个文件内
standalone=”yes”
standalone=”no” -
XML文档-根元素
每个XML文档必须有且只有一个根元素
根元素是一个完全包括文档中其他所有元素的元素
根元素的起始标记要放在所有其他元素的起始标记之前
根元素的结束标记要放在所有其他元素的结束标记之后 -
XML文档-标记 AND 属性
<title id="1">bookTitle1</title> 开始标记 文本 结束标记
1.一对标记是一个元素
2.id=”1″作为 title元素的属性=>’id’ 值=>1 -
XML文档-书写XML文件注意事项
1.必须有XML声明语句
<?xml version="1.0" encoding="UTF-8"?>
2.必须有且仅有一个根元素
3.标记大小写敏感,标记成对
4.属性值用引号
5.空标记关闭
6.元素正确嵌套
-
-
DOM 介绍
- DOM是Document Object Model的缩写,即文档对象模型,是W3C组件推荐的处理XML的标准接口,定义了所有文档元素的对象和属性,以及访问它们的方法(接口)。W3C文档对象模型(DOM)定义了访问诸如XML和XHTML文档的标准,是一个使程序和脚本有能力动态地访问和更新文档的内容、结构以及样式的平台和语言中立的接口
-
DOM文档树模型
DOM将一个XML文档以对象树的形式来表示,该对象树包含若干个节点,这些节点之间存在父子关系。每个节点是一个对象,代表XML文档的元素、属性、注释等。每个对象封装了操作DOM树的方法和属性。
DOM规范的核心就是树模型,对于要解析的XML文档,解析器会把XML文档加载到内存中,在内存中为XML文件建立逻辑形式的树。从本质上说,DOM就是XML文档的一个结构化的视图,它将一个XML文档看作是一棵节点树,而其中的每一个节点代表一个可以与其进行交互的对象。树的节点是一个个的对象,这样通过操作这棵树和这些对象就可以完成对XML文档的操作,为处理文档的所有方面提供了一个完美的概念性框架。
功能:
1.载入整个XML文档并解析为节点树,以灵活多变的方式处理。
2.遍历节点。
3.获取某子树支下某类型的节点。
4.直接获取指定的节点。 -
理解DOM
节点(Node)
标签(Tag、Mark)
元素(Element)
属性(Attribute)
文本(Text、Cdata )
1.一对严格封闭或一个自封闭的标签对应一个元素。
2.元素、属性和文本均为节点
3.从根元素出发,整个XML形成一个完全由节点组成的树形体系
4.元素节点构成分支,属性和文本节点构成树叶 -
w3s Document 对象参考手册
(*必看*)http://www.w3school.com.cn/xmldom/dom_document.asp
-
PHP 5的DOM解析器
-
DOMNode类
DOMDocument类
DOMNodeList类
DOMElement类
DOMText类
DOMAttr类
在DOM接口规范中,包含有多个接口。其中常用的基本接口有Document接口、Node接口、NodeList接口、Element接口、Text接口、Attr接口等接口。其中,Document接口是对文档进行操作的入口,它是从Node接口继承过来的。Node接口是其他大多数接口的父类,象Documet、Element、Attribute、Text等接口都是从Node接口继承过来的。NodeList接口是一个节点的集合,它包含了某个节点中的所有子节点 -
XML的DOM模型的常用php操作
DOMDocument([string version], [string encoding])
可以使用new关键字初始化一个空的文档对象。如下:
$doc = new DOMDocument('1.0');
#(加载文档前)文档的空格符和制表符操作(false:删除;true:保留) preserveWhiteSpace(bool) #装入XML文档: #filename 本地或远程xml文件 load(string filename [, int options]) #source 仅仅xml字符串 loadXML(string source [, int options]) #输出XML之前,formatOutput属性设置为TRUE,可以美化文档的输出格式,使DOM解析器在文档中增加换行符,并向右缩进 formatOutput(bool) 输出DOMDocument对象内容: #将XML文档输出到浏览器或做为标准标出(注意:也可以输出某个node的节点及其子节点,一般可以通过其打印出节点做测试用) saveXML([DOMNode node [, integer options]]) #输出成本地文件 save(string filename [, integer options])
#load 本地xml文件加载并美化输出浏览器 $doc = new DOMDocument(); $doc->preserveWhiteSpace = TRUE; $doc->load('xmldata.xml'); $doc->formatOutput = TRUE; echo $doc->saveXML(); var_dump($doc);//class DOMDocument#1 (0) { } var_dump($doc->getElementsByTagName('title')); //class DOMNodeList#2 (0) { } /*获取title节点总数*/ print_r($doc->getElementsByTagName('title')->length);//2 /*打印title第一个节点*/(saveXML一大作用) echo $doc->saveXML($doc->getElementsByTagName('title')->item(0)); //
bookTitle1 var_dump($doc->getElementsByTagName('title')->item(0));//class DOMElement#3 (0) { } print_r($doc->getElementsByTagName('title')->item(0)->getAttribute('id'));//1一定好好研究一下上例的返回值,具有借鉴作用奥
#load加载远程xml文件,并带http头信息 $opts = array( 'http' => array( 'user_agent' => 'PHP libxml agent', ) ); $context = stream_context_create($opts); libxml_set_streams_context($context); // request a file through HTTP $doc = DOMDocument::load('http://www.example.com/file.xml'); # #loadXML xml字符串结构 $doc = new DOMDocument(); $doc->loadXML('<root><node/></root>'); echo $doc->saveXML(); # #loadXML xml字符串结构2 $str = <<<XML <?xml version="1.0" encoding="iso-8859-1"?> <!DOCTYPE root [ <!ENTITY nbsp " "> ]> <div>This is a non-breaking space.</div> XML; $dd2 = new DOMDocument(); $dd2->loadXML($str); echo $dd2->saveXML(); # /*案例编码问题:对于loadHTML加载节点中有中文存在的xml或者html字符串, xml或html头部一定要有相应编码类型:例如: <?xml version="1.0" encoding="UTF-8"?> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> */ function loadNprepareHead($content,$encod='') { //设置自动检测字符编码,以encoding_list if (empty($encod)) $encod = mb_detect_encoding($content,"ASCII,UTF-8,ISO-8859-1,windows-1252,iso-8859-15"); $headpos = mb_strpos($content,'<head>'); if ($headpos === FALSE) $headpos= mb_strpos($content,'<HEAD>'); if ($headpos !== FALSE) { $headpos+=6; $content = mb_substr($content,0,$headpos) . '<meta http-equiv="Content-Type" content="text/html; charset='.$encod.'">' .mb_substr($content,$headpos); } return mb_convert_encoding($content, 'UTF-8', $encod); } //test_gb2312.html $myhtml = <<<EOF <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=gb2312"> <title>My Page</title> </head> <body> <p><a href="/mypage1">斤斤计较就世界!</a></p> <p><a href="/mypage2">Another Hello World!</a></p> </body> </html> EOF; $doc = new DOMDocument(); $myhtml = loadNprepareHead($myhtml); $doc->loadHTML($myhtml); print_r($doc->encoding);exit;
-
错误处理机制
//用户错误处理(false开启错误显示,true关闭错误显示) bool libxml_use_internal_errors ([ bool $use_errors = false ] ) //获得错误信息数组 array libxml_get_errors () //清除libxml的错误缓冲 libxml_clear_errors();
注意:libxml_use_internal_errors(true) 关闭错误显示
//开启错误显示//展示错误 libxml_use_internal_errors(false); $doc = new DOMDocument; if (!$doc->load('file.xml')) { foreach (libxml_get_errors() as $error) { echo $error; } libxml_clear_errors(); } #延伸案例:通过php去验证其html的标签的严谨性 libxml_use_internal_errors(true); $doc = new DOMDocument(); $doc->loadHTMLFile('http://www.baidu.com/'); print_r(libxml_get_errors()); libxml_clear_errors();
-
html的DOM模型的常用php操作
#(加载文档前)文档的空格符和制表符操作(false:删除;true:保留) preserveWhiteSpace(bool) #装入XML文档: #filename 本地或远程html文件 loadHTMLFile(string filename) #source 仅仅html字符串 loadHTML(string source ) # #输出html之前,formatOutput属性设置为TRUE,很好的格式化输出缩进 formatOutput(bool) 输出DOMDocument对象内容: #将html文档输出到浏览器或做为标准标出(注意:也可以输出某个node的节点及其子节点) saveHTML ([ DOMNode $node = NULL ] ) #输出成本地文件 saveHTMLFile(string filename)
loadHTML或loadHTMLFile加载文件并在浏览器上显示
$doc = new DOMDocument(); $doc->loadHTML("Test"); //$doc->loadHTMLFile("filename.html"); //$doc->loadHTMLFile("www.baidu.com/filename.html"); echo $doc->saveHTML(); //echo $doc->saveHTMLFile("test4.html")
saveHTML 浏览器输出元素及其子元素信息
$doc = new DOMDocument; $doc->loadHTML('<div><h1>Hello world!</h1></div>'); echo $doc->saveHTML($doc->getElementsByTagName("h1")->item(0)); //<h1>Hello world!</h1>
DOMXPath 采集举例
libxml_use_internal_errors(true) ; $doc = new DOMDocument(); $doc->loadHTMLFile("http://www.youku.com/v_olist/c_97.html"); $doc->preserveWhiteSpace = TRUE; $doc->formatOutput = TRUE; $body = $doc->getElementsByTagName('body')->item(0); $xpath = new DOMXPath($doc); //xpath 获取元素节点 $path = "//ul[@class='p pv']"; $uls = $xpath->query($path,$body); //echo $doc->saveHTML($uls->item(0)); foreach($uls as $ul) { $lis = $ul->getElementsByTagName('li'); foreach($lis as $li) { $as = $li->getElementsByTagName('a'); echo $as ->length.''; } }
注意:即使子标签只有一个,那他也是DOMNodeList对象所以也必须用item(0)下标表示
#saveHTMLFile 保存文件 $doc = new DOMDocument(); $doc->formatOutput = true; $root = $doc->createElement("html"); $root = $doc->appendChild($root); $head = $doc->createElement("head"); $head = $root->appendChild($head); $title = $doc->createElement("title"); $title = $head->appendChild($title); $text = $doc->createTextNode("This is the title你好"); $text = $title->appendChild($text); echo "Wrote: " . $doc->saveHTMLFile("test4.html") . " bytes"; // Wrote: 129 bytes
-
DOMNode类
总结:
参考:
-
PHP5的XML新特性
http://blog.csdn.net/ice_berg16/article/details/52176#t0 http://cn2.php.net/manual/en/domxpath.query.php
-
用 PHP 读取和编写 XML DOM
http://www.ibm.com/developerworks/cn/opensource/os-xmldomphp/ http://www.poluoluo.com/jzxy/201207/169778.html
-
php使用DOM处理xml文档
http://blog.sina.com.cn/s/blog_6066ce530100emr1.html