الدالة json_encode تأخذ المعاملات التالية:
المعامل | تفاصيل |
value | القيمة المطلوب ترميزها، يمكن أن تكون من أي نوع عدا الموارد ويجب ترميز جميع بيانات السّلاسل UTF-8 النصيّة بصيغة |
options |
خيارات على شكل قناع بتي وهي:
ويوجد وصف لسلوك هذه الثوابت في صفحة JSON ثوابت |
depth | يحدد العمق الأقصى، ويجب أن يكون أكبر من الصّفر |
الدالة json_decode فتأخذ المعاملات التالية:
المعامل | تفاصيل |
json | السلسلة النصية المُراد فك ترميزها بصيغة فقط UTF-8 تعمل هذه الدّالّة مع سلاسل نصّيّة مُرمَّزة بترميز JSON |
assoc | تُحوَّل الكائنات المُعادة من الدالة إلى مصفوفات ترابطية عندما تكون قيمته TRUE |
options | خيارات لفك ترميز JSON على شكل قناع بتي يوجد خيار واحد مدعوم حاليًا وهو JSON_BIGINT_AS_STRING ويسمح بقلب الأعداد الصحيحة الكبيرة إلى سلاسل نصّيّة بدلًا من أعداد عشرية |
فك ترميز سلسلة نصية بصيغة JSON
تأخذ الدالة json_decode المعامل الأول على شكل سلسلة نصية مرمّزة بصيغة JSON وتحلله إلى متغير PHP، إذا كان كائن JSON هو مصفوفة فهي تعيد كائنًا من \stdClass إذا كان عنصر المستوى الأعلى في الكائن هو قاموس (dictionary) أو مصفوفة مفهرسة، وتعيد قيمًا عددية أو NULL
من أجل قيم عددية معينة مثل السلاسل النصية البسيطة "true" و"false" و"null"، وتعيد NULL
عند أي خطأ.
تعيد الشيفرة التالية كائنًا بما أنّ عنصر المستوى الأعلى في السلسلة النصية بصيغة JSON هو قاموس JSON:
$json_string = '{"name": "Jeff", "age": 20, "active": true, "colors": ["red", "blue"]}'; $object = json_decode($json_string); printf('Hello %s, You are %s years old.', $object->name, $object->age); // Hello Jeff, You are 20 years old.
تعيد الشيفرة التالية مصفوفة بما أنّ عنصر المستوى الأعلى في السلسلة النصية بصيغة JSON هو مصفوفةJSON:
$json_string = '["Jeff", 20, true, ["red", "blue"]]'; $array = json_decode($json_string); printf('Hello %s, You are %s years old.', $array[0], $array[1]);
يمكنك استخدام الدالة var_dump() للاطلاع على أنواع وقيم كل خاصيّة للكائن الذي فُكَّ ترميزه، فإذا استخدمناها للكائن $object
في مثالنا السابق:
var_dump($object);
يكون الخرج:
class stdClass#2 (4) { ["name"] => string(4) "Jeff" ["age"] => int(20) ["active"] => bool(true) ["colors"] => array(2) { [0] => string(3) "red" [1] => string(4) "blue" } }
ملاحظة: حُوِّلت أنواع المتغيرات في JSON إلى مكافئاتها في PHP.
نقوم بتمرير true
معاملًا ثانيًا للدالة json_decode()
لإرجاع مصفوفة ترابطية من كائنات JSON بدلًا من إرجاع كائن. مثال:
$json_string = '{"name": "Jeff", "age": 20, "active": true, "colors": ["red", "blue"]}'; $array = json_decode($json_string, true); var_dump($array);
خرج الشيفرة السابقة:
array(4) { ["name"] => string(4) "Jeff" ["age"] => int(20) ["active"] => bool(true) ["colors"] => array(2) { [0] => string(3) "red" [1] => string(4) "blue" } }
ليس للمعامل الثاني $assoc
تأثير إذا كان المتغير الذي سيُرجع ليس كائنًا.
ملاحظة: ستفقد التمييز بين مصفوفة فارغة وكائن فارغ إذا كنت تستخدم المعامل $assoc
، أي أنّ تنفيذ json_encode()
على الخرج المفكوك ترميزه مرةً ثانية سينتج بنية JSON مختلفة.
تعيد الدالة json_decode()
القيمة NULL
إذا كان عمق السلسلة النصية بصيغة JSON أكثر من 512 عنصر (20 عنصر في إصدارات PHP أقدم من 5.2.3 أو 128 في الإصدار 5.2.3) بالتعاود (recursion)، يمكن التحكم بهذا الحد في الإصدار 5.3 وما بعده باستخدام المعامل الثالث $depth
كما هو موضح في الدليل الرسمي للغة PHP:
تنفذ PHP مجموعة عليا من JSON كما ذُكر في RFC 4627 - سترمّز أيضًا وتفك ترميز الأنواع العددية وNULL
، تدعم RFC 4627 فقط هذه القيم عندما تكون متداخلة ضمن مصفوفة أو كائن. بالرغم من أن هذه المجموعة العليا متوافقة مع التعريف الموسع لنص JSON في RFC 7159 الأحدث (الذي يهدف إلى التفوق على RFC 4627) وECMA-404 وهذا قد يسبب مشاكل في قابلية التشغيل المتبادل مع محللات JSON التي تلتزم بدقة بالنوع RFC 4627 عند تشفير قيمة عددية.
يعني هذا أنّ السلسلة النصية البسيطة ستعدّ كائن JSON صحيح في PHP مثال:
$json = json_decode('"some string"', true); var_dump($json, json_last_error_msg());
الخرج:
string(11) "some string" string(8) "No error"
لكن السلاسل النصية البسيطة التي ليست في مصفوفة أو كائن ليست جزءًا من معيار RFC 4627، أي أن المتفحصات (checkers) على الإنترنت مثل JSLint وJSON Formatter & Validator التي تعمل بالنمط RFC 4627 ستعطيك خطأً.
المعامل الثالث للدالة json_decode()
هو $depth
يحدد العمق التعاودي (القيمة الافتراضية 512)، أي عدد الكائنات المتداخلة ضمن الكائن الأصلي الذي سيُفَك تشفيره.
المعامل الرابع $options
يقبل قيمة واحدة حاليًا وهي JSON_BIGINT_AS_STRING
، أي أنّ السلوك الافتراضي للدالة (مع عدم وجود هذا المعامل) يحول القيم الصحيحة الكبيرة إلى أعداد عشرية بدلًا من سلاسل نصية.
لا تُعدّ المتغيرات غير الصحيحة ذات الأحرف الكبيرة للكلمات true وfalse وnull دخلًا صحيحًا.
لدينا المثال التالي:
var_dump(json_decode('tRue'), json_last_error_msg()); var_dump(json_decode('tRUe'), json_last_error_msg()); var_dump(json_decode('tRUE'), json_last_error_msg()); var_dump(json_decode('TRUe'), json_last_error_msg()); var_dump(json_decode('TRUE'), json_last_error_msg()); var_dump(json_decode('true'), json_last_error_msg());
الخرج في الإصدار قبل PHP 5.6:
bool(true) string(8) "No error" bool(true) string(8) "No error" bool(true) string(8) "No error" bool(true) string(8) "No error" bool(true) string(8) "No error" bool(true) string(8) "No error"
أما في الإصدارات اللاحقة:
NULL string(12) "Syntax error" NULL string(12) "Syntax error" NULL string(12) "Syntax error" NULL string(12) "Syntax error" NULL string(12) "Syntax error" bool(true) string(8) "No error"
ينطبق الأمر أيضًا على false وnull.
لاحظ أنّ الدالة json_decode()
تُعيد NULL
إذا كان من غير الممكن تحويل السلسلة النصية.
// غير صحيحة json صيغة $json = "{'name': 'Jeff', 'age': 20 }" ; $person = json_decode($json); // null ملاحظة: محاولة الوصول إلى خاصيّة عنصر ليس كائنًا تُرجع echo $person->name; echo json_last_error(); # 4 (JSON_ERROR_SYNTAX) echo json_last_error_msg(); # unexpected character
ليس من الآمن أن نعتمد فقط على القيمة المُرجعة بأن تكون NULL
لاكتشاف الأخطاء، فمثلًا إذا كانت السلسلة النصية بصيغة JSON لا تتضمن شيء إلا "null" فإنّ الدالة json_decode()
ستُرجع null
حتى في حال عدم حدوث أخطاء.
ترميز سلسلة نصية بصيغة JSON
تحوّل الدالة json_encode مصفوفة PHP (أو كائن ينفذ الواجهة JsonSerializable
بدءًا من الإصدار PHP 5.4) إلى سلسلة نصية بترميز صيغة JSON وتعيدها، وفي حال الفشل تعيد FALSE.
$array = [ 'name' => 'Jeff', 'age' => 20, 'active' => true, 'colors' => ['red', 'blue'], 'values' => [0=>'foo', 3=>'bar'], ];
تُحوَّل عند الترميز أنواع بيانات PHP (السلاسل النصية والأعداد الصحيحة والقيم المنطقية) إلى مكافئاتها في JSON، وتُرمَّز المصفوفات الترابطية ككائنات JSON وعند الاستدعاء مع الوسطاء الافتراضيين تُرمَّز المصفوفات المفهرسة كمصفوفات JSON، ما لم تكن مفاتيح المصفوفة سلسلة عددية مستمرة تبدأ من الصفر، فعندها ستُرمَّز المصفوفة ككائن JSON.
echo json_encode($array);
الخرج:
{"name":"Jeff","age":20,"active":true,"colors":["red","blue"],"values":{"0":"foo","3":"bar"}}
الوسائط
بدءًا من الإصدار PHP 5.3 فإنّ المعامل الثاني للدالة json_encode
هو قناع بتي والذي يمكن أن يكون واحد أو أكثر من التالي، ويمكن دمجه كما هو الحال مع أي قناع بتي مع العامل الثنائي OR |
.
الإصدار PHP 5.3 ومابعده
JSON_FORCE_OBJECT: يفرض إنشاء كائن بدلًا من مصفوفة.
$array = ['Joel', 23, true, ['red', 'blue']]; echo json_encode($array); echo json_encode($array, JSON_FORCE_OBJECT);
الخرج:
["Joel",23,true,["red","blue"]] {"0":"Joel","1":23,"2":true,"3":{"0":"red","1":"blue"}}
JSON_HEX_TAG، JSONHEXAMP، JSON_HEX_APOS، JSON_HEX_QUOT.
تضمن الخيارات السابقة التحويلات التالية عند الترميز:
الثابت | الدخل | الخرج |
JSON_HEX_TAG | < | \u003C |
JSON_HEX_TAG | > | \u003E |
JSON_HEX_AMP | & | \u0026 |
JSON_HEX_APOS | ' | \u0027 |
JSON_HEX_QUOT | " | \u0022 |
$array = ["tag"=>"<>", "amp"=>"&", "apos"=>"'", "quot"=>"\""]; echo json_encode($array); echo json_encode($array, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
الخرج:
{"tag":"<>","amp":"&","apos":"'","quot":"\""} {"tag":"\u003C\u003E","amp":"\u0026","apos":"\u0027","quot":"\u0022"}
الإصدار PHP 5.3 ومابعده
JSON_NUMERIC_CHECK: يضمن تحويل السلاسل النصية العددية إلى أعداد صحيحة.
$array = ['23452', 23452]; echo json_encode($array); echo json_encode($array, JSON_NUMERIC_CHECK);
الخرج:
["23452",23452] [23452,23452]
الإصدار PHP 5.4 ومابعده
JSON_PRETTY_PRINT: يجعل صيغة JSON مقروءة بسهولة.
$array = ['a' => 1, 'b' => 2, 'c' => 3, 'd' => 4]; echo json_encode($array); echo json_encode($array, JSON_PRETTY_PRINT);
الخرج:
{"a":1,"b":2,"c":3,"d":4} { "a": 1, "b": 2, "c": 3, "d": 4 }
JSON_UNESCAPED_SLASHES: يضمّن هذا الخيار خطوط الهروب المائلة الأمامية /
في الخرج:
$array = ['filename' => 'example.txt', 'path' => '/full/path/to/file/']; echo json_encode($array); echo json_encode($array, JSON_UNESCAPED_SLASHES);
الخرج:
{"filename":"example.txt","path":"\/full\/path\/to\/file"} {"filename":"example.txt","path":"/full/path/to/file"}
JSON_UNESCAPED_UNICODE: يضمّن محارف بترميز UTF8 في الخرج بدلًا من السلاسل النصية بترميز يونيكود.
$blues = ["english"=>"blue", "norwegian"=>"blå", "german"=>"blau"]; echo json_encode($blues); echo json_encode($blues, JSON_UNESCAPED_UNICODE);
الخرج:
{"english":"blue","norwegian":"bl\u00e5","german":"blau"} {"english":"blue","norwegian":"blå","german":"blau"}
الإصدار PHP 5.5 ومابعده
JSON_PARTIAL_OUTPUT_ON_ERROR: يسمح بمتابعة الترميز حتى لو وُجدت بعض القيم غير قابلة للترميز.
$fp = fopen("foo.txt", "r"); $array = ["file"=>$fp, "name"=>"foo.txt"]; echo json_encode($array); // no output echo json_encode($array, JSON_PARTIAL_OUTPUT_ON_ERROR);
الخرج:
{"file":null,"name":"foo.txt"}
الإصدار PHP 5.6 ومابعده
JSON_PRESERVE_ZERO_FRACTION: يضمن ترميز الأعداد العشرية كأعداد عشرية دومًا.
$array = [5.0, 5.5]; echo json_encode($array); echo json_encode($array, JSON_PRESERVE_ZERO_FRACTION);
الخرج:
[5,5.5] [5.0,5.5]
الإصدار PHP 7.1 ومابعده
JSON_UNESCAPED_LINE_TERMINATORS: عندما يُستخدم مع JSON_UNESCAPED_UNICODE
يعود إلى سلوك إصدارات PHP القديمة ولا يتجاوز المحرف الفاصل للأسطر U+2028
والمحرف الفاصل للفقرات U+2029
. بالرغم من أن هذه المحارف صحيحة في JSON فهي غير صحيحة في جافاسكربت لذا فقد تغيّر السلوك الافتراضي للخيار JSON_UNESCAPED_UNICODE
في الإصدار PHP 7.1.
$array = ["line"=>"\xe2\x80\xa8", "paragraph"=>"\xe2\x80\xa9"]; echo json_encode($array, JSON_UNESCAPED_UNICODE); echo json_encode($array, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_LINE_TERMINATORS);
الخرج:
{"line":"\u2028","paragraph":"\u2029"} {"line":" ","paragraph":" "}
تنقيح أخطاء JSON
عندما تفشل إحدى الدالتين json_encode
أوjson_decode
في التحليل إلى السلسلة النصية المطلوبة فإنّها تعيد false
، ولا تنشر PHP أي أخطاء أو تحذيرات في هذه الحالة إنما تقع المسؤولية على المستخدم الذي يجب أن يستخدم الدالتين json_last_error() وjson_last_error_msg() للتحقق من حدوث أخطاء ومعالجتها وفق التطبيق (تنقيحها، عرض رسالة خطأ وغير ذلك).
يظهر المثال التالي خطأً مشهورًا عند العمل مع JSON وهو الفشل في ترميز/فك ترميز سلسلة نصية بصيغة JSON (بسبب تمرير سلسلة نصية بترميز UTF-8 غير صحيح مثلًا).
// غير صحيحة JSON سلسلة نصية بصيغة $jsonString = json_encode("{'Bad JSON':\xB1\x31}"); if (json_last_error() != JSON_ERROR_NONE) { printf("JSON Error: %s", json_last_error_msg()); } // JSON Error: Malformed UTF-8 characters, possibly incorrectly encoded
json_last_error_msg
تعيد هذه الدالة رسالة مقروءة من قبل الإنسان للخطأ الأخير الذي حدث عند محاولة ترميز/فك ترميز سلسلة نصية.
تعيد هذه الدالة دومًا سلسلة نصية حتى لو لم يحدث خطأ والرسالة الافتراضية في حال عدم حدوث خطأ هي No Error
، وتعيد false
إذا حدث خطأ ما (غير معروف).
يجب الحذر عند استخدام هذه الدالة في الحلقات لأنّه سيتم تجاوزها في كل حلقة، ويجب استخدامها فقط للحصول على الرسالة للعرض وليس لاستخدامها في تعليمات التحكم.
// لا تكتب هذه الشيفرة // لأن نتيجة الدالة سلسلة نصية true النتيجة دائمًا if (json_last_error_msg()){} // ممارسة سيئة if (json_last_error_msg() != "No Error"){} // (يمكنك كتابة هذا (اختبار العدد الصحيح مع إحدى الثوابت المعرفة مسبقًا if (json_last_error() != JSON_ERROR_NONE) { // لعرض رسالة فقط وليس للاختبار json_last_error_msg استخدمنا printf("JSON Error: %s", json_last_error_msg()); }
لم تكن هذه الدالة موجودة في الإصدارات السابقة للإصدار PHP 5.5. إليك تنفيذ الترقيع المتعدد (polyfill):
if (!function_exists('json_last_error_msg')) { function json_last_error_msg() { static $ERRORS = array( JSON_ERROR_NONE => 'No error', JSON_ERROR_DEPTH => 'Maximum stack depth exceeded', JSON_ERROR_STATE_MISMATCH => 'State mismatch (invalid or malformed JSON)', JSON_ERROR_CTRL_CHAR => 'Control character error, possibly incorrectly encoded', JSON_ERROR_SYNTAX => 'Syntax error', JSON_ERROR_UTF8 => 'Malformed UTF-8 characters, possibly incorrectly encoded' ); $error = json_last_error(); return isset($ERRORS[$error]) ? $ERRORS[$error] : 'Unknown error'; } }
json_last_error()
تعيد هذه الدالة عددًا صحيحًا مربوطًا بإحدى ثوابت PHP المعرفة مسبقًا.
الثابت | المعنى |
JSON_ERROR_NONE | لم يحدث أي خطأ |
JSON_ERROR_DEPTH | حدث تجاوز للحد الأقصى لعمق المكدس |
JSON_ERROR_STATE_MISMATCH | صيغة JSON غير صحيحة أو تالفة |
JSON_ERROR_CTRL_CHAR | خطأ محرف التحكم ربما مرمَّز بشكلٍ خاطئ |
JSON_ERROR_SYNTAX | خطأ في الصياغة (منذ الإصدار PHP 5.3.3) |
JSON_ERROR_UTF8 | محارف UTF-8 تالفة ربما مرمَّزة بشكلٍ خاطئ (منذ الإصدارPHP 5.5.0) |
JSON_ERROR_RECURSION | مرجع تعاودي أو أكثر في القيمة المطلوب ترميزها |
JSON_ERROR_INF_OR_NAN | قيمة غير رقمية أو لا نهائية في القيمة المطلوب ترميزها |
JSON_ERROR_UNSUPPORTED_TYPE | القيمة المُعطاة من نوع لا يمكن ترميزه |
استخدام الواجهة JsonSerializable في كائن
الإصدار PHP 5.4 وما بعده
قد تحتاج عند بناء واجهة برمجة التطبيقات REST (Representational state transfer) إلى تقليل بيانات كائن ليُمرَّر إلى تطبيق العميل، ولهذا الهدف يوضّح المثال التالي كيفية استخدام الواجهة JsonSerializable.
في هذا المثال يوسّع الصنف User
كائن DB model من تقنية ORM الافتراضية (تقنية ربط الكائنات بالعلاقات).
class User extends Model implements JsonSerializable { public $id; public $name; public $surname; public $username; public $password; public $email; public $date_created; public $date_edit; public $role; public $status; public function jsonSerialize() { return [ 'name' => $this->name, 'surname' => $this->surname, 'username' => $this->username ]; } }
نضيف تنفيذ JsonSerializable
للصنف بتوفير التابع jsonSerialize()
.
public function jsonSerialize()
الآن عند تمرير الكائن User
في وحدة تحكم التطبيق (controller) أو السكربت إلى الدالة json_encode()
ستحصل على مصفوفة معادة بصيغة JSON للتابع jsonSerialize()
بدلًا من الكائن بأكمله.
json_encode($User);
تعيد الشيفرة السابقة:
{"name":"John", "surname":"Doe", "username" : "TestJson"}
مثال قيم الخاصيات
سيقلل هذا كمية البيانات المُعادة من النقطة النهائية (endpoint) لواجهة برمجة التطبيقات RESTful ويسمح باستبعاد خاصيّات الكائن من تمثيل JSON.
استخدام الخاصيّات الخاصة والمحمية مع الدالة json_encode()
إذا أردت تجنّب استخدام JsonSerializable
فمن الممكن استخدام الخاصيّات الخاصة أو المحمية لإخفاء بيانات الصنف من خرج الدالة json_encode()
وعندها لا يحتاج الصنف إلى تنفيذ الواجهة JsonSerializable
.
ترمّز الدالة json_encode()
الخاصيّات العامة فقط من الصنف إلى صيغة JSON.
<?php class User { // الخاصيّات الخاصة تُستخدم فقط ضمن هذا الصنف private $id; private $date_created; private $date_edit; // الخاصيّات المستخدمة في الأصناف الموسّعة protected $password; protected $email; protected $role; protected $status; // مشاركة هذه الخاصيّات مع المستخدم النهائي public $name; public $surname; public $username; // هنا jsonSerialize() لا نحتاج لاستخدام } $theUser = new User(); var_dump(json_encode($theUser));
الخرج:
string(44) "{"name":null,"surname":null,"username":null}"
ترويسة JSON والرد المُعاد
نضيف في الشيفرة التالية ترويسة مع نوع المحتوى JSON:
<?php $result = array('menu1' => 'home', 'menu2' => 'code php', 'menu3' => 'about'); // json إرجاع الرد بصيغة header('Content-Type: application/json'); // تصريح الترويسة // الترميز echo json_encode($result, true); exit();
الترويسة موجودة لذا يتمكن التطبيق من اكتشاف ما البيانات المُعادة وكيف يجب معالجتها، ولا حظ أنّ ترويسة المحتوى هي فقط معلومات حول نوع البيانات المُعادة.
إذا كنت تستخدم UTF-8 يمكنك كتابة:
header("Content-Type: application/json;charset=utf-8");
مثال jQuery:
$.ajax({ url:'url_your_page_php_that_return_json' }).done(function(data){ console.table('json ',data); console.log('Menu1: ', data.menu1); });
إنشاء ملف XML باستخدام DomDocument
نحتاج لإنشاء ملف XML
باستخدام الصنف DOMDocument
إلى إنشاء كل الوسوم والخاصيّات باستخدام التابعين createElement()
وcreateAttribute()
اللذين ينشئان بنية XML
باستخدام التابع appendChild()
.
يتضمن المثال التالي وسوم وخاصيات وقسم CDATA (Character Data) وفضاء اسم مختلف للوسم الثاني:
$dom = new DOMDocument('1.0', 'utf-8'); $dom->preserveWhiteSpace = false; $dom->formatOutput = true; // إنشاء الوسوم الأساسية دون القيم $books = $dom->createElement('books'); $book_1 = $dom->createElement('book'); // إنشاء بعض الوسوم مع قيم $name_1 = $dom->createElement('name', 'PHP - An Introduction'); $price_1 = $dom->createElement('price', '$5.95'); $id_1 = $dom->createElement('id', '1'); // إنشاء وإضافة خاصية $attr_1 = $dom->createAttribute('version'); $attr_1->value = '1.0'; // إضافة الخاصية $id_1->appendChild($attr_1); // الثاني بفضاء اسم مختلف book إنشاء $namespace = 'www.example.com/libraryns/1.0'; // books تضمين بادئة فضاء الاسم في الوسم $books->setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:ns', $namespace); $book_2 = $dom->createElementNS($namespace,'ns:book'); $name_2 = $dom->createElementNS($namespace, 'ns:name'); // name أخرى ووضعه ضمن الوسم DOMNode الذي هو نسخة CDATA إنشاء قسم $name_cdata = $dom->createCDATASection('PHP - Advanced'); $name_2->appendChild($name_cdata); $price_2 = $dom->createElementNS($namespace, 'ns:price', '$25.00'); $id_2 = $dom->createElementNS($namespace, 'ns:id', '2'); // XML إنشاء ملف $books->appendChild($book_1); $book_1->appendChild($name_1); $book_1->appendChild($price_1); $book_1->appendChild($id_1); $books->appendChild($book_2); $book_2->appendChild($name_2); $book_2->appendChild($price_2); $book_2->appendChild($id_2); $dom->appendChild($books); // في سلسلة نصية XML ملف saveXML() يعيد التابع print_r ($dom->saveXML());
ستنتج الشيفرة السابقة ملف XML
التالي:
<?xml version="1.0" encoding="utf-8"?> <books xmlns:ns="www.example.com/libraryns/1.0"> <book> <name>PHP - An Introduction</name> <price>$5.95</price> <id version="1.0">1</id> </book> <ns:book> <ns:name><![CDATA[PHP - Advanced]]></ns:name> <ns:price>$25.00</ns:price> <ns:id>2</ns:id> </ns:book> </books>
قراءة ملف XML باستخدام DOMDocument
يمكن استخدام الصنف DOMDocument
بطريقة مشابهة لاستخدام SimpleXML
لتحليل XML
من سلسلة نصية أو من ملف XML
.
- من سلسلة نصية:
$doc = new DOMDocument(); $doc->loadXML($string);
- من ملف:
$doc = new DOMDocument(); // استخدم مسار الملف الفعلي النسبي أو المطلق $doc->load('books.xml');
مثال عن التحليل: بفرض لدينا صيغة XML
التالية:
<?xml version="1.0" encoding="UTF-8"?> <books> <book> <name>PHP - An Introduction</name> <price>$5.95</price> <id>1</id> </book> <book> <name>PHP - Advanced</name> <price>$25.00</price> <id>2</id> </book> </books>
هذا مثال شيفرة لتحليل الصيغة السابقة:
$books = $doc->getElementsByTagName('book'); foreach ($books as $book) { $title = $book->getElementsByTagName('name')->item(0)->nodeValue; $price = $book->getElementsByTagName('price')->item(0)->nodeValue; $id = $book->getElementsByTagName('id')->item(0)->nodeValue; print_r ("The title of the book $id is $title and it costs $price." . "\n"); }
سينتج عنها الخرج التالي:
The title of the book 1 is PHP - An Introduction and it costs $5.95. The title of the book 2 is PHP - Advanced and it costs $25.00.
الاستفادة من XML مع مكتبة SimpleXML في PHP
تعد SimpleXML
مكتبة قوية تحوّل السلاسل النصية بصيغة XML
إلى صيغة سهلة لاستخدام كائن PHP.
بفرض لدينا بنية XML التالية:
<?xml version="1.0" encoding="UTF-8"?> <document> <book> <bookName>StackOverflow SimpleXML Example</bookName> <bookAuthor>PHP Programmer</bookAuthor> </book> <book> <bookName>Another SimpleXML Example</bookName> <bookAuthor>Stack Overflow Community</bookAuthor> <bookAuthor>PHP Programmer</bookAuthor> <bookAuthor>FooBar</bookAuthor> </book> </document>
قراءة بياناتنا في SimpleXML
نحتاج بدايةً إلى قراءة بياناتنا في SimpleXML
، يمكننا ذلك باستخدام 3 طرق مختلفة. يمكننا أولًا تحميل البيانات من عقدة DOM.
$xmlElement = simplexml_import_dom($domNode);
الخيار الثاني لدينا هو تحميل البيانات من ملف XML.
$xmlElement = simplexml_load_file($filename);
أخيرًا يمكننا تحميل البيانات من متغير.
$xmlString = '<?xml version="1.0" encoding="UTF-8"?> <document> <book> <bookName>StackOverflow SimpleXML Example</bookName> <bookAuthor>PHP Programmer</bookAuthor> </book> <book> <bookName>Another SimpleXML Example</bookName> <bookAuthor>Stack Overflow Community</bookAuthor> <bookAuthor>PHP Programmer</bookAuthor> <bookAuthor>FooBar</bookAuthor> </book> </document>'; $xmlElement = simplexml_load_string($xmlString);
سواء اخترنا التحميل من عنصر DOM أو من ملف أو من سلسلة نصية ستحصل على متغير من الصنف SimpleXMLElement
يدعى $xmlElement
ويمكننا الآن البدء باستخدام XML في PHP.
الوصول إلى بيانات SimpleXML
أسهل طريقة للوصول إلى البيانات في عنصر SimpleXMLElement
هي استدعاء الخاصيّات مباشرةً، يمكننا الوصول إلى bookName
كما يلي:
echo $xmlElement->book->bookName;
تفترض SimpleXML
عند هذه النقطة أننا نريد الكتاب الأول لأننا لم نذكر بشكلٍ صريح أي كتاب نريده، ويمكننا اختيار كتاب غير الكتاب الأول بالطريقة التالية:
echo $xmlElement->book[1]->bookName;
ويجب ملاحظة أنّ استخدام [0]
يكافئ عدم استخدام شيء أي أنّ:
$xmlElement->book
تعمل نفس عمل:
$xmlElement->book[0]
تمرير حلقة عبر XML
يوجد عدة أسباب لرغبتك في تكرار حلقة عبر XML مثل أن يكون عندك عدد كبير من العناصر، الكتب في مثالنا، تريد عرضه في صفحة ويب، عندها يمكنك استخدام حلقة foreach أوحلقة for المعيارية مستفيدين من إيجابيات دالة SimpleXMLElement للعد.
foreach ( $xmlElement->book as $thisBook ) { echo $thisBook->bookName }
أو
$count = $xmlElement->count(); for ( $i=0; $i<$count; $i++ ) { echo $xmlElement->book[$i]->bookName; }
معالجة الأخطاء
وصلنا الآن إلى النهاية ومن المهم أن ندرك أننا نخطئ كبشر ومن المحتمل أن نواجه أخطاء خاصةً إذا كنا نتعامل مع ملفات XML
مختلفة لذا نريد معالجة هذه الأخطاء.
بفرض أننا أنشأنا ملف XML
ستلاحظ إذا كان هذا الملف يشبه الملف الذي أنشأناه سابقًا ستكون فيه مشكلة وهي أنّ وسم الإغلاق /doc
بدلًا من /document
.
<?xml version="1.0" encoding="UTF-8"?> <document> <book> <bookName>StackOverflow SimpleXML Example</bookName> <bookAuthor>PHP Programmer</bookAuthor> </book> <book> <bookName>Another SimpleXML Example</bookName> <bookAuthor>Stack Overflow Community</bookAuthor> <bookAuthor>PHP Programmer</bookAuthor> <bookAuthor>FooBar</bookAuthor> </book> </doc>
بفرض أننا حمّلناه ضمن شيفرة PHP كمتغير $file
.
libxml_use_internal_errors(true); $xmlElement = simplexml_load_file($file); if ( $xmlElement === false ) { $errors = libxml_get_errors(); foreach ( $errors as $thisError ) { switch ( $thisError->level ) { case LIBXML_ERR_FATAL: echo "FATAL ERROR: "; break; case LIBXML_ERR_ERROR: echo "Non Fatal Error: "; break; case LIBXML_ERR_WARNING: echo "Warning: "; break; } echo $thisError->code . PHP_EOL . 'Message: ' . $thisError->message . PHP_EOL . 'Line: ' . $thisError->line . PHP_EOL . 'Column: ' . $thisError->column . PHP_EOL . 'File: ' . $thisError->file; } libxml_clear_errors(); } else { echo 'Happy Days'; }
ستكون النتيجة:
FATAL ERROR: 76 Message: Opening and ending tag mismatch: document line 2 and doc Line: 13 Column: 10 File: filepath/filename.xml
لكن بمجرد حل هذه المشكلة سنرى الخرج "Happy Days".
إنشاء ملف XML باستخدام الصنف XMLWriter
ننشئ نسخة كائن XMLWriter
:
$xml = new XMLWriter();
ثم نفتح الملف الذي نريد الكتابة فيه فمثلًا إذا أردنا الكتابة في /var/www/example.com/xml/output.xml
نكتب:
$xml->openUri('file:///var/www/example.com/xml/output.xml');
نكتب الشيفرة التالية للبدء بالملف (إنشاء وسم بداية ملف XML
):
$xml->startDocument('1.0', 'utf-8');
ستؤدي إلى الخرج:
<?xml version="1.0" encoding="UTF-8"?>
يمكننا الآن البدء بكتابة العناصر:
$xml->writeElement('foo', 'bar');
سينتج XML
التالي:
<foo>bar</foo>
إذا كنت تحتاج شيئًا أكثر تعقيدًا من العقد البسيطة والقيم الواضحة يمكنك أن تبدأ عنصر وتضيف خاصيّات إليه قبل إنهائه:
$xml->startElement('foo'); $xml->writeAttribute('bar', 'baz'); $xml->writeCdata('Lorem ipsum'); $xml->endElement();
سينتج الخرج التالي:
<foo bar="baz"><![CDATA[Lorem ipsum]]></foo>
قراءة ملف XML باستخدام SimpleXML
يمكنك تحليل XML
من سلسلة نصية أو من ملف XML
.
- من سلسلة نصية:
$xml_obj = simplexml_load_string($string);
- من ملف:
$xml_obj = simplexml_load_file('books.xml');
مثال عن التحليل:
بفرض لدينا ملف XML
التالي:
<?xml version="1.0" encoding="UTF-8"?> <books> <book> <name>PHP - An Introduction</name> <price>$5.95</price> <id>1</id> </book> <book> <name>PHP - Advanced</name> <price>$25.00</price> <id>2</id> </book> </books>
هذا مثال شيفرة لتحليله:
$xml = simplexml_load_string($xml_string); $books = $xml->book; foreach ($books as $book) { $id = $book->id; $title = $book->name; $price = $book->price; print_r ("The title of the book $id is $title and it costs $price." . "\n"); }
سينتج عنها الخرج التالي:
The title of the book 1 is PHP - An Introduction and it costs $5.95. The title of the book 2 is PHP - Advanced and it costs $25.00.
مكتبة SimpleXML
تحميل بيانات XML إلى simplexml
التحميل من سلسلة نصية
نستخدم simplexml_load_string
لإنشاء SimpleXMLElement
من سلسلة نصية:
$xmlString = "<?xml version='1.0' encoding='UTF-8'?>"; $xml = simplexml_load_string($xmlString) or die("Error: Cannot create object");
لاحظ أنّه يجب استخدام or
وليس ||
لأنّ أولوية or
أعلى من =
، وستُنفَّذ الشيفرة بعد or
فقط إذا كانت نتيجة $xml
هي false
.
التحميل من ملف نستخدم simplexml_load_file
لتحميل بيانات XML
من ملف أو رابط:
$xml = simplexml_load_string("filePath.xml"); $xml = simplexml_load_string("https://example.com/doc.xml");
يمكن أن يكون الرابط من أي مخطط تدعمه PHP ?أو مُغلِّف مجرى مخصص.
تحليل HTML
تحليل HTML من سلسلة نصية
تنفّذ PHP محللًا متوافقًا مع DOM المستوى 2 مما يسمح لنا بالعمل مع HTML باستخدام التوابع المعروفة مثل getElementById()
أوappendChild()
.
$html = '<html><body><span id="text">Hello, World!</span></body></html>'; $doc = new DOMDocument(); libxml_use_internal_errors(true); $doc->loadHTML($html); echo $doc->getElementById("text")->textContent;
الخرج:
Hello, World!
لاحظ أنّ PHP ستصدر تحذيرات بشأن مشاكل HTML التي قد تحدث، خاصةً إذا كنت تستورد جزء من ملف، لتجنب هذه التحذيرات نخبر مكتبة DOM (libxml) أن تعالج أخطائها قبل استيراد HTML باستدعاء libxml_use_internal_errors()، ويمكنك بعدها استخدام libxml_get_errors() لمعالجة الأخطاء عند الحاجة.
استخدام XPath
$html = '<html><body><span class="text">Hello, World!</span></body></html>'; $doc = new DOMDocument(); $doc->loadHTML($html); $xpath = new DOMXPath($doc); $span = $xpath->query("//span[@class='text']")->item(0); echo $span->textContent;
الخرج:
Hello, World!
SimpleXML
SimpleXML
هي مكتبة PHP توفر طريقة سهلة للتعامل مع ملفات XML
(خاصةً القراءة والتكرار عبر بيانات XML
)، القيد الوحيد هو أنّ ملف XML
يجب أن يكون مُصاغ جيدًا (well-formed).
تحليل XML باستخدام المنهجية الإجرائية
// XML تحميل سلسلة نصية $xmlstr = file_get_contents('library.xml'); $library = simplexml_load_string($xmlstr); // XML تحميل ملف $library = simplexml_load_file('library.xml');
لتحميل ملف XML
يمكنك كتابة مسار الملف المحلي أو رابط صالح إذا كان الإعداد allow_url_fopen
مضبوطًا إلى "On" في php.ini.
تحليل XML باستخدام المنهجية الكائنية التوجه
// XML تحميل سلسلة نصية $xmlstr = file_get_contents('library.xml'); $library = new SimpleXMLElement($xmlstr); // XML تحميل ملف $library = new SimpleXMLElement('library.xml', NULL, true);
الوصول إلى الأبناء والخاصيّات
عندما تحلل SimpleXML
ملف XML
تحوّل كل عناصر XML
فيه، أو العقد، إلى خاصيّات لكائن SimpleXMLElement
ناتج، وتحوّل خاصيّات XML
إلى مصفوفة ترابطية يمكن الوصول إليها من الخاصيّة التي تعود لها.
- عندما تعرف أسمائهم:
$library = new SimpleXMLElement('library.xml', NULL, true); foreach ($library->book as $book){ echo $book['isbn']; echo $book->title; echo $book->author; echo $book->publisher; }
العيب الأساسي لهذه المنهجية أنّه من الضروري معرفة اسم كل عنصر وخاصية في ملف XML.
- عندما لا تعرف أسمائهم (أو لا تريد معرفتهم):
foreach ($library->children() as $child){ echo $child->getName(); // الحصول على خاصيّات هذا العنصر foreach ($child->attributes() as $attr){ echo ' ' . $attr->getName() . ': ' . $attr; } // الحصول على الأبناء foreach ($child->children() as $subchild){ echo ' ' . $subchild->getName() . ': ' . $subchild; } }
ترجمة -وبتصرف- للفصول [JSON - XML - SimpleXML - Parsing HTML] من كتاب PHP Notes for Professionals book
اقرأ أيضًا
- المقال التالي: الأصناف (Classes) والكائنات (Objects) في PHP
- المقال السابق: تنسيق النصوص وتحليلها في PHP
أفضل التعليقات
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.