Libxml 函数和常量与 SimpleXML、XSLT 以及 DOM 函数一起使用。
Libxml 是PHP处理XML文档的核心库,它提供了:
Libxml是PHP中处理XML的基础库,大多数XML相关扩展(DOM、SimpleXML、XSLT)都依赖于它。了解Libxml函数可以帮助您更好地调试和处理XML解析问题。
这些函数需要 Libxml 程序包。 在 xmlsoft.org 下载
大多数PHP安装默认包含Libxml支持。您可以通过以下方式检查:
// 检查Libxml扩展是否可用
if (extension_loaded('libxml')) {
echo 'Libxml 扩展已启用';
} else {
echo 'Libxml 扩展未启用';
}
// 获取Libxml版本
echo "Libxml 版本: " . LIBXML_VERSION . "\n";
echo "Libxml 点号版本: " . LIBXML_DOTTED_VERSION . "\n";
// 检查常用功能
if (defined('LIBXML_ERR_ERROR')) {
echo "Libxml 错误处理功能可用\n";
}
| 函数 | 描述 | 版本 |
|---|---|---|
| libxml_clear_errors() | 清空 Libxml 错误缓冲。 | PHP 5+ |
| libxml_get_errors() | 检索错误数组。 | PHP 5+ |
| libxml_get_last_error() | 从 Libxml 检索最后的错误。 | PHP 5+ |
| libxml_set_streams_context() | 为下一次 Libxml 文档加载或写入设置流环境。 | PHP 5+ |
| libxml_use_internal_errors() | 禁用 Libxml 错误,允许用户按需读取错误信息。 | PHP 5+ |
| libxml_set_external_entity_loader() | 设置外部实体加载器。 | PHP 5.4+ |
| libxml_disable_entity_loader() | 禁用加载外部实体,提高安全性。 | PHP 8.0+ |
| 常量 | 描述 | 版本 |
|---|---|---|
| 解析选项 (Parsing Options) | ||
| LIBXML_COMPACT | 设置小型节点分配优化。会改善应用程序的性能。 | PHP 5+ |
| LIBXML_DTDATTR | 设置默认 DTD 属性。 | PHP 5+ |
| LIBXML_DTDLOAD | 加载外部子集。 | PHP 5+ |
| LIBXML_DTDVALID | 通过 DTD 进行验证。 | PHP 5+ |
| LIBXML_NOBLANKS | 删除空节点。 | PHP 5+ |
| LIBXML_NOCDATA | 把 CDATA 设置为文本节点。 | PHP 5+ |
| LIBXML_NOEMPTYTAG | 更改空标签(比如 <br/> 改为 <br></br>)。仅在 DOMDocument->save() 和 DOMDocument->saveXML() 函数中可用。 | PHP 5+ |
| LIBXML_NOENT | 替代实体。 | PHP 5+ |
| LIBXML_NOERROR | 不显示错误报告。 | PHP 5+ |
| LIBXML_NONET | 在加载文档时停止网络访问。 | PHP 5+ |
| LIBXML_NOWARNING | 不显示警告报告。 | PHP 5+ |
| LIBXML_NOXMLDECL | 在保存文档时,撤销 XML 声明。 | PHP 5+ |
| LIBXML_NSCLEAN | 删除额外的命名空间声明。 | PHP 5+ |
| LIBXML_XINCLUDE | 使用 XInclude 置换。 | PHP 5+ |
| LIBXML_PARSEHUGE | 设置XML解析不限制文档大小和深度。 | PHP 5.3.2+ |
| LIBXML_BIGLINES | 在错误报告中存储行号(大文件性能更好)。 | PHP 5.3.2+ |
| 错误级别 (Error Levels) | ||
| LIBXML_ERR_NONE | 获得无错误。 | PHP 5+ |
| LIBXML_ERR_WARNING | 获得简单警告。 | PHP 5+ |
| LIBXML_ERR_ERROR | 获得可恢复的错误。 | PHP 5+ |
| LIBXML_ERR_FATAL | 获得致命的错误。 | PHP 5+ |
| 版本信息 (Version Information) | ||
| LIBXML_VERSION | 获得 Libxml 版本(例如:20605 或 20617)。 | PHP 5+ |
| LIBXML_DOTTED_VERSION | 获得有点号的 Libxml 版本(例如:2.6.5 或 2.6.17)。 | PHP 5+ |
// 启用内部错误处理(不显示错误,而是捕获它们)
libxml_use_internal_errors(true);
// 尝试解析无效的XML
$xml = '<root><item>Test<item></root>'; // 缺少关闭标签
$doc = simplexml_load_string($xml);
if ($doc === false) {
echo "XML解析失败!\n";
// 获取所有错误
$errors = libxml_get_errors();
foreach ($errors as $error) {
echo "错误: ";
switch ($error->level) {
case LIBXML_ERR_WARNING:
echo "警告 " . $error->code;
break;
case LIBXML_ERR_ERROR:
echo "错误 " . $error->code;
break;
case LIBXML_ERR_FATAL:
echo "致命错误 " . $error->code;
break;
}
echo ": " . trim($error->message) . "\n";
echo " 行: " . $error->line . ", 列: " . $error->column . "\n";
}
// 清除错误缓冲
libxml_clear_errors();
} else {
echo "XML解析成功!\n";
}
// 获取最后一个错误
$lastError = libxml_get_last_error();
if ($lastError) {
echo "最后一个错误: " . $lastError->message . "\n";
}
// 启用内部错误处理
libxml_use_internal_errors(true);
// 使用DOMDocument加载XML并使用解析选项
$xml = '<root>
<item>Test 1</item>
<item><![CDATA[Test 2]]></item>
<empty/>
<item>Test 3</item>
</root>';
$dom = new DOMDocument();
// 设置多个解析选项
$options = LIBXML_NOBLANKS | LIBXML_NOCDATA | LIBXML_COMPACT;
$dom->loadXML($xml, $options);
// 保存时使用选项
$dom->formatOutput = true;
$xmlOutput = $dom->saveXML();
echo "处理后的XML:\n";
echo htmlspecialchars($xmlOutput) . "\n";
// 验证DTD
$xmlWithDTD = '<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to,from,heading,body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>John</to>
<from>Jane</from>
<heading>Reminder</heading>
<body>Don\'t forget the meeting!</body>
</note>';
$dom2 = new DOMDocument();
if ($dom2->loadXML($xmlWithDTD, LIBXML_DTDVALID)) {
echo "XML通过DTD验证\n";
} else {
echo "XML验证失败\n";
$errors = libxml_get_errors();
foreach ($errors as $error) {
echo "验证错误: " . $error->message . "\n";
}
libxml_clear_errors();
}
// 设置流上下文
$opts = [
'http' => [
'method' => 'GET',
'header' => 'User-Agent: MyXMLParser/1.0\r\n',
'timeout' => 30
]
];
$context = stream_context_create($opts);
// 设置流上下文供libxml使用
libxml_set_streams_context($context);
// 现在加载远程XML时会使用上面的上下文设置
libxml_use_internal_errors(true);
// 尝试加载远程XML(需要allow_url_fopen开启)
// $xml = file_get_contents('http://example.com/data.xml');
// $doc = simplexml_load_string($xml);
// 禁用外部实体加载器以提高安全性(防止XXE攻击)
if (function_exists('libxml_disable_entity_loader')) {
$oldValue = libxml_disable_entity_loader(true);
}
// 或者设置自定义外部实体加载器
if (function_exists('libxml_set_external_entity_loader')) {
libxml_set_external_entity_loader(function($public, $system, $context) {
// 记录或阻止外部实体加载
error_log("尝试加载外部实体: Public=$public, System=$system");
return null; // 返回null阻止加载
});
}
// 解析可能包含外部实体的XML
$xmlWithEntity = '<?xml version="1.0"?>
<!DOCTYPE test [
<!ENTITY xxe SYSTEM "file:///etc/passwd">
]>
<root>
<data>&xxe;</data>
</root>';
$dom = new DOMDocument();
if ($dom->loadXML($xmlWithEntity, LIBXML_NOENT | LIBXML_DTDLOAD)) {
echo "XML加载成功(但外部实体已被阻止)\n";
} else {
echo "XML加载失败\n";
}
// 恢复外部实体加载器
if (function_exists('libxml_disable_entity_loader') && isset($oldValue)) {
libxml_disable_entity_loader($oldValue);
}
// Libxml与SimpleXML集成
libxml_use_internal_errors(true);
$xml = '<books>
<book>
<title>PHP入门</title>
<author>张三</author>
<price>49.99</price>
</book>
<book>
<title>XML解析指南</title>
<author>李四</author>
<price>59.99</price>
</book>
</books>';
$books = simplexml_load_string($xml);
if ($books === false) {
$errors = libxml_get_errors();
foreach ($errors as $error) {
echo "SimpleXML错误: " . $error->message . "\n";
}
libxml_clear_errors();
} else {
echo "使用SimpleXML成功解析XML\n";
foreach ($books->book as $book) {
echo "书名: " . $book->title . ", 作者: " . $book->author . "\n";
}
}
// Libxml与DOM扩展集成
$dom = new DOMDocument();
libxml_use_internal_errors(true);
if ($dom->loadXML($xml, LIBXML_NOBLANKS)) {
echo "使用DOMDocument成功解析XML\n";
$xpath = new DOMXPath($dom);
$titles = $xpath->query('//book/title');
echo "找到 " . $titles->length . " 本书:\n";
foreach ($titles as $title) {
echo " - " . $title->nodeValue . "\n";
}
} else {
$errors = libxml_get_errors();
foreach ($errors as $error) {
echo "DOM错误: " . $error->message . "\n";
}
libxml_clear_errors();
}
// Libxml与XSLT扩展集成(如果可用)
if (extension_loaded('xsl')) {
$xsl = '<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html><body>
<h1>图书列表</h1>
<xsl:for-each select="books/book">
<div>
<h2><xsl:value-of select="title"/></h2>
<p>作者: <xsl:value-of select="author"/></p>
<p>价格: <xsl:value-of select="price"/></p>
</div>
</xsl:for-each>
</body></html>
</xsl:template>
</xsl:stylesheet>';
$xslDoc = new DOMDocument();
$xslDoc->loadXML($xsl);
$xslt = new XSLTProcessor();
$xslt->importStylesheet($xslDoc);
$result = $xslt->transformToXml($dom);
if ($result) {
echo "XSLT转换成功\n";
// echo $result;
}
}
libxml_use_internal_errors(true)以控制错误处理libxml_get_errors()获取详细信息libxml_clear_errors()清理错误缓冲,避免错误累积libxml_disable_entity_loader(true)或设置自定义实体加载器