PHP XML
Expat (SAX) parser functions and error handling.
Key PointsWhen `xml_parse` returns `false`, check `xml_get_error_code`.
Functions
| Function | Purpose |
|---|---|
| xml_parser_create | 创建解析器(指定输出编码) |
| xml_parser_free | 释放解析器 |
| xml_parse | 喂数据(第三参数标最后一块) |
| xml_parse_into_struct | 一次解析成数组 |
| xml_set_element_handler | 开始/结束标签回调 |
| xml_set_character_data_handler | 文本回调 |
| xml_set_default_handler | 默认回调(注释、CDATA 等) |
| xml_get_error_code | 错误码 |
| xml_error_string | 错误描述 |
| xml_get_current_line_number | 出错行号 |
| xml_parser_set_option | 设置选项(大小写折叠等) |
Parse into an array
PHP
<?php
$xml = '<r><a id="1">x</a><b>y</b></r>';
$p = xml_parser_create("UTF-8");
xml_parse_into_struct($p, $xml, $vals, $index);
xml_parser_free($p);
print_r($vals[1]);
echo $index["A"][0], "\n";Output
Array
(
[tag] => A
[attributes] => Array
(
[ID] => 1
)
[type] => complete
[level] => 2
[value] => x
)
1$vals is a flat event list and $index maps tag names to positions. It saves writing callbacks for simple XML.
Locating errors
PHP
<?php
$xml = "<r>\n <a>1</a>\n <b>2</c>\n</r>";
$p = xml_parser_create("UTF-8");
$ok = xml_parse($p, $xml, true);
if (!$ok) {
echo "错误码: " . xml_get_error_code($p) . "\n";
echo "描述: " . xml_error_string(xml_get_error_code($p)) . "\n";
echo "行号: " . xml_get_current_line_number($p) . "\n";
echo "列号: " . xml_get_current_column_number($p) . "\n";
}
xml_parser_free($p);Output
错误码: 76
描述: Mismatched tag
行号: 3
列号: 11Codes come from libxml and should not be hardcoded — they can change between versions. Use
xml_error_string() or just the boolean.Options
PHP
<?php
$xml = '<Root><Item id="1">A</Item></Root>';
$p = xml_parser_create("UTF-8");
xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($p, XML_OPTION_TARGET_ENCODING, "UTF-8");
xml_set_element_handler(
$p,
function ($p, $name, $attrs) {
echo "标签: $name\n";
},
function ($p, $name) {}
);
xml_parse($p, $xml, true);
xml_parser_free($p);Output
标签: Root
标签: ItemSAX or DOM
| Need | SAX | DOM |
|---|---|---|
| 内存恒定 | 是 | 否 |
| 随机访问节点 | 否 | 是 |
| 修改文档 | 困难 | 容易 |
| 代码复杂度 | 高 | 低 |
| 大文件 | 适合 | 不适合 |
SAX code is typically 3× longer than DOM and its state handling is error-prone. Only worth it when the file is too big for DOM.
函数
| 函数 | 作用 |
|---|---|
| xml_parser_create | 创建解析器(指定输出编码) |
| xml_parser_free | 释放解析器 |
| xml_parse | 喂数据(第三参数标最后一块) |
| xml_parse_into_struct | 一次解析成数组 |
| xml_set_element_handler | 开始/结束标签回调 |
| xml_set_character_data_handler | 文本回调 |
| xml_set_default_handler | 默认回调(注释、CDATA 等) |
| xml_get_error_code | 错误码 |
| xml_error_string | 错误描述 |
| xml_get_current_line_number | 出错行号 |
| xml_parser_set_option | 设置选项(大小写折叠等) |
解析成数组
PHP
<?php
$xml = '<r><a id="1">x</a><b>y</b></r>';
$p = xml_parser_create("UTF-8");
xml_parse_into_struct($p, $xml, $vals, $index);
xml_parser_free($p);
print_r($vals[1]);
echo $index["A"][0], "\n";Output
Array
(
[tag] => A
[attributes] => Array
(
[ID] => 1
)
[type] => complete
[level] => 2
[value] => x
)
1$vals 是扁平的事件列表,$index 是「标签名 → 位置数组」的索引。这个函数省去了写回调,适合结构简单的 XML。
错误定位
PHP
<?php
$xml = "<r>\n <a>1</a>\n <b>2</c>\n</r>";
$p = xml_parser_create("UTF-8");
$ok = xml_parse($p, $xml, true);
if (!$ok) {
echo "错误码: " . xml_get_error_code($p) . "\n";
echo "描述: " . xml_error_string(xml_get_error_code($p)) . "\n";
echo "行号: " . xml_get_current_line_number($p) . "\n";
echo "列号: " . xml_get_current_column_number($p) . "\n";
}
xml_parser_free($p);Output
错误码: 76
描述: Mismatched tag
行号: 3
列号: 11错误码是 libxml 的编号,不要硬编码判断具体数字——不同版本可能变化。用
xml_error_string() 拿到描述,或者只判断 xml_parse 的布尔结果。选项
PHP
<?php
$xml = '<Root><Item id="1">A</Item></Root>';
$p = xml_parser_create("UTF-8");
xml_parser_set_option($p, XML_OPTION_CASE_FOLDING, 0);
xml_parser_set_option($p, XML_OPTION_TARGET_ENCODING, "UTF-8");
xml_set_element_handler(
$p,
function ($p, $name, $attrs) {
echo "标签: $name\n";
},
function ($p, $name) {}
);
xml_parse($p, $xml, true);
xml_parser_free($p);Output
标签: Root
标签: ItemSAX 与 DOM 的选择
| 需求 | SAX | DOM |
|---|---|---|
| 内存恒定 | 是 | 否 |
| 随机访问节点 | 否 | 是 |
| 修改文档 | 困难 | 容易 |
| 代码复杂度 | 高 | 低 |
| 大文件 | 适合 | 不适合 |
SAX 的代码量通常是 DOM 的 3 倍以上,而且状态管理容易出错。只有文件大到 DOM 装不下时才值得用 SAX。