如何遍历XML并将国家-地区-城市数据存入MySQL表?
从XML层级数据到MySQL存储的完整实现指南
我来帮你梳理从国家-地区-城市层级XML数据到MySQL存储的完整流程,从数据库表结构设计到PHP代码落地都给你讲清楚:
一、先搞定MySQL表结构设计
针对你这种明确的三级层级数据,推荐设计三个关联表,数据结构清晰且易于维护:
1. 国家表 (countries)
用来存储国家编码和名称,比如GR对应希腊:
CREATE TABLE countries ( country_id INT AUTO_INCREMENT PRIMARY KEY, country_code VARCHAR(2) NOT NULL UNIQUE, -- 唯一的国家编码 country_name VARCHAR(100) NOT NULL );
2. 地区表 (regions)
关联对应的国家,存储地区的编码和名称:
CREATE TABLE regions ( region_id INT AUTO_INCREMENT PRIMARY KEY, country_id INT NOT NULL, region_code VARCHAR(50) NOT NULL, -- 地区编码,比如GR-AT region_name VARCHAR(100) NOT NULL, FOREIGN KEY (country_id) REFERENCES countries(country_id) ON DELETE CASCADE );
3. 城市表 (cities)
关联对应的地区,存储城市的编码和名称:
CREATE TABLE cities ( city_id INT AUTO_INCREMENT PRIMARY KEY, region_id INT NOT NULL, city_code VARCHAR(50) NOT NULL, -- 城市编码,比如GR-ATH city_name VARCHAR(100) NOT NULL, FOREIGN KEY (region_id) REFERENCES regions(region_id) ON DELETE CASCADE );
如果觉得分表麻烦,也可以用单表自关联的方式,但三级结构下分表更易后续查询和维护。
二、PHP完整遍历与存储代码
假设你已经能获取到每个国家的XML文件,下面基于SimpleXML完成读取、遍历、入库的完整逻辑,用PDO操作数据库更安全:
1. 封装数据库连接
先写个复用的数据库连接函数,避免重复代码:
function getDbConnection() { $host = 'localhost'; $dbname = '你的数据库名'; $username = '你的用户名'; $password = '你的密码'; try { $pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password); $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return $pdo; } catch(PDOException $e) { die("数据库连接失败: " . $e->getMessage()); } }
2. 遍历XML并插入数据
先假设你的XML结构是这样的(结合你提到的地区/城市示例简化):
示例XML结构:
<country code="GR" name="希腊"> <regions> <region code="GR-AT" name="阿提卡"> <cities> <city code="GR-ATH" name="雅典"/> <city code="GR-PIR" name="比雷埃夫斯"/> </cities> </region> </regions> </country>
对应的PHP处理代码:
// 获取数据库连接 $pdo = getDbConnection(); // 假设你已经有所有国家XML文件的路径数组,比如$countryXmlFiles = ['gr.xml', 'cn.xml', ...]; foreach ($countryXmlFiles as $xmlPath) { // 加载XML文件,失败则跳过当前文件 $xml = simplexml_load_file($xmlPath); if (!$xml) { echo "加载XML文件失败: $xmlPath<br>"; continue; } // 1. 插入国家数据(先检查是否已存在,避免重复) $countryCode = (string)$xml['code']; $countryName = (string)$xml['name']; $stmt = $pdo->prepare("SELECT country_id FROM countries WHERE country_code = ?"); $stmt->execute([$countryCode]); $countryId = $stmt->fetchColumn(); if (!$countryId) { $stmt = $pdo->prepare("INSERT INTO countries (country_code, country_name) VALUES (?, ?)"); $stmt->execute([$countryCode, $countryName]); $countryId = $pdo->lastInsertId(); } // 2. 遍历所有地区 foreach ($xml->regions->region as $regionNode) { $regionCode = (string)$regionNode['code']; $regionName = (string)$regionNode['name']; // 检查地区是否已存在 $stmt = $pdo->prepare("SELECT region_id FROM regions WHERE country_id = ? AND region_code = ?"); $stmt->execute([$countryId, $regionCode]); $regionId = $stmt->fetchColumn(); if (!$regionId) { $stmt = $pdo->prepare("INSERT INTO regions (country_id, region_code, region_name) VALUES (?, ?, ?)"); $stmt->execute([$countryId, $regionCode, $regionName]); $regionId = $pdo->lastInsertId(); } // 3. 遍历当前地区下的所有城市 // 先判断是否存在城市节点,避免空遍历报错 if (isset($regionNode->cities->city)) { foreach ($regionNode->cities->city as $cityNode) { $cityCode = (string)$cityNode['code']; $cityName = (string)$cityNode['name']; // 检查城市是否已存在 $stmt = $pdo->prepare("SELECT city_id FROM cities WHERE region_id = ? AND city_code = ?"); $stmt->execute([$regionId, $cityCode]); $cityId = $stmt->fetchColumn(); if (!$cityId) { $stmt = $pdo->prepare("INSERT INTO cities (region_id, city_code, city_name) VALUES (?, ?, ?)"); $stmt->execute([$regionId, $cityCode, $cityName]); } } } } echo "成功处理国家: $countryName ($countryCode)<br>"; }
三、几个关键注意点
- 数据去重:每次插入前先查询是否已存在对应数据,避免重复入库(尤其是如果XML文件可能被重复处理的情况)。
- 字符编码:确保数据库连接用
utf8mb4,和XML文件编码一致,避免中文或特殊字符乱码。 - 异常处理:可以在代码中添加更多
try-catch块,捕获XML解析或数据库操作的异常,方便排查问题。比如在遍历XML的循环外包裹try-catch:try { // 遍历XML的逻辑 } catch (Exception $e) { echo "处理$xmlPath时出错: " . $e->getMessage() . "<br>"; continue; } - 批量插入优化:如果数据量很大,建议用批量插入提升效率。比如收集多个城市数据后,用
INSERT INTO cities (...) VALUES (...), (...), (...)的格式一次性插入。 - XML容错:如果有些地区没有城市节点,一定要用
isset()判断,避免报错。
内容的提问来源于stack exchange,提问作者Abdul Rahman
相关产品推荐
相关产品推荐

