在系統整合、數據交換場景中,需確保 XML 文件結構符合預期規範。本文提供一個基於 SimpleXML 的輕量級結構驗證器,以基準文件為標準,遞歸檢查目標文件的節點、屬性、層級是否合規,適用於無 XSD Schema 環境下的快速驗證。
<?php
/**
* XML 結構驗證器
* @param string $baseFilePath 基準結構文件路徑
* @param string $checkFilePath 待驗證文件路徑
* @return bool 結構合規返回 true,否則 false
*/
function checkXmlFileStructure($baseFilePath, $checkFilePath)
{
// 載入基準文件
if (!file_exists($baseFilePath)) return false;
$base = simplexml_load_file($baseFilePath);
if ($base === false) return false;
// 載入待驗證文件
if (!file_exists($checkFilePath)) return false;
$check = simplexml_load_file($checkFilePath);
if ($check === false) return false;
// 根節點名稱必須一致
if ($base->getName() !== $check->getName()) return false;
// 遞歸驗證結構
return checkXmlStructure($base, $check);
}
/**
* 遞歸驗證節點結構
* @param SimpleXMLElement $base 基準節點
* @param SimpleXMLElement $check 待驗證節點
* @return bool
*/
function checkXmlStructure($base, $check)
{
// 1. 檢查屬性:基準定義的屬性必須存在於目標
foreach ($base->attributes() as $name => $baseAttr) {
if (!isset($check->attributes()->$name)) {
return false; // 缺少必要屬性
}
}
// 2. 若基準無子節點,目標也不應有子節點 (嚴格模式)
// 此處採用寬容模式:允許目標有額外子節點
// 若需嚴格模式,取消下面註釋:
// if (count($base->children()) === 0) {
// return count($check->children()) === 0;
// }
// 3. 將目標子節點按名稱分組 (同名節點可能多個)
$checkChildren = [];
foreach ($check->children() as $name => $child) {
$checkChildren[$name][] = $child;
}
// 4. 遞歸檢查基準的每個子節點
$checkedNames = [];
foreach ($base->children() as $name => $baseChild) {
// 跳過已檢查的同名節點 (基準中重複定義視為同一類型)
if (in_array($name, $checkedNames)) continue;
$checkedNames[] = $name;
// 基準要求的子節點必須存在於目標
if (empty($checkChildren[$name])) {
return false; // 缺少必要子節點
}
// 對目標中每個同名節點進行遞歸驗證 (至少有一個通過即可?此處要求全部通過)
foreach ($checkChildren[$name] as $checkChild) {
if (!checkXmlStructure($baseChild, $checkChild)) {
return false;
}
}
}
return true;
}
/* ===== 入口適配 ===== */
if (php_sapi_name() === 'cli') {
// 命令列模式: php check_xml.php base_file=base.xml check_file=test.xml
parse_str(implode('&', array_slice($argv, 1)), $_GET);
if (empty($_GET['base_file']) || empty($_GET['check_file'])) {
fwrite(STDERR, "Usage: php " . basename(__FILE__) . " base_file=base.xml check_file=check.xml\n");
exit(1);
}
exit(checkXmlFileStructure($_GET['base_file'], $_GET['check_file']) ? 0 : 1);
} else {
// Web 模式: check_xml.php?base_file=base.xml&check_file=test.xml
if (empty($_GET['base_file']) || empty($_GET['check_file'])) {
header('Content-Type: text/plain; charset=utf-8');
echo "Usage: " . basename(__FILE__) . "?base_file=base.xml&check_file=check.xml";
exit;
}
header('Content-Type: text/plain; charset=utf-8');
echo checkXmlFileStructure($_GET['base_file'], $_GET['check_file']) ? '1' : '0';
}
php check_xml_structure.php base_file=base.xml check_file=check.xml
# 返回碼 0=通過, 1=失敗
# Shell 腳本判斷:
if [ $? -ne 0 ]; then echo "XML 結構不合規"; fi
GET /check_xml_structure.php?base_file=base.xml&check_file=check.xml
# 返回: 1 (通過) 或 0 (失敗)
<!-- base_1.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>
<Category>Category文字</Category>
<Title>Title文字</Title>
</item>
</items>
<!-- check_1.xml (合規:包含基準所有節點,可有額外節點) -->
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item>
<Category>Category文字</Category>
<Title>Title文字</Title>
</item>
<item>
<Category>Category文字</Category>
<Title>Title文字</Title>
<Description>額外描述</Description> <!-- 允許額外 -->
</item>
</items>
驗證結果:通過 (目標包含基準所有節點,多出的 Description 不影響)
<!-- base_2.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item category="Category文字" Title="Title文字"/>
</items>
<!-- check_2.xml (合規:屬性齊全,可有額外屬性) -->
<?xml version="1.0" encoding="UTF-8"?>
<items>
<item category="Category文字" Title="Title文字" Description="描述"/>
<item category="Category文字" Title="Title文字"/>
<item category="Category文字" Title="Title文字" Description="描述"/>
</items>
驗證結果:通過
<!-- 缺少必要屬性 -->
<item category="Category文字"/> <!-- 缺 Title 屬性 -->
<!-- 缺少必要子節點 -->
<item>
<Category>...</Category>
</item> <!-- 缺 Title 子節點 -->
<!-- 根節點名稱不符 -->
<data>...</data> <!-- 基準為 items -->
| 適用 | 不適用 |
|---|---|
| 無 XSD 環境的快速結構檢查 | 複雜資料類型、約束條件 (唯一性、引用完整性) |
| API 回應結構回歸測試 | 高性能、大文件 (GB級) 驗證 |
| 配置文件部署前驗證 | 需嚴格標準合規的企業級數據交換 |
| 輕量級微服務契約測試 | 替代正式 Schema 驗證流程 |
此驗證器以 ~80 行核心代碼實現了實用的 XML 結構合規檢查,為缺乏 Schema 定義的項目提供了低成本的質量保障手段。