在PHP中如何解析和处理HTML/XML
技术背景
在PHP开发中,经常需要解析和处理HTML/XML数据。例如,在进行网页数据抓取、数据转换等操作时,都需要对HTML/XML进行解析。PHP提供了多种方式来实现这一需求,不同的方法适用于不同的场景。
实现步骤
原生XML扩展
- DOM:允许通过DOM API操作XML文档,基于libxml,能解析和修改真实世界中的(有缺陷的)HTML,还能进行XPath查询。
1 2 3 4 5
| $dom = new DOMDocument(); @$dom->loadHTML('<html><body><h1>Hello, World!</h1></body></html>'); $h1 = $dom->getElementsByTagName('h1')->item(0); echo $h1->textContent;
|
- XMLReader:是一个XML拉取解析器,基于libxml,像游标一样在文档流上向前移动并在每个节点处停止。
1 2 3 4 5 6 7 8 9
| $reader = new XMLReader(); $reader->open('example.xml'); while ($reader->read()) { if ($reader->nodeType == XMLReader::ELEMENT && $reader->name == 'item') { echo $reader->readInnerXML(); } } $reader->close();
|
- XML Parser:可创建XML解析器并为不同的XML事件定义处理程序,基于libxml,实现了SAX风格的XML推式解析器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| $parser = xml_parser_create(); xml_set_element_handler($parser, "startElement", "endElement"); xml_set_character_data_handler($parser, "characterData"); $xml = '<root><item>Value</item></root>'; xml_parse($parser, $xml); xml_parser_free($parser);
function startElement($parser, $name, $attrs) { echo "Start element: $name\n"; }
function endElement($parser, $name) { echo "End element: $name\n"; }
function characterData($parser, $data) { echo "Character data: $data\n"; }
|
- SimpleXml:当HTML是有效的XHTML时可使用,它能将XML转换为对象,可通过普通属性选择器和数组迭代器进行处理。
1 2 3 4
| $xml = '<root><item>Value</item></root>'; $simpleXml = simplexml_load_string($xml); echo $simpleXml->item;
|
第三方库(基于libxml)
- FluentDom:为PHP中的DOMDocument提供类似jQuery的流畅XML接口,可通过XPath或CSS选择器进行选择。
- HtmlPageDom:使用DOM轻松操作HTML文档的PHP库,依赖于Symfony2组件的DomCrawler。
- phpQuery:基于jQuery JavaScript库的服务器端、可链式调用、由CSS3选择器驱动的DOM API。
- laminas-dom:提供处理DOM文档和结构的工具,提供统一的接口来使用XPath和CSS选择器查询DOM文档。
- fDOMDocument:扩展了标准DOM,在所有错误情况下使用异常而不是PHP警告或通知。
- sabre/xml:包装和扩展了XMLReader和XMLWriter类,创建了一个简单的“xml到对象/数组”映射系统和设计模式。
- FluidXML:用于操作XML的PHP库,具有简洁流畅的API。
第三方库(非基于libxml)
- PHP Simple HTML DOM Parser:用PHP5+编写的HTML DOM解析器,支持无效HTML,可像jQuery一样使用选择器查找标签。但代码库较差,解析速度慢且占用内存多。
1 2 3 4 5 6
| include('simple_html_dom.php'); $html = file_get_html('http://www.example.com/'); foreach ($html->find('img') as $element) { echo $element->src . '<br>'; }
|
- PHP Html Parser:简单灵活的HTML解析器,可使用任何CSS选择器选择标签。但速度较慢,CPU使用率高,且没有清除创建的DOM对象内存的功能。
HTML 5解析
- HTML5DomDocument:扩展了原生DOMDocument库,修复了一些错误并添加了一些新功能。
- HTML5:完全用PHP编写的符合标准的HTML5解析器和编写器,稳定且在许多生产网站中使用。
正则表达式
虽然不推荐,但在某些特定情况下可以使用正则表达式从HTML中提取数据。不过,正则表达式对HTML的匹配通常很脆弱,微小的标记变化可能导致正则表达式失败。
1 2 3 4 5 6
| $html = '<html><body><img src="example.jpg"></body></html>'; preg_match_all('/<img\s+src="([^"]+)"/', $html, $matches); foreach ($matches[1] as $src) { echo $src . '<br>'; }
|
最佳实践
- 优先使用原生XML扩展,因为它们通常更快且能提供更多的控制。
- 当处理有效的XHTML时,可考虑使用SimpleXml。
- 对于需要类似jQuery操作的场景,可选择基于libxml的第三方库,如FluentDom、phpQuery等。
- 尽量避免使用正则表达式解析HTML,除非是非常简单的任务。
常见问题
- 解析有缺陷的HTML:可使用DOM扩展,它能处理一些有缺陷的HTML。也可使用HTML Tidy先清理HTML,将其转换为XHTML后再进行解析。
- 性能问题:使用基于原生扩展的方法和库通常能获得更好的性能。避免使用性能较差的第三方库,如PHP Simple HTML DOM Parser和PHP Html Parser。
- 正则表达式匹配失败:正则表达式对HTML的微小变化很敏感,应谨慎使用。如果必须使用,要确保正则表达式的编写考虑到可能的变化。