تبدیل XML به JSON زمانی لازم میشود که داده از سرویسهای سازمانی، فایلهای پیکربندی، سیستمهای قدیمی، SOAP API یا خروجی نرمافزارهایی دریافت میشود که XML تولید میکنند، اما برنامه مقصد با JavaScript، REST API، پایگاه داده سندگرا یا ساختارهای JSON کار میکند. این تبدیل در نگاه اول ساده به نظر میرسد، اما XML و JSON مدل داده یکسانی ندارند. XML میتواند attribute، namespace، متن، element تکراری، ترتیب فرزندان، CDATA و mixed content داشته باشد؛ در حالی که JSON با object، array و مقدارهای نوعدار کار میکند. بنابراین یک تبدیل مطمئن باید قواعد نگاشت روشنی برای elementها، attributeها، آرایهها، null، نوع داده و namespace داشته باشد.
پاسخ سریع: برای تبدیل XML به JSON، هر element معمولاً به یک کلید object، متن element به مقدار و elementهای تکراری همنام به array تبدیل میشوند. Attributeها باید با قرارداد مشخصی مانند پیشوند
@یا object جداگانه نگهداری شوند. XML بدون Schema نوع دادهها را بهصورت متن نگه میدارد؛ بنابراین تبدیل Number، Boolean و null باید با قواعد صریح یا XSD انجام شود.
تبدیل XML به JSON دقیقاً چه کاری انجام میدهد؟
در این تبدیل، یک درخت XML به ساختاری از object و array تبدیل میشود. سادهترین حالت زمانی است که هر element فقط متن یا چند فرزند ساده دارد و attribute یا mixed content وجود ندارد.
ورودی XML:
<user>
<id>101</id>
<name>سارا</name>
<active>true</active>
</user>
یک خروجی رایج:
{
"user": {
"id": "101",
"name": "سارا",
"active": "true"
}
}
همه مقدارها در این خروجی String هستند، چون XML خام نوع Number یا Boolean را بهصورت ذاتی حفظ نمیکند. تبدیل "101" به Number و "true" به Boolean تصمیمی جداگانه است.
تفاوت مدل داده XML و JSON
| ویژگی | XML | JSON |
|---|---|---|
| ساختار | Element، Attribute و متن | Object، Array و مقدار |
| ریشه | دقیقاً یک Document Element | Object، Array یا مقدار ساده |
| نوع داده | متن مگر اینکه Schema نوع را تعریف کند | String، Number، Boolean، null، Object و Array |
| Attribute | پشتیبانی داخلی | معادل مستقیم ندارد |
| Namespace | پشتیبانی داخلی | معادل مستقیم ندارد |
| Mixed Content | ممکن است element و متن ترکیب شوند | نگاشت طبیعی و یکتا ندارد |
| Element تکراری | مجاز و رایج | معمولاً به Array تبدیل میشود |
به همین دلیل، دو کتابخانه مختلف ممکن است از یک XML خروجی JSON متفاوتی بسازند و هر دو از نظر قراردادی قابلقبول باشند.
نگاشت Elementهای تودرتو
Element داخلی معمولاً به object داخلی تبدیل میشود:
<order>
<id>A-500</id>
<customer>
<name>مریم</name>
<city>تبریز</city>
</customer>
</order>
{
"order": {
"id": "A-500",
"customer": {
"name": "مریم",
"city": "تبریز"
}
}
}
این نگاشت تا زمانی ساده است که نام فرزندان تکراری نباشد و element همزمان متن و فرزند نداشته باشد.
Elementهای تکراری چگونه به Array تبدیل میشوند؟
وقتی چند فرزند همنام وجود دارند، معمولاً یک array ساخته میشود:
<items>
<item>
<sku>P10</sku>
<qty>2</qty>
</item>
<item>
<sku>P22</sku>
<qty>1</qty>
</item>
</items>
{
"items": {
"item": [
{
"sku": "P10",
"qty": "2"
},
{
"sku": "P22",
"qty": "1"
}
]
}
}
بعضی مبدلها wrapper را حذف میکنند و مستقیماً items را array میسازند. این سادهتر است، اما اطلاعات دقیق ساختار XML را تغییر میدهد.
تفاوت یک عضو با چند عضو
یکی از مشکلات رایج این است که یک element در فایل اول یکبار و در فایل دوم چندبار ظاهر شود. اگر مبدل فقط در حالت تکرار array بسازد، نوع فیلد ناپایدار میشود:
{
"item": {"sku": "P10"}
}
در مقابل:
{
"item": [
{"sku": "P10"},
{"sku": "P22"}
]
}
برای API پایدار بهتر است Schema مشخص کند کدام elementها همیشه array هستند، حتی اگر فقط یک عضو داشته باشند.
Attributeها در JSON چگونه نگهداری میشوند؟
JSON معادل مستقیمی برای attribute ندارد. چند قرارداد رایج وجود دارد:
<product id="P10" currency="IRR">
<name>کیبورد</name>
<price>1250000</price>
</product>
روش پیشوندگذاری
{
"product": {
"@id": "P10",
"@currency": "IRR",
"name": "کیبورد",
"price": "1250000"
}
}
روش object جداگانه
{
"product": {
"attributes": {
"id": "P10",
"currency": "IRR"
},
"name": "کیبورد",
"price": "1250000"
}
}
روش object جداگانه برخورد نام attribute و element را کاهش میدهد. روش پیشوندگذاری خروجی کوتاهتری میسازد. انتخاب باید در کل پروژه ثابت باشد.
متن Element همراه Attribute
وقتی element هم attribute و هم متن دارد، نمیتوان مقدار را فقط یک String ساده قرار داد:
<price currency="IRR">1250000</price>
خروجی قراردادی:
{
"price": {
"@currency": "IRR",
"#text": "1250000"
}
}
نامهای @currency و #text استاندارد رسمی JSON نیستند؛ فقط یک قرارداد رایج برای حفظ اطلاعات XML هستند.
Element خالی چه معنایی دارد؟
این دو شکل XML معمولاً از نظر XML برابرند:
<note></note>
<note />
اما هنگام تبدیل به JSON، چند خروجی ممکن است:
"note": """note": null"note": {}- حذف کامل کلید
هیچ انتخابی بهطور مطلق درست نیست. اگر XSD از nillable و xsi:nil استفاده کند، null را میتوان دقیقتر تشخیص داد.
xsi:nil و null
<note xmlns:xsi="urn:example:xml-schema-instance"
xsi:nil="true" />
با قرارداد مناسب میتوان این element را به null تبدیل کرد:
{
"note": null
}
اما element خالی بدون xsi:nil الزاماً null نیست و ممکن است String خالی باشد.
تشخیص نوع دادهها
XML خام معمولاً متن تولید میکند. مقادیر زیر بدون Schema ابهام دارند:
| متن XML | تفسیرهای ممکن | ریسک |
|---|---|---|
00123 | String یا Number | صفر ابتدایی ممکن است حذف شود |
true | String یا Boolean | ممکن است متن واقعی باشد |
1 | String، Number یا Boolean قراردادی | بدون Schema مبهم است |
9007199254740993 | String یا عدد بزرگ | در JavaScript احتمال کاهش دقت وجود دارد |
2026-08-06 | String یا تاریخ | JSON نوع Date مستقل ندارد |
روشهای اصلی:
- تمام متنها را String نگه دارید.
- با قواعد محافظهکارانه نوع را حدس بزنید.
- از XSD برای تعیین نوع element و attribute استفاده کنید.
- Schema داخلی برنامه را برای تبدیل فیلدهای مشخص به کار ببرید.
برای جلوگیری از تغییر ناخواسته شناسه و کد پستی، روش Schema-driven مطمئنتر است.
Namespace در تبدیل XML به JSON
XML میتواند elementهای همنام از namespaceهای متفاوت داشته باشد:
<root xmlns:a="urn:example:a"
xmlns:b="urn:example:b">
<a:item>A</a:item>
<b:item>B</b:item>
</root>
اگر prefix یا URI حذف شود، هر دو element به کلید item تبدیل میشوند و برخورد نام رخ میدهد. روشهای نگهداری namespace:
- حفظ نام کامل مانند
{urn:example:a}item. - حفظ prefix مانند
a:item. - ذخیره namespace در metadata جداگانه.
- حذف namespace فقط زمانی که برخورد نام و نیاز قراردادی وجود ندارد.
Prefix ممکن است بین دو سند تغییر کند، اما URI namespace هویت واقعی را نشان میدهد. بنابراین برای پردازش دقیق، URI مطمئنتر است.
CDATA در JSON چگونه نمایش داده میشود؟
CDATA فقط روشی برای نوشتن متن در XML است. پس از Parse، بیشتر Parserها آن را همان متن معمولی تحویل میدهند:
<script><![CDATA[
if (a < b) {
run();
}
]]></script>
خروجی:
{
"script": "if (a < b) {\n run();\n}"
}
اگر حفظ تفاوت بین CDATA و متن عادی مهم باشد، Parser باید metadata مخصوص ارائه کند؛ JSON ساده این تفاوت را نگه نمیدارد.
Mixed Content؛ چالش مهم XML
XML میتواند متن و element را ترکیب کند:
<p>این یک <strong>متن مهم</strong> است.</p>
تبدیل ساده object-based ممکن است ترتیب متن را از بین ببرد. یک مدل حفظکننده ترتیب میتواند چنین باشد:
{
"p": {
"content": [
{"type": "text", "value": "این یک "},
{
"type": "element",
"name": "strong",
"value": "متن مهم"
},
{"type": "text", "value": " است."}
]
}
}
برای دادههای سندی مانند HTML، DocBook یا XML محتوایی، تبدیل ساده element-to-object معمولاً کافی نیست.
ترتیب Elementها
JSON object از نظر معنایی برای دسترسی با کلید طراحی شده است، اما XML ترتیب فرزندان را حفظ میکند. اگر چند element با نام متفاوت ترتیب معنادار داشته باشند، تبدیل به object ساده ممکن است این معنا را پنهان کند.
برای حفظ کامل ترتیب میتوان خروجی array-based تولید کرد:
{
"children": [
{"name": "title", "value": "راهنما"},
{"name": "image", "value": "cover.png"},
{"name": "paragraph", "value": "متن"}
]
}
تبدیل XML به JSON در JavaScript
در مرورگر میتوان XML را با DOMParser خواند. نمونه زیر attribute، متن و elementهای تکراری را مدیریت میکند:
function elementToValue(element) {
const result = {};
for (const attribute of element.attributes) {
result[`@${attribute.name}`] = attribute.value;
}
const childElements = [...element.children];
if (childElements.length === 0) {
const text = element.textContent ?? "";
if (element.attributes.length === 0) {
return text;
}
result["#text"] = text;
return result;
}
for (const child of childElements) {
const value = elementToValue(child);
const key = child.nodeName;
if (Object.prototype.hasOwnProperty.call(result, key)) {
if (!Array.isArray(result[key])) {
result[key] = [result[key]];
}
result[key].push(value);
} else {
result[key] = value;
}
}
return result;
}
function xmlToJson(xmlText) {
const document = new DOMParser().parseFromString(
xmlText,
"application/xml"
);
const parserError = document.querySelector("parsererror");
if (parserError) {
throw new Error("XML نامعتبر است.");
}
const root = document.documentElement;
return {
[root.nodeName]: elementToValue(root)
};
}
این نمونه whitespace متنی میان elementها را نادیده میگیرد و mixed content را بهطور کامل حفظ نمیکند. برای namespace نیز از nodeName استفاده میکند که ممکن است prefix را در خود داشته باشد.
تبدیل XML به JSON در Node.js
در Node.js باید از XML parser معتبر استفاده شود. تنظیمات مهم کتابخانه معمولاً شامل این موارد است:
- حفظ یا حذف attributeها.
- نام پیشوند attribute.
- تبدیل element تکراری به array.
- حفظ namespace.
- Trim کردن یا حفظ whitespace.
- تبدیل خودکار Number و Boolean.
- مدیریت entity و DTD.
تنظیم پیشفرض کتابخانه را بدون بررسی قرارداد مقصد نپذیرید، زیرا خروجی ممکن است در نسخه یا کتابخانه دیگر متفاوت باشد.
تبدیل XML به JSON در Python
نمونه زیر با xml.etree.ElementTree elementها، attributeها و تکرار فرزندان را مدیریت میکند:
import json
import xml.etree.ElementTree as ET
from collections import defaultdict
def element_to_value(element):
result = {
f"@{key}": value
for key, value in element.attrib.items()
}
children = list(element)
if not children:
text = element.text or ""
if not result:
return text
result["#text"] = text
return result
grouped = defaultdict(list)
for child in children:
grouped[child.tag].append(element_to_value(child))
for tag, values in grouped.items():
result[tag] = values[0] if len(values) == 1 else values
text = (element.text or "").strip()
if text:
result["#text"] = text
return result
def xml_to_json(xml_text):
root = ET.fromstring(xml_text)
return {
root.tag: element_to_value(root)
}
xml_text = """
<order id="A-500">
<item>
<sku>P10</sku>
<qty>2</qty>
</item>
<item>
<sku>P22</sku>
<qty>1</qty>
</item>
</order>
"""
data = xml_to_json(xml_text)
print(json.dumps(
data,
ensure_ascii=False,
indent=2
))
در کد واقعی، متن XML باید شامل علامتهای واقعی XML باشد؛ در این مثال کاراکترها برای نمایش امن داخل HTML escape شدهاند.
خطاهای Syntax XML قبل از تبدیل
اگر XML well-formed نباشد، تبدیل نباید ادامه پیدا کند. خطاهای رایج:
- بستهنشدن element.
- عدم تطابق نام tag باز و بسته.
- وجود چند root element.
- استفاده از ampersand خام.
- کوتیشن ناقص در attribute.
- prefix namespace بدون declaration.
- کاراکتر نامعتبر برای نسخه XML انتخابی.
Well-formed بودن فقط Syntax را تأیید میکند. انطباق با XSD یا قواعد کسبوکار مرحله دیگری است.
نمونه صحیح و غلط
XML صحیح
<user>
<name>A & B</name>
</user>
XML غلط به دلیل ampersand خام
<user>
<name>A & B</name>
</user>
XML غلط به دلیل tag ناسازگار
<user>
<name>سارا</title>
</user>
خطاهای رایج در تبدیل XML به JSON
نادیدهگرفتن Attributeها
اگر فقط فرزندان و متن خوانده شوند، metadata موجود در attributeها از بین میرود.
تبدیل Element تکراری به مقدار منفرد
این کار باعث overwrite شدن اعضای قبلی میشود. فرزندان همنام باید array شوند یا طبق Schema پردازش شوند.
تبدیل خودکار بیشازحد نوعها
مقدار 00123 نباید بدون Schema به Number تبدیل شود. نوعدهی محافظهکارانه از تغییر داده جلوگیری میکند.
حذف Namespace بدون بررسی
دو element از namespaceهای مختلف ممکن است پس از حذف prefix همنام شوند و داده یکدیگر را overwrite کنند.
Trim کردن همه متنها
در دادههای سندی، whitespace میتواند معنادار باشد. Trim خودکار برای همه elementها مناسب نیست.
فرض اینکه هر Element خالی null است
Element خالی ممکن است String خالی یا مقدار موجود اما بدون متن باشد. null باید با قرارداد یا xsi:nil تشخیص داده شود.
امنیت هنگام Parse XML
- قابلیت external entity را غیرفعال کنید تا خطر XXE کاهش یابد.
- DTD را فقط در صورت نیاز و با سیاست امن فعال کنید.
- اندازه فایل، عمق درخت، تعداد element و طول متن را محدود کنید.
- از Parser بهروز و تنظیمشده برای ورودی غیرقابلاعتماد استفاده کنید.
- برای جلوگیری از حملات گسترش entity، محدودیت منابع اعمال کنید.
- JSON خروجی را بدون validation وارد دیتابیس، HTML یا command نکنید.
- نام کلیدها را هنگام merge کردن objectهای JavaScript کنترل کنید.
تبدیل XML به JSON محتوای ورودی را امن نمیکند. داده پس از تبدیل همچنان باید متناسب با مقصد validate و encode شود.
پردازش XMLهای بزرگ
DOM کل سند XML را در حافظه نگه میدارد. برای فایلهای بزرگ، SAX، pull parser یا iterparse مناسبتر است.
- Elementها را بهصورت رویدادی پردازش کنید.
- پس از تبدیل هر بخش، حافظه element پردازششده را آزاد کنید.
- برای خروجی بزرگ از NDJSON استفاده کنید.
- اگر JSON Array لازم است، براکت و کاماها را در Stream مدیریت کنید.
- Schema را از قبل مشخص کنید تا تصمیمهای نوع و array در لحظه انجام شوند.
- شماره خط یا مسیر XPath عنصر مشکلدار را در گزارش خطا ثبت کنید.
بهترین روشهای تبدیل XML به JSON
- قرارداد نگاشت را مستند کنید: attribute، متن، array، namespace و null.
- XML را با Parser معتبر بخوانید: از Regex یا split برای Parse XML استفاده نکنید.
- امنیت Parser را تنظیم کنید: entity خارجی و DTD را کنترل کنید.
- نوع داده را با Schema تعیین کنید: از حدس تهاجمی پرهیز کنید.
- Arrayها را پایدار نگه دارید: فیلد چندمقداری همیشه array باشد.
- Namespace را آگاهانه حفظ یا حذف کنید: احتمال برخورد نام را بررسی کنید.
- Mixed content را سادهسازی نکنید: اگر ترتیب متن مهم است، مدل ترتیبی بسازید.
- برای فایل بزرگ Stream کنید: از ساخت DOM کامل پرهیز کنید.
- JSON خروجی را اعتبارسنجی کنید: Syntax و Schema مقصد را جداگانه بررسی کنید.
چکلیست قبل از استفاده از JSON خروجی
- آیا XML از نظر Syntax معتبر و well-formed است؟
- آیا external entity و DTD امن تنظیم شدهاند؟
- آیا Attributeها در خروجی حفظ شدهاند؟
- آیا Elementهای تکراری به array تبدیل شدهاند؟
- آیا فیلدهای array حتی با یک عضو نیز نوع پایدار دارند؟
- آیا null و String خالی از هم قابل تشخیصاند؟
- آیا namespaceها بدون برخورد نام مدیریت شدهاند؟
- آیا Number و Boolean فقط طبق Schema تبدیل شدهاند؟
- آیا mixed content و ترتیب فرزندان اهمیت دارند؟
- آیا متن فارسی با UTF-8 سالم است؟
- آیا JSON نهایی با Schema مقصد سازگار است؟
چه زمانی تبدیل XML به JSON اتلاف اطلاعات دارد؟
اگر attribute و element بدون قرارداد یکسان شوند، namespace حذف شود، mixed content به object ساده تبدیل شود یا نوع داده فقط حدس زده شود، بخشی از اطلاعات XML از بین میرود. همچنین تفاوت میان element خالی، element حذفشده و xsi:nil ممکن است محو شود.
برای round-trip قابلاعتماد، mapping باید در هر دو جهت ثابت باشد. نگهداری prefix attribute، کلید متن، URI namespace، نوعهای Schema و فهرست elementهای چندمقداری ضروری است.
جمعبندی تبدیل XML به JSON
تبدیل XML به JSON یک فرآیند نگاشت ساختاری است. Elementها به کلید و object، elementهای تکراری به array، attributeها به metadata قراردادی و متن به مقدار تبدیل میشوند. چالش اصلی در type inference، null، namespace، mixed content، ترتیب و امنیت Parser است. برای نتیجه پایدار، از XML parser استاندارد، Schema مشخص و قواعد نگاشت مستند استفاده کنید.
برای تبدیل سریع داده میتوانید از ابزار داخلی تبدیل XML به JSON استفاده کنید. پیش از تبدیل، اعتبارسنج XML خطاهای ساختاری ورودی را مشخص میکند و پس از تبدیل نیز اعتبارسنج JSON برای بررسی Syntax خروجی مناسب است.