العمل مع XML في C++: مكتبات PugiXML وRapidXML
XML (لغة الترميز القابلة للامتداد) لا يزال أحد التنسيقات الرئيسية لتخزين ونقل البيانات المنظمة. في لغة C++، توجد عدة مكتبات قوية للعمل مع XML، من أبرزها PugiXML (خفيفة الوزن، مع دعم XPath) وRapidXML (سريعة للغاية، تعمل "في المكان"). في هذه المقالة، سنستعرض كلتا المكتبتين، وميزاتهما، وطريقة تثبيتهما، وأمثلة عملية.
1. PugiXML — أداة متعددة الاستخدامات
PugiXML هي مكتبة خفيفة الوزن، متعددة المنصات، تدعم XPath 1.0 وترميزات UTF-8/UTF-16. وهي مثالية لمعظم المهام: من قراءة ملفات التكوين إلى التحليل المعقد لمستندات XML.
التثبيت
قم بتنزيل ملفات الرأس (header files) من الموقع الرسمي أو استخدم مدير الحزم (vcpkg, Conan). قم بتضمينها في المشروع:
#include "pugixml.hpp"using namespace pugi;مثال: تحميل وقراءة XML
#include <iostream>#include "pugixml.hpp"
int main() { xml_document doc; if (!doc.load_file("config.xml")) { std::cerr << "خطأ في تحميل الملف"; return -1; }
// الحصول على العنصر الجذر xml_node root = doc.child("settings"); for (xml_node node = root.child("param"); node; node = node.next_sibling("param")) { std::string name = node.attribute("name").as_string(); int value = node.attribute("value").as_int(); std::cout << "المعامل: " << name << " = " << value << ""; } return 0;}مثال: إنشاء مستند XML
xml_document doc;xml_node root = doc.append_child("catalog");for (int i = 1; i <= 3; ++i) { xml_node item = root.append_child("item"); item.append_attribute("id") = i; item.append_child("name").text() = ("المنتج " + std::to_string(i)).c_str(); item.append_child("price").text() = 100.0 * i;}doc.save_file("catalog.xml");مزايا PugiXML:
- دعم XPath للاستعلامات المعقدة (مثل:
doc.select_nodes("//item[@id>1]")). - التعامل مع الترميزات وUnicode.
- توثيق مفصل ومجتمع نشط.
2. RapidXML — السرعة والبساطة
RapidXML هي مكتبة تعتمد فقط على ملفات الرأس (header-only)، تقوم بتحليل XML دون نسخ البيانات (in-place). تعمل بشكل أسرع بكثير من PugiXML، لكنها لا تدعم XPath وتتطلب الحذر فيما يتعلق بعمر السلاسل النصية.
التثبيت
انسخ rapidxml.hpp والملفات الإضافية (rapidxml_utils.hpp, rapidxml_print.hpp) إلى المشروع.
مثال: تحليل سلسلة نصية
#include <iostream>#include "rapidxml.hpp"
int main() { char xml[] = "<root><item id='1'>قيمة</item></root>"; rapidxml::xml_document<> doc; doc.parse<0>(xml); // 0 — أعلام التحليل
rapidxml::xml_node<>* root = doc.first_node("root"); rapidxml::xml_node<>* item = root->first_node("item"); if (item) { std::cout << "المعرف: " << item->first_attribute("id")->value() << ""; std::cout << "المحتوى: " << item->value() << ""; } return 0;}مثال: إنشاء XML
rapidxml::xml_document<> doc;rapidxml::xml_node<>* root = doc.allocate_node(rapidxml::node_element, "data");doc.append_node(root);
rapidxml::xml_node<>* child = doc.allocate_node(rapidxml::node_element, "value", "42");root->append_node(child);
// الإخراج إلى سلسلة نصيةstd::string result;rapidxml::print(std::back_inserter(result), doc);std::cout << result;هام: