当前位置: 首页> 最新文章列表> 如何通过 xml_parse 解析多个根元素的 XML 文件

如何通过 xml_parse 解析多个根元素的 XML 文件

M66 2025-04-28

在 XML 标准中,一个合法的 XML 文档应该只能有一个根元素(Root Element)。但在实际应用场景中,有时候我们会遇到一些“非标准”格式的 XML 文件,比如一个文件中包含多个根元素。这种结构在使用 PHP 的 xml_parse 解析器时会引发问题,因为解析器默认是以标准 XML 格式工作的。

那么,如何才能正确解析这种包含多个根元素的 XML 文件呢?本文将带你一步步解决这个问题。

问题示例

设想我们有这样一个 XML 文件 data.xml,内容如下:

<item>
  <name>Item 1</name>
</item>
<item>
  <name>Item 2</name>
</item>

在标准 XML 中,这是不合法的,因为它包含了两个顶级的 <item> 元素。

方法一:包裹为单一根节点

一种常见的解决方法是,在程序中人为地为这些内容添加一个“虚拟”的根节点。

$xmlContent = file_get_contents('https://m66.net/data.xml');

// 包裹一个虚拟的根节点
$xmlContent = "<root>$xmlContent</root>";

$parser = xml_parser_create();
xml_parse_into_struct($parser, $xmlContent, $values, $index);
xml_parser_free($parser);

print_r($values);

这样处理后,xml_parse 就可以把整个文档看作是一个合法的 XML 文件来处理,解析过程也就不会报错了。

方法二:逐行解析多个片段

如果 XML 文件非常大,或者你不想一次性读取所有内容,也可以使用 xml_parse 的流式处理方式,一段一段地解析。

$parser = xml_parser_create();

function startElement($parser, $name, $attrs) {
    echo "Start: $name\n";
}

function endElement($parser, $name) {
    echo "End: $name\n";
}

function characterData($parser, $data) {
    echo "Data: " . trim($data) . "\n";
}

xml_set_element_handler($parser, "startElement", "endElement");
xml_set_character_data_handler($parser, "characterData");

$handle = fopen("https://m66.net/data.xml", "r");
if ($handle) {
    // 包裹每个 <item> 块,加上虚拟根元素进行逐段解析
    $chunk = '';
    while (($line = fgets($handle)) !== false) {
        $chunk .= $line;
        if (strpos($line, '</item>') !== false) {
            $xml = "<root>$chunk</root>";
            xml_parse($parser, $xml, true);
            $chunk = '';
        }
    }
    fclose($handle);
}

xml_parser_free($parser);