مقال تقني

ترتيب عناصر Pivot حسب القيمة في Delphi: autoSortScope و -2

ترتب 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 واعتمدت على النطاق وحده

يخزن Excel ترتيب قيم PivotTable في مرجع pivotArea داخل autoSortScope، حيث يكون الحقل 4294967294 صياغة غير موقعة من 32 بتاً للـ -2 للحقل الزائف Values وينتقي ابن x حقل البيانات الذي ترتب به HotXLS
يحول المرجع المتداخل اتجاه الترتيب المجرد إلى قياس ملموس: تشير x v=0 إلى حقل البيانات 0، الترتيبي الذي تكشفه HotXLS بوصفه SortDataField على TXLSPivotField

لماذا عاد قياس الترتيب بوصفه -1؟

فقد قارئ HotXLS أصلاً قياس الترتيب لأن 4294967294 لا تتسع في عدد صحيح موقع من 32 بتاً. مساعد السمات غلاف رقيق فوق StrToIntDef، والقيمة خارج المدى تعيد الافتراضي بصمت، فلم يطابق اختبار محور البيانات قط، وبقي SortDataField عند -1، واحتفظ الحقل بـ sortType="descending" وحدها دون قياس مرفق

كان الفشل هادئاً بأسوأ طريقة. الحقل التنازلي دون قياس ما يزال يرتب، فقط حسب تسمية العنصر بالعكس، فتقرير رتبته Excel حسب المجموع عاد من HotXLS بترتيب العناصر معكوساً. لم يرفع شيء استثناء وكانت الأعداد في كل خلية صحيحة. كان ترتيب الصفوف وحده خاطئاً، وفي ملفات من تأليف Excel فقط

يقارن الإصلاح في lxPivotXml.pas رمز السمة الخام بوصفه سلسلة قبل أي تحويل صحيح. إن كانت rankBy قد ضبطت قياساً فهي تغلب؛ وإلا فمرجع يكون رمز field فيه '4294967294' بالضبط يحل SortDataField من قيمة x المنتقاة له. لم يحتج جانب التقييم إلى تغيير: كان المقارن ينهي مجاميع كل عضو على محوري الصفوف والأعمدة أصلاً، ويعالج الترتيب التنازلي ويفصل التعادلات. البيانات ببساطة لم تكن تصل إليه قط

فقد قارئ pivot في HotXLS ترتيب قيم Excel لأن 4294967294 تفيض عن StrToIntDef موقع من 32 بتاً وتركت SortDataField عند -1؛ ويقارن الإصلاح سلسلة الرمز الخام قبل أي تحويل صحيح
هبّط المسار القديم ترتيب قيم تنازلياً إلى ترتيب تسميات معكوس دون استثناء؛ والمسار الجديد في lxPivotXml.pas يحل القياس كلما كان رمز الحقل 4294967294 بالضبط

ينطبق الدرس العام على أي قارئ 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 تعادلات ترتيب قيم pivot في Excel داخل Delphi تحديدًا حسب تسمية العنصر، معيدةً A, B, C, D لتجهيزة من أربعة أعضاء أنتج فيها ترتيب Excel غير المستقر B, C, A, D
المجاميع المتساوية تسقط إلى مقارنة تسميات يعكسها علم التنازلي أيضاً، فلا يمكن إلا لترتيب الصفوف المتعادلة أن يختلف بين المحركين

الأعضاء المطويون والحقل الأعمق

تتحقق الأعضاء المطوّون في 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 وتحديثها المخازن المؤقتة والحقول والتحديث قبل أن تصل إلى ترتيبها