首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP XML 数据生成与解析:DOMDocument 构建、XMLReader 流式读取、JSON 对比、命名空间处理

     編輯:PHP 相關知識

场景对比:XML vs JSON

维度XMLJSON
体积冗长(标签重复)紧凑
解析速度较慢(DOM/SAX)极快(原生 json_decode)
类型系统仅文本,需 Schema 约束原生数字/布尔/数组/对象
命名空间/混合内容原生支持需约定俗成
流式处理XMLReader (pull parser)无标准流式解析器
适用场景企业集成、SOAP、配置文件、文档标记REST API、前后端交互、配置、日志

1. 生成 XML:DOMDocument 规范构建

<?php
function generateStudentXml(array $students): string
{
    $dom = new DOMDocument('1.0', 'UTF-8');
    $dom->formatOutput = true; // 缩进美化
    $dom->preserveWhiteSpace = false;

    $root = $dom->createElement('students');
    $dom->appendChild($root);

    foreach ($students as $stu) {
        $node = $dom->createElement('student');
        $node->setAttribute('id', $stu['id']);

        // 简单元素
        foreach (['name', 'sex', 'age'] as $field) {
            $child = $dom->createElement($field, $stu[$field]);
            $node->appendChild($child);
        }

        // CDATA 包含 HTML/特殊字符
        if (!empty($stu['bio'])) {
            $bio = $dom->createElement('bio');
            $bio->appendChild($dom->createCDATASection($stu['bio']));
            $node->appendChild($bio);
        }

        $root->appendChild($node);
    }

    return $dom->saveXML();
}

// 数据源
$students = [
    ['id' => 1, 'name' => '张三', 'sex' => '男', 'age' => 20, 'bio' => '喜欢<编程> & 游戏'],
    ['id' => 2, 'name' => '李四', 'sex' => '女', 'age' => 19, 'bio' => ''],
];

header('Content-Type: application/xml; charset=UTF-8');
echo generateStudentXml($students);

输出示例:

<?xml version="1.0" encoding="UTF-8"?>

  
    张三
    男
    20
     & 游戏]]>
  
  
    李四
    女
    19
  

2. 解析 XML:XMLReader 大文件流式读取(内存恒定)

<?php
function parseLargeXml(string $urlOrPath): \Generator
{
    $reader = new XMLReader();
    if (!$reader->open($urlOrPath)) {
        throw new \RuntimeException("Cannot open XML: $urlOrPath");
    }

    try {
        while ($reader->read()) {
            // 只关心  元素开始
            if ($reader->nodeType === XMLReader::ELEMENT && $reader->name === 'student') {
                // 读取完整  子树为 DOMNode
                $node = $reader->expand(); // 返回 DOMElement
                $dom = new DOMDocument();
                $studentNode = $dom->importNode($node, true);

                yield [
                    'id'   => $studentNode->getAttribute('id'),
                    'name' => $studentNode->getElementsByTagName('name')->item(0)?->textContent,
                    'sex'  => $studentNode->getElementsByTagName('sex')->item(0)?->textContent,
                    'age'  => (int)$studentNode->getElementsByTagName('age')->item(0)?->textContent,
                    'bio'  => $studentNode->getElementsByTagName('bio')->item(0)?->textContent,
                ];
            }
        }
    } finally {
        $reader->close();
    }
}

// 使用:逐个处理,内存仅保留当前节点
foreach (parseLargeXml('https://example.com/students.xml') as $stu) {
    // 入库、转 JSON、推送队列...
    echo "{$stu['name']} ({$stu['age']})\n";
}
XMLReader::expand() 将当前节点及子树导入 DOM,便于 XPath/DOM 方法提取,但会临时构建子树 DOM,超大单节点(>10MB)仍需注意。

3. SimpleXML:小文件极简解析

<?php
$xml = simplexml_load_file('students.xml');
// 或 simplexml_load_string($xmlStr)

foreach ($xml->student as $stu) {
    echo (string)$stu->name; // 强制转 string
    echo (string)$stu['id']; // 属性访问
    // 命名空间:$stu->children('ns', true)->field
}

4. 命名空间处理实战

<?php
$xml = <<

  Value

XML;

$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('foo', 'https://example.com/foo');

$items = $xpath->query('//foo:item');
foreach ($items as $item) {
    echo $item->getAttribute('id') . ': ' . $item->textContent;
}

5. XML ↔ JSON 互转

<?php
// XML -> JSON
function xmlToJson(string $xml): string
{
    $dom = new DOMDocument();
    $dom->loadXML($xml);
    // 简易转换:属性变 @attr,文本变 #text
    $json = json_encode(domToArray($dom->documentElement), JSON_UNESCAPED_UNICODE);
    return $json;
}

function domToArray(DOMElement $el): array
{
    $arr = ['@attributes' => []];
    foreach ($el->attributes as $attr) {
        $arr['@attributes'][$attr->name] = $attr->value;
    }
    foreach ($el->childNodes as $child) {
        if ($child->nodeType === XML_TEXT_NODE) {
            $arr['#text'] = $child->textContent;
        } elseif ($child->nodeType === XML_ELEMENT_NODE) {
            $key = $child->tagName;
            $value = domToArray($child);
            if (isset($arr[$key])) {
                if (!isset($arr[$key][0])) $arr[$key] = [$arr[$key]];
                $arr[$key][] = $value;
            } else {
                $arr[$key] = $value;
            }
        }
    }
    return $arr;
}

// JSON -> XML (简易)
function jsonToXml(string $json, string $rootName = 'root'): string
{
    $data = json_decode($json, true);
    $dom = new DOMDocument('1.0', 'UTF-8');
    $root = $dom->createElement($rootName);
    $dom->appendChild($root);
    arrayToDom($data, $root, $dom);
    return $dom->saveXML();
}

function arrayToDom(array $data, DOMElement $parent, DOMDocument $dom): void
{
    foreach ($data as $key => $value) {
        if ($key === '@attributes') {
            foreach ($value as $attr => $val) {
                $parent->setAttribute($attr, $val);
            }
        } elseif ($key === '#text') {
            $parent->appendChild($dom->createTextNode($value));
        } elseif (is_array($value) && isset($value[0])) {
            foreach ($value as $item) {
                $child = $dom->createElement($key);
                $parent->appendChild($child);
                arrayToDom($item, $child, $dom);
            }
        } else {
            $child = $dom->createElement($key);
            $parent->appendChild($child);
            arrayToDom($value, $child, $dom);
        }
    }
}

性能与选型建议

场景推荐方案理由
生成小配置/数据交换JSON (json_encode)原生、快、体积小
生成标准 XML 接口(对外)DOMDocument规范、支持 CDATA/命名空间/Schema 验证
解析小 XML(<5MB)SimpleXML代码极简、语法糖丰富
解析大 XML(>50MB)XMLReader + expand()流式、内存恒定、支持 XPath 片段查询
高性能解析固定结构XMLReader 纯游标模式无 DOM 开销,仅节点类型/名称/值判断

总结

PHP 操作 XML 核心三件套:DOMDocument 生成、XMLReader 流式解析大文件、SimpleXML 便捷解析小文件。现代 API 优先选 JSON,仅在对接遗留系统、SOAP、标准化文档交换时使用 XML。掌握 XMLReader::expand() 与 DOMXPath 配合,能优雅解决「大文件+复杂查询」的矛盾。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved