تابع xml_set_end_namespace_decl_handler() در PHP
در پردازش XML در PHP، گاهی نیاز داریم اطلاعات مربوط به اعلامیههای namespace (مثلاً xmlns یا xmlns:prefix) را ردیابی کنیم تا بدانیم هر پیشوند (prefix) به چه URI نگاشته شده و چه زمانی این نگاشتن از حوزه (scope) خارج میشود. تابع xml_set_end_namespace_decl_handler() به ما اجازه میدهد یک تابع بازگشتی (callback) ثبت کنیم که هنگام پایان یک اعلامیه namespace فراخوانی شود.
کاربرد کلی و چه زمانی به آن نیاز داریم
- مدیریت و نگهداری نگاشت prefix → URI هنگام پیمایش درخت XML.
- پاکسازی (pop) نگاشت namespace هنگام خروج از عنصر (end element) که آن namespace را اعلام کرده بود.
- زمانی که از تجزیهگر سطح پایین (Expat via xml_parse) استفاده میکنیم و میخواهیم کنترل دقیقی برscope نامفضاها داشته باشیم.
امضای تابع و نکات فنی
| تابع | شرح |
|---|---|
| xml_set_end_namespace_decl_handler(resource $parser, callable $handler) | ثبت handler که هنگام پایان یک namespace فراخوانی میشود. بازگرداندن مقدار بولی (true/false) برای موفقیت در ثبت. |
Callback معمولاً دو پارامتر دریافت میکند: منبع پارسر ($parser) و prefix (رشته). اگر namespace پیشفرض (default namespace) تمام شود، مقدار prefix ممکن است رشته خالی (“”) باشد. برای دریافت URI هنگام شروع اعلام namespace باید از handler شروع namespace (xml_set_start_namespace_decl_handler) استفاده کنید که URI را نیز در اختیار میگذارد.
مثال ساده: ثبت و حذف نگاشت namespace
<?php
$xml = '
<ns:child>Some text</ns:child>
</root>';
$parser = xml_parser_create();
// ساختار سادهای برای نگهداری نگاشتها
$nsStack = [];
function startNS($parser, $prefix, $uri) {
global $nsStack;
// ذخیره نگاشت به صورت stack برای مدیریت scope
$nsStack[] = ['prefix' => $prefix, 'uri' => $uri];
echo "Start namespace: prefix='{$prefix}', uri='{$uri}'n";
}
function endNS($parser, $prefix) {
global $nsStack;
// حذف آخرین نگاشت با همان prefix (نحوه ساده: pop)
$entry = array_pop($nsStack);
echo "End namespace: prefix='{$prefix}' (popped)n";
}
xml_set_start_namespace_decl_handler($parser, 'startNS');
xml_set_end_namespace_decl_handler($parser, 'endNS');
if (!xml_parse($parser, $xml, true)) {
printf("XML error: %s at line %dn",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser));
}
xml_parser_free($parser);
?>شرح: این مثال یک رشته XML ساده را تجزیه میکند. در startNS نگاشت prefix→URI داخل یک آرایه استک ذخیره میشود و در endNS هنگام خاتمه اعلام namespace آن را از استک حذف میکنیم. این روش ساده نشان میدهد که چگونه میتوان scope نامفضاها را مدیریت کرد.
نکات عملی و بهبودها
- در مثال بالا استفاده از array_pop ممکن است اگر چند اعلامیه با یک prefix در عمقهای مختلف داشته باشیم نیاز به بهبود داشته باشد. بهتر است هنگام pop بررسی کنید که prefix تطابق دارد یا نگاشت را تا پیدا شدن مورد مناسب حذف کنید.
- در پروژههای پیچیده بهتر است از ساختار stack که شامل شمارنده سطوح یا نگاشتهای تو در تو است استفاده کنید تا به درستی تکرارهای یک prefix مدیریت شوند.
- اگر ترجیح میدهید که نامفضاها بهصورت خودکار به نام عنصر الصاق شوند، میتوانید از xml_parser_create_ns() استفاده کنید که URI و نام محلی را با یک جداکننده ترکیب میکند (مثلاً “uri|localname”). این باعث سادهتر شدن پردازش نامهای عنصر میشود.
نمونه با مدیریت دقیقتر استک
<?php
$xml = '...'; // همان XML
$parser = xml_parser_create();
$nsStack = [];
function startNS2($parser, $prefix, $uri) {
global $nsStack;
// نگاشتها را به صورت چندتایی برای هر prefix نگه میداریم
if (!isset($nsStack[$prefix])) $nsStack[$prefix] = [];
$nsStack[$prefix][] = $uri;
echo "StartNS2: {$prefix} => {$uri}n";
}
function endNS2($parser, $prefix) {
global $nsStack;
if (isset($nsStack[$prefix]) && count($nsStack[$prefix]) > 0) {
$uri = array_pop($nsStack[$prefix]);
echo "EndNS2: {$prefix} (removed {$uri})n";
if (count($nsStack[$prefix]) === 0) unset($nsStack[$prefix]);
} else {
echo "EndNS2: {$prefix} (no entry)n";
}
}
xml_set_start_namespace_decl_handler($parser, 'startNS2');
xml_set_end_namespace_decl_handler($parser, 'endNS2');
xml_parse($parser, $xml, true);
xml_parser_free($parser);
?>شرح: این پیادهسازی به ازای هر prefix یک پشته URI نگهداری میکند تا در صورت تودرتو بودن اعلامیهها، بازگردانی درست انجام شود.
نکات کلیدی و بهترین شیوهها
- xml_set_end_namespace_decl_handler تنها در سطح تابعی (low-level) معنیدار است؛ در بسیاری از موارد کار با DOM یا SimpleXML سادهتر و کافی است.
- اطمینان حاصل کنید که اکستنشن XML (Expat) در PHP فعال است؛ در غیر این صورت این توابع در دسترس نخواهند بود.
- همیشه پس از پایان کار xml_parser_free را فراخوانی کنید تا منابع آزاد شوند.
- برای سازگاری بهتر با نامفضاها و دریافت URIها در نام عناصر، xml_parser_create_ns را بررسی کنید — این متد نامها را با جداکننده مشخص به شما میدهد و ممکن است نیاز به ردیابی دستی namespace را کاهش دهد.
چرا این ابزار مفید است؟
اگر در حال پیادهسازی یک پردازشگر XML اختصاصی، مبدل XML به فرمت دلخواه، یا موتور اعتبارسنجی سطح پایین هستید که نیازمند آگاهی از تغییرات زمینه (scope) نامفضاهاست، استفاده از start/end namespace handlers به شما امکان میدهد کنترل دقیق و کارآمدی روی آنها داشته باشید. مخصوصاً در اسناد با تودرتوی زیاد و اعلامیههای متعدد namespace، ردیابی صحیح scope برای تولید خروجی درست یا نگاشت عناصر ضروری است.
جمعبندی
تابع xml_set_end_namespace_decl_handler() یک ابزار ساده اما قدرتمند برای آگاه شدن از خاتمه scope یک namespace است. همراه با تابع شروع namespace و مدیریت درست یک استک یا نگاشت چندتایی میتوانید کنترل کاملی روی نگاشت prefix→URI داشته باشید. در پروژههای ساده استفاده از DOM/SimpleXML راحتتر است، اما برای پردازشهای حساس و performative، این توابع سطح پایین گزینه مناسبی هستند.
آیا این مطلب برای شما مفید بود ؟



