ترتب HotXLS عناصر PivotTable حسب القيمة داخل Delphi عبر خاصيتين على TXLSPivotField: ينتقي SortType تصاعدياً أو تنازلياً، ويسمي SortDataField حقل البيانات ذا الأساس الصفري الذي تقود مجاميعه الترتيب. وعندما تفتح HotXLS ملف XLSX من تأليف Excel تستعيد ذلك حقل البيانات من عنصر autoSortScope، حيث يخزن Excel حقل Values بوصفه field="4294967294"، الصياغة غير الموقعة للـ -2
الترتيب حسب القيمة هو الطلب الذي ينتهي إليه كل تقرير مبيعات: «أرني المناطق من الأكبر إلى الأصغر». في واجهة Excel إنه نقرتان. وفي صيغة الملف إنه سمة، ومنطقة pivot متداخلة، وفهرس حقل محجوز، وترتيبي لحقل بيانات منتقى، والقارئ الذي يفوّت أي قطعة منها يفتح الملف دون شكوى مع ذلك. إنه فقط يرتب حسب الشيء الخطأ
أين يخزن Excel قياس الترتيب حسب القيمة؟
يخزن Excel قياس الترتيب داخل autoSortScope فقط، لا على الحقل نفسه. سمة sortType على <pivotField> (قيمة ST_FieldSortType من ECMA-376 Part 1: manual أو ascending أو descending) تقول أي اتجاه يُرتب. أما أي قياس يُرتب به فيسكن ابن <autoSortScope> الذي يلف <pivotArea> ينقي مرجع محور البيانات التابع لها حقلاً واحداً للبيانات
<pivotField axis="axisRow" showAll="0" sortType="descending">
<items count="5"> ... </items>
<autoSortScope>
<pivotArea dataOnly="0" outlineLevel="all" fieldPosition="0">
<references count="1">
<reference field="4294967294" count="1" selected="0">
<x v="0"/>
</reference>
</references>
</pivotArea>
</autoSortScope>
</pivotField>
يشير عنصر reference عادةً إلى حقل pivot بفهرس. فهرس الحقل -2 محجوز في جزء PivotTable من ECMA-376 للحقل الزائف Values، الذي تعرضه Excel بوصفه «Values» عندما يجلس قياسان أو أكثر على محور. السمة معرَّفة عدداً صحيحاً غير موقع من 32 بتاً، فـ -2 يسير على السلك 4294967294. وينتقي <x v="0"/> تحته حقل البيانات 0، أول مدخل في <dataFields>. وهناك أيضاً سمة rankBy على <pivotField>، لكن في الملفات التي قارنّاها تركتها Excel واعتمدت على النطاق وحده
لماذا عاد قياس الترتيب بوصفه -1؟
فقد قارئ HotXLS أصلاً قياس الترتيب لأن 4294967294 لا تتسع في عدد صحيح موقع من 32 بتاً. مساعد السمات غلاف رقيق فوق StrToIntDef، والقيمة خارج المدى تعيد الافتراضي بصمت، فلم يطابق اختبار محور البيانات قط، وبقي SortDataField عند -1، واحتفظ الحقل بـ sortType="descending" وحدها دون قياس مرفق
كان الفشل هادئاً بأسوأ طريقة. الحقل التنازلي دون قياس ما يزال يرتب، فقط حسب تسمية العنصر بالعكس، فتقرير رتبته Excel حسب المجموع عاد من HotXLS بترتيب العناصر معكوساً. لم يرفع شيء استثناء وكانت الأعداد في كل خلية صحيحة. كان ترتيب الصفوف وحده خاطئاً، وفي ملفات من تأليف Excel فقط
يقارن الإصلاح في lxPivotXml.pas رمز السمة الخام بوصفه سلسلة قبل أي تحويل صحيح. إن كانت rankBy قد ضبطت قياساً فهي تغلب؛ وإلا فمرجع يكون رمز field فيه '4294967294' بالضبط يحل SortDataField من قيمة x المنتقاة له. لم يحتج جانب التقييم إلى تغيير: كان المقارن ينهي مجاميع كل عضو على محوري الصفوف والأعمدة أصلاً، ويعالج الترتيب التنازلي ويفصل التعادلات. البيانات ببساطة لم تكن تصل إليه قط
ينطبق الدرس العام على أي قارئ OOXML مكتوب في ديلفي. تصف ECMA-376 عدة سمات فهارس بوصفها xsd:unsignedInt ثم تستخدم قمة المدى حارساً، فالقارئ الموقع ذو المسار البديل الافتراضي يحول قيمة محجوزة إلى «سمة مفقودة». قارن الرمز، أو حلل إلى Int64 أو Cardinal، في كل موضع قد يعني فيه فهرس حقل Values
ترتيب عناصر pivot حسب قياس من كود Delphi
لترتيب حقل pivot في HotXLS حسب القيمة، اضبط SortType على xlpfstAscending أو xlpfstDescending واضبط SortDataField على فهرس القياس ذي الأساس الصفري في قائمة DataFields للجدول. ومع SortType = xlpfstManual، وهو الافتراضي، يُتجاهل SortDataField وتحفظ العناصر ترتيب مخزنها المؤقت أو البرمجي
uses
SysUtils, lxHandleX, lxPivot;
var
Book: TXLSXWorkbook;
Data, Report: TXLSXWorksheet;
Pivot: TXLSPivotTable;
Region: TXLSPivotField;
begin
Book := TXLSXWorkbook.Create;
try
Data := Book.Sheets.Add('Data');
Data.Cells[1, 1].Value := 'Region';
Data.Cells[1, 2].Value := 'Product';
Data.Cells[1, 3].Value := 'Units';
// ... املأ الصفوف 2..41 ...
Report := Book.Sheets.Add('Report');
Pivot := Report.AddPivotTable('Data!A1:C41', 3, 1, 'UnitsByRegion');
Region := Pivot.AddRowField('Region');
Pivot.AddDataFieldByName('Units', xlpaSum); // حقل البيانات 0
Region.SortType := xlpfstDescending; // المنطقة الأكبر أولاً
Region.SortDataField := 0; // ترتيب حسب مجموع Units
Region.AutoSortScope := '0'; // بث autoSortScope الخاص بـ Excel أيضاً
if Book.MaterializeNativePivotTable(Pivot) <> 1 then
raise Exception.Create('Pivot layout was rejected');
Book.SaveAs('units-by-region.xlsx');
finally
Book.Free;
end;
end;
تفصيلان يستحقان ملاحظة. يبث كاتب HotXLS SortDataField بوصفه rankBy، وعندما لا تكون AutoSortScope فارغة يكتب أيضاً كتلة autoSortScope بمرجع محور البيانات 4294967294، مضيعاً سلسلة الخاصية في خانة x v. وعند التحميل يستقبل AutoSortScope رمز x v نفسه، فلترتيبات القيمة تحمل الخاصية الترتيبي لحقل البيانات بوصفه نصاً. وضبطه على '0' ينتج إذن ملفاً يحمل القياس في الموضعين معاً، وهو أقرب تطابق لما تكتبه Excel بنفسها. ثم يرصّ MaterializeNativePivotTable الشبكة المرتبة وبياناتها الوصفية للتخطيط معاً ويعيد 1 عند النجاح أو -1 مع تشخيص
صفوف العناصر ليست الشيء الوحيد الذي يُرتب. تمر حقول الأعمدة عبر المقارن نفسه، مستخدمة مجاميع لكل عمود بدل مجاميع لكل صف، فحقل أعمدة ذو SortType = xlpfstDescending و SortDataField صالح يرتب أعمدته حسب القيمة بالطريقة نفسها تماماً
فحص الترتيب الذي يحمله مصنف Excel أصلاً
لملفات تأليف Excel تملأ HotXLS SortType و SortDataField و AutoSortScope أثناء تحميل تعريف الـ pivot، فيمكنك تدقيق ترتيب تقرير أو تغييره دون إعادة بناء الجدول. يسرد المقتطف أدناه كل حقل يرتب حسب قياس ويسمي القياس بـ DisplayName له
var
Book: TXLSXWorkbook;
Pivot: TXLSPivotTable;
Field: TXLSPivotField;
I: Integer;
begin
Book := TXLSXWorkbook.Create;
try
Book.Open('sales-report.xlsx');
Pivot := Book.Sheets.SheetByName('Report').PivotTables[0];
for I := 0 to Pivot.FieldCount - 1 do
begin
Field := Pivot.Fields[I];
if (Field.SortType <> xlpfstManual) and (Field.SortDataField >= 0) then
Writeln(Field.Name, ' sorted by ',
Pivot.DataFields[Field.SortDataField].DisplayName);
end;
// اقلب ترتيب Region إلى تصاعدي وأعد بناء الشبكة القائمة
Field := Pivot.FindFieldByName('Region');
if Field <> nil then
Field.SortType := xlpfstAscending;
if Book.MaterializeNativePivotTable(Pivot, True) <> 1 then
raise Exception.Create('Could not re-materialize the pivot');
Book.SaveAs('sales-report-asc.xlsx');
finally
Book.Free;
end;
end;
الوسيط الثاني لـ MaterializeNativePivotTable يخبر HotXLS بتبنّي مدى المخرجات القائم للـ pivot بدل معاملته تصادماً. يظهر النمط نفسه في دليل Show Values As للترتيب والمجاميع الجارية في HotXLS، حيث يهم ترتيب الترتيب لأن المجاميع الجارية تتراكم بترتيب العرض
كيف تفصل HotXLS التعادلات عندما تتساوى قيمة عنصرين؟
تفصل HotXLS التعادلات بحسب تسمية العنصر، تحديدًا مقصوفاً، وهو فرق معلوم عن Excel. عندما يتساوى مجموع عضوين يعود المقارن إلى مقارنة تسميتيهما، ويعكس علم التنازلي تلك المقارنة أيضاً. العناصر التي مقاييسها ليست عدداً صالحاً ترتب بعد الصالحة بترتيب تصاعدي، ويعكس علم التنازلي المقارنة كلها، ذلك التجميع شاملاً
لا تعد Excel بأي ترتيب تعادل إطلاقاً. في تجهيزة اختبار كان فيها أربعة أعضاء A و B و C و D بمجموع واحد، أنتج ترتيب تصاعدي في Excel B, C, A, D. لا شيء في البيانات الوصفية المحفوظة يتنبأ بتلك التبديلة؛ إنها ناتج ثانوي لترتيب غير مستقر، ويمكن أن تختلف بين الملفات. تعيد HotXLS A, B, C, D للمدخل نفسه. يفحص تحققنا لتلك الحالة مجموعة الأعضاء وقيم كل عضو لا التسلسل، وتطابقت تجهيزة التنازلي بتعادل 15/15 مع Excel خلية بخلية. إن كان كودك اللاحق معتمداً على موضع الصفوف المتعادلة بالضبط فارتب حسب قياس ثانٍ أو اجعل القيم مميزة
الأعضاء المطويون والحقل الأعمق
تتحقق الأعضاء المطوّون في HotXLS صفاً مجمّعاً واحداً لكل عنصر مطوًى. عندما يخفي Excel تفاصيل عنصر يكتب sd="0" على ذلك <item>؛ وتكشفه HotXLS بوصفه TXLSPivotItem.IsDetailHidden. يعرض العنصر المطوّى بتسميته العادية، ويحل محل شجرته الفرعية كاملة، وينطبق الطي على ذلك العنصر تحت كل أب، بينما تحفظ الكتل الحاوية مجاميعها الفرعية الخاصة
var
Category: TXLSPivotField;
begin
// للـ Pivot Category (خارجي) و Product (داخلي) على الصفوف
Category := Pivot.FindFieldByName('Category');
if (Category <> nil) and (Category.ItemCount > 0) then
Category.Items[0].IsDetailHidden := True; // اطوِ الفئة الأولى
if Book.MaterializeNativePivotTable(Pivot, True) <> 1 then
raise Exception.Create('Collapse was rejected');
end;
يتفاعل الطي مع الترتيب بطريقة يمكن توقعها: الصف المطوّى ما يزال عضواً في حقه، فيأخذ موقعه من مجموعه كأي عنصر آخر. والحقل الأعمق مختلف. لا مستوى داخلي له، فلا شيء يُطوى عنده، ومنذ إصلاح سابق لا تعرض HotXLS صفاً لمجموع فرعي له أيضاً، حتى مع علم defaultSubtotal مضبوطاً. يسلك Excel السلوك نفسه على المحاور أحادية الحقل ومتعددة المستويات، وقبل ذلك التغيير كان يمكن لـ HotXLS بثّ صف Total شبحي تحت الحقل الأعمق. ولسمات مستوى الحقل المعنية هنا تغطي جولة HotXLS في صلاحية مخطط CT_PivotField ما يشترطه المخطط على <pivotField> وعناصره
مزالق عند الفحص مقابل أتمتة Excel
عندما تفحص ترتيب HotXLS عكسياً مقابل Excel عبر أتمتة COM، استدعِ AutoSort بالتسمية المحلية للقياس، مُهربةً كما تعرضها Excel حرفياً. على Excel بلغة صينية التسمية الافتراضية لحقل Units مجمّع هي '求和项:Units'؛ وتمرير 'Sum of Units' على تلك الآلة لا يرفع خطأ ولا يغير شيئاً. السكربت نفسه الذي يعمل على Excel إنجليزية يصير بلا فعل في مكان آخر بصمت، فاقرأ التسمية من حقل البيانات بدل ترميزها ثابتة
- لم يمكن قراءة
PivotField.SortTypeعائدةً عبر COM في بناء Excel الذي اختبرناه، فتحقق من الترتيب من XML المحفوظ أو الخلايا المعروضة بدلاً من ذلك - في ذلك البناء وضع حقل أب لمجموعة يدوية على المحور نفسه خارج الحقل المرتب كبح ترتيب الأعضاء حسب القيمة؛ والعرض المرتب تحت آباء المجموعات اليدوية غير متحقق منه
- رُفضت كتابات إلى
PivotField.OutlineوPivotField.LayoutFormفي ذلك البناء أيضاً، فاضبط تخطيط outline لتجهيزة عبرPivotTable.RowAxisLayoutبدلاً منها
لا تغيّر تلك العثرات صيغة الملف، لكنها تقرر ما إذا كان اختبار انحدار يثبت شيئاً. اختبار يستدعي AutoSort بالتسمية الخاطئة ينجح مقابل pivot لم يرتب قط
FAQ
ماذا يعني الحقل 4294967294 في ملف PivotTable XML؟
الحقل 4294967294 هو ترميز غير موقع من 32 بتاً لفهرس الحقل -2، الذي يحجزه ECMA-376 للحقل الزائف Values. داخل autoSortScope يشير إلى مرجع محور بيانات، وينتقي ابنه x أي حقل بيانات ترتب به العناصر
هل ترتب HotXLS عناصر pivot حسب القيمة دون تثبيت Excel؟
نعم. تحسب HotXLS الترتيب بنفسها عندما تحقق شبكة الـ pivot، مستخدمة مجاميع كل عضو لحقل البيانات المنتقى، وتكتب sortType و rankBy و autoSortScope اختيارياً كي يحفظ Excel الترتيب نفسه بعد تحديث. لا يمكن إلا لترتيب التعادلات بين القيم المتساوية أن يختلف عن Excel
لماذا رُتبت عناصر pivot ألفبائياً بدل حسب القيمة؟
عادةً لأن الحقل له اتجاه ترتيب دون قياس. تحقق أن SortType ليست xlpfstManual وأن SortDataField بين 0 و DataFieldCount - 1؛ وعند -1 ترتب HotXLS العناصر بالتسمية في الاتجاه المطلوب
الترتيب حسب القيمة والأعضاء المطوّون وبقية أنبوب pivot الأصلي متوفرة في HotXLS، مكون جداول البيانات لـ Delphi لملفات XLS و XLSX، الذي يقرأ ويحرر ويكتب مصنفات Excel دون تثبيت Excel. وإن كنت تبني الـ pivot من الصفر أولاً فتغطي برنامج HotXLS التعليمي لبناء جداول pivot وتحديثها المخازن المؤقتة والحقول والتحديث قبل أن تصل إلى ترتيبها