Laravel 13 XML 处理完全指南
XML 是重要的数据交换格式,在许多企业系统中广泛使用。本文将深入探讨 Laravel 13 中 XML 处理的各种方法和最佳实践。
XML 解析
简单 XML 解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| <?php
namespace App\Services;
class XmlParser { public function parse(string $xml): array { $simpleXml = simplexml_load_string($xml); return $this->xmlToArray($simpleXml); }
public function parseFile(string $path): array { $simpleXml = simplexml_load_file($path); return $this->xmlToArray($simpleXml); }
protected function xmlToArray($xml): array { $result = [];
foreach ($xml->children() as $name => $node) { $value = $this->xmlToArray($node);
if (empty($value)) { $result[$name] = (string) $node; } else { $result[$name] = $value; } }
return $result; } }
|
DOMDocument 解析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| <?php
namespace App\Services;
use DOMDocument; use DOMXPath;
class DomXmlParser { public function parse(string $xml): array { $dom = new DOMDocument(); $dom->loadXML($xml); $dom->preserveWhiteSpace = false;
return $this->domToArray($dom->documentElement); }
public function query(string $xml, string $xpath): array { $dom = new DOMDocument(); $dom->loadXML($xml);
$xpathObj = new DOMXPath($dom); $nodes = $xpathObj->query($xpath);
$result = []; foreach ($nodes as $node) { $result[] = $this->domToArray($node); }
return $result; }
protected function domToArray($node): array { $result = [];
if ($node->hasAttributes()) { foreach ($node->attributes as $attr) { $result['@attributes'][$attr->nodeName] = $attr->nodeValue; } }
if ($node->hasChildNodes()) { foreach ($node->childNodes as $child) { if ($child->nodeType === XML_TEXT_NODE) { $text = trim($child->nodeValue); if ($text !== '') { $result['@text'] = $text; } } else { $childArray = $this->domToArray($child); $name = $child->nodeName;
if (isset($result[$name])) { if (!isset($result[$name][0])) { $result[$name] = [$result[$name]]; } $result[$name][] = $childArray; } else { $result[$name] = $childArray; } } } }
return $result; } }
|
XML 构建
简单 XML 构建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <?php
namespace App\Services;
use SimpleXMLElement;
class XmlBuilder { public function build(array $data, string $root = 'root'): string { $xml = new SimpleXMLElement('<?xml version="1.0" encoding="UTF-8"?><' . $root . '/>'); $this->arrayToXml($data, $xml);
return $xml->asXML(); }
protected function arrayToXml(array $data, SimpleXMLElement $xml): void { foreach ($data as $key => $value) { if (is_array($value)) { if (is_numeric($key)) { $key = 'item'; } $subnode = $xml->addChild($key); $this->arrayToXml($value, $subnode); } else { if (is_numeric($key)) { $key = 'item'; } $xml->addChild($key, htmlspecialchars($value)); } } } }
|
DOMDocument 构建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| <?php
namespace App\Services;
use DOMDocument; use DOMElement;
class DomXmlBuilder { protected DOMDocument $dom;
public function __construct() { $this->dom = new DOMDocument('1.0', 'UTF-8'); $this->dom->formatOutput = true; }
public function build(array $data, string $root = 'root'): string { $rootElement = $this->dom->createElement($root); $this->dom->appendChild($rootElement);
$this->buildElements($data, $rootElement);
return $this->dom->saveXML(); }
protected function buildElements(array $data, DOMElement $parent): void { foreach ($data as $key => $value) { if (str_starts_with($key, '@')) { $parent->setAttribute(substr($key, 1), $value); continue; }
if (is_array($value)) { if ($this->isNumericArray($value)) { foreach ($value as $item) { $element = $this->dom->createElement($key); $parent->appendChild($element);
if (is_array($item)) { $this->buildElements($item, $element); } else { $element->textContent = $item; } } } else { $element = $this->dom->createElement($key); $parent->appendChild($element); $this->buildElements($value, $element); } } else { $element = $this->dom->createElement($key); $element->textContent = $value; $parent->appendChild($element); } } }
protected function isNumericArray(array $array): bool { return array_keys($array) === range(0, count($array) - 1); } }
|
XML 验证
XSD 验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
| <?php
namespace App\Services;
use DOMDocument;
class XmlValidator { public function validateAgainstXsd(string $xml, string $xsdPath): array { libxml_use_internal_errors(true);
$dom = new DOMDocument(); $dom->loadXML($xml);
$valid = $dom->schemaValidate($xsdPath);
$errors = []; if (!$valid) { foreach (libxml_get_errors() as $error) { $errors[] = [ 'line' => $error->line, 'column' => $error->column, 'message' => trim($error->message), 'level' => $error->level === LIBXML_ERR_ERROR ? 'error' : 'warning', ]; } }
libxml_clear_errors();
return [ 'valid' => $valid, 'errors' => $errors, ]; }
public function validateWellFormed(string $xml): array { libxml_use_internal_errors(true);
$dom = new DOMDocument(); $valid = $dom->loadXML($xml);
$errors = []; if (!$valid) { foreach (libxml_get_errors() as $error) { $errors[] = [ 'line' => $error->line, 'message' => trim($error->message), ]; } }
libxml_clear_errors();
return [ 'valid' => $valid, 'errors' => $errors, ]; } }
|
XML 转换服务
完整 XML 服务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
| <?php
namespace App\Services;
use SimpleXMLElement; use DOMDocument;
class XmlService { public function toArray(string $xml): array { $simpleXml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA); return json_decode(json_encode($simpleXml), true); }
public function toJson(string $xml, int $options = 0): string { $array = $this->toArray($xml); return json_encode($array, $options); }
public function fromArray(array $data, string $root = 'root', bool $formatOutput = true): string { $dom = new DOMDocument('1.0', 'UTF-8'); $dom->formatOutput = $formatOutput;
$rootElement = $dom->createElement($root); $dom->appendChild($rootElement);
$this->buildXml($dom, $rootElement, $data);
return $dom->saveXML(); }
protected function buildXml(DOMDocument $dom, DOMElement $parent, array $data): void { foreach ($data as $key => $value) { if (str_starts_with($key, '@')) { $parent->setAttribute(substr($key, 1), (string) $value); continue; }
if (str_starts_with($key, '#')) { $parent->textContent = (string) $value; continue; }
if (is_array($value)) { if ($this->isSequential($value)) { foreach ($value as $item) { $child = $dom->createElement($key); $parent->appendChild($child); if (is_array($item)) { $this->buildXml($dom, $child, $item); } else { $child->textContent = (string) $item; } } } else { $child = $dom->createElement($key); $parent->appendChild($child); $this->buildXml($dom, $child, $value); } } else { $child = $dom->createElement($key); $child->textContent = (string) $value; $parent->appendChild($child); } } }
protected function isSequential(array $array): bool { return array_keys($array) === range(0, count($array) - 1); }
public function transform(string $xml, string $xsltPath): string { $xmlDoc = new DOMDocument(); $xmlDoc->loadXML($xml);
$xsltDoc = new DOMDocument(); $xsltDoc->load($xsltPath);
$processor = new \XSLTProcessor(); $processor->importStylesheet($xsltDoc);
return $processor->transformToXML($xmlDoc); } }
|
XML 导入导出
模型 XML 导出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
| <?php
namespace App\Services;
use App\Models\User; use App\Services\XmlService;
class UserXmlExport { protected XmlService $xmlService;
public function __construct(XmlService $xmlService) { $this->xmlService = $xmlService; }
public function export(array $userIds = null): string { $query = User::query();
if ($userIds) { $query->whereIn('id', $userIds); }
$users = $query->get();
$data = [ '@version' => '1.0', '@generated' => now()->toIso8601String(), 'users' => [ 'user' => $users->map(fn($user) => $this->formatUser($user))->toArray(), ], ];
return $this->xmlService->fromArray($data, 'users'); }
protected function formatUser(User $user): array { return [ '@id' => $user->id, 'name' => $user->name, 'email' => $user->email, 'created_at' => $user->created_at->toIso8601String(), ]; }
public function download(array $userIds = null) { $xml = $this->export($userIds);
return response($xml, 200, [ 'Content-Type' => 'application/xml', 'Content-Disposition' => 'attachment; filename="users.xml"', ]); } }
|
XML 导入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
| <?php
namespace App\Services;
use App\Models\User; use App\Services\XmlService;
class UserXmlImport { protected XmlService $xmlService;
public function __construct(XmlService $xmlService) { $this->xmlService = $xmlService; }
public function import(string $xml): array { $data = $this->xmlService->toArray($xml);
$results = [ 'total' => 0, 'success' => 0, 'failed' => 0, 'errors' => [], ];
$users = $data['users']['user'] ?? [];
if (isset($users['@id'])) { $users = [$users]; }
foreach ($users as $index => $userData) { $results['total']++;
try { $this->importUser($userData); $results['success']++; } catch (\Exception $e) { $results['failed']++; $results['errors'][] = [ 'index' => $index, 'error' => $e->getMessage(), ]; } }
return $results; }
protected function importUser(array $data): User { $id = $data['@id'] ?? null;
$userData = [ 'name' => $data['name'] ?? '', 'email' => $data['email'] ?? '', ];
if ($id) { $user = User::updateOrCreate(['id' => $id], $userData); } else { $user = User::create($userData); }
return $user; } }
|
总结
Laravel 13 的 XML 处理提供了:
- SimpleXML 和 DOMDocument 解析
- 灵活的 XML 构建器
- XSD 验证支持
- XML 与数组互转
- XSLT 转换功能
- 模型导入导出
掌握 XML 处理技巧可以满足各种数据交换需求。