مقاله فنی

interop فایل ODS در HotXLS: فرمول و قاعده برای هر دو برنامه

برای تولید یک فایل ODS که هم Excel و هم LibreOffice درست بخوانند، HotXLS هر فرمول را با سینتکس OpenFormula زیر یک namespace اعلان‌شده یعنی of: می‌نویسد، و هر فرمت شرطی از جنس مقدار یا فرمول را دوبار می‌نویسد: به‌شکل یک <style:map> روی استایل هر سلول پوشش‌داده‌شده که تنها فرمی است که Excel 16 می‌خواند، و به‌شکل یک بلاک calcext:conditional-formats که فرمی است که LibreOffice به آن اعتماد می‌کند. هر برنامه نیمه مالِ دیگری را نادیده می‌گیرد، پس فایلی که در یکی درست دیده می‌شود درباره دیگری هیچ چیزی ثابت نمی‌کند

آن جمله آخر درس شش نسخه HotXLS بین v2.384.55 و v2.384.72 است. هر فیکس با فایلی شروع شد که HotXLS نوشته بود، خودش بی‌نقص می‌خواندش، و یکی از دو برنامه هدف غلط می‌خواندش. آنچه می‌آید این است که هر برنامه واقعاً چه چیزی می‌پذیرد، چه نشانه‌گذاری‌ای هر دو را راضی می‌کند، و کدام فراخوانی‌های API مربوط به HotXLS از دلفی همان را تولید می‌کنند

چرا یک فایل ODS در یک برنامه سالم و در دیگری خراب دیده می‌شود؟

یک فایل ODS در یک برنامه سالم و در دیگری خراب دیده می‌شود چون Excel و LibreOffice بخش‌های متفاوتی از همان پکیج را می‌خوانند. OpenDocument به فرمول‌ها و فرمت‌های شرطی بیش از یک املای قانونی می‌دهد، LibreOffice یک namespace افزونه مال خودش هم رویش می‌گذارد، و هر مصرف‌کننده زیرمجموعه‌ای را برمی‌دارد که پیاده کرده. نویسنده‌ای که فقط مقابل یک مصرف‌کننده تست شده با کمال میل روی نشانه‌گذاری همگرا می‌شود که دیگری بی‌سروصدا غلط می‌خواند

هیچ‌کدام از دو برنامه خطا گزارش نمی‌کنند. LibreOffice در سلول‌هایی که فرمول‌هایش را نتوانست parse کند #VALUE! نشان می‌دهد؛ Excel workbook را با فرمت‌های شرطی غایب باز می‌کند، یا با فرمولی که بازنویسی شده به چیزی که به #NAME? یا ثابت 0 ارزیابی می‌شود. نویسنده‌ای که خروجی خودش را round-trip می‌کند هیچ‌کدام را نمی‌بیند. HotXLS دقیقاً با همان تله سراغ فرمول‌نویسی namespace رفت: reader آن پیشوند of: را به‌عنوان متن ساده مچ می‌کرد، پس هر round-trip با خودش پاس می‌شد در حالی که LibreOffice در همه سلول‌های فرمول‌دار #VALUE! نشان می‌داد

فیچرآنچه Excel 16 می‌خواندآنچه LibreOffice 26.2 می‌خواند
ستون کامل نوشته‌شده به‌شکل A:Aبدفهمیده می‌شود به A:(A)تحمل می‌شود
ستون کامل نوشته‌شده به‌شکل [.A:.A]بلهبله
فرمت‌های شرطی در <style:map>بله، تنها فرمی که می‌خواندوقتی calcext هست نادیده گرفته می‌شود
فرمت‌های شرطی در calcext:conditional-formatsنادیده گرفته می‌شودبله، و ترجیح داده می‌شود
قاعده مقداری calcext با ویژگی calcext:operatorنادیده گرفته می‌شودبه‌عنوان «مساوی 0» وارد می‌شود
قاعده فرمولی calcext نوشته‌شده به‌شکل is-true-formula(...)نادیده گرفته می‌شودبه‌عنوان یک مقایسه مقداری با 0 وارد می‌شود

OpenFormula در ODS: اول namespace را اعلان کنید، بعد سینتکس را درست بزنید

یک سلول فرمول‌دار در ODS فقط وقتی برای LibreOffice خواناست که پیشوند of: در table:formula به یک namespace اعلان‌شده XML حل شود. پیشوند تزئین نیست. ‏of: مپ می‌شود به urn:oasis:names:tc:opendocument:xmlns:of:1.2، و msoxl: که پیشوندی است HotXLS برای فرمول‌هایی که مترجم OpenFormula‌اش مدلشان نمی‌کند استفاده می‌کند، مپ می‌شود به http://schemas.microsoft.com/office/excel/formula. قبل از v2.384.56 ریشه content.xml هر دو پیشوند را بدون اعلان استفاده می‌کرد، و LibreOffice اصلاً نمی‌توانست گرامر فرمول را شناسایی کند

<!-- قبل از v2.384.56: پیشوند استفاده شده اما هرگز اعلان نشده؛ LibreOffice مقدار #VALUE! نشان می‌دهد -->
<office:document-content xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" ...>
  <table:table-cell table:formula="of:=SUM([.A1:.A3])" office:value-type="float" office:value="245"/>

<!-- از v2.384.56: هر دو namespace مربوط به فرمول روی ریشه اعلان شده‌اند -->
<office:document-content
    xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2"
    xmlns:msoxl="http://schemas.microsoft.com/office/excel/formula" ...>

با فیکس شدن namespace، خود عبارت هم همچنان باید یک OpenFormula معتبر باشد، طبق تعریف بخش 4 از OpenDocument 1.3. تله‌ها جاهایی‌اند که سینتکس اکسل و OpenFormula شبیه به نظر می‌رسند اما یکی نیستند:

  • ارجاع‌های سلولی براکت‌دار و با نقطه پیشوندند، و علامت‌های $ جزو ارجاع‌اند: ‏[.$A$1] و [.A$1:.$B2] یک OpenFormula معتبرند. قبل از v2.384.55 نویسنده HotXLS همه $ها را می‌انداخت، پس ارجاع‌های مطلق نسبی برمی‌گشتند و فقط وقتی خراب می‌شدند که کسی سلول را کپی می‌کرد
  • ستون‌ها و سطرهای کامل باید فرم براکت‌دار را بگیرند: ‏[.A:.A] و [.$A:.$B] و [.1:.1] و [.$1:.$2]. یک of:=SUM(A:A) لخت را LibreOffice تحمل می‌کند، اما Excel 16 بازش می‌کند به‌شکل =SUM(A:(A)) با #NAME?، و ارجاع‌های سطری و $A:$B را به ثابت 0 می‌برد. HotXLS فرم براکت‌دار را از v2.384.65 می‌نویسد
  • آرگومان‌های تابع با ; جدا می‌شوند، نه ,
  • اجتماع ارجاع‌ها از عملگر ~ استفاده می‌کند: مقدار AREAS((A1,B2)) اکسل می‌شود AREAS(([.A1]~[.B2])). ترجمه همان کاما به ; به‌جای آن، یک آرگومان اجتماع را به دو آرگومان می‌برد
  • آرایه‌های درون‌خطی ستون‌ها را با ; و سطرها را با | جدا می‌کنند: مقدار {1,2;3,4} اکسل می‌شود {1;2|3;4}. قبل از v2.384.55 HotXLS مقدار {1;2;3;4} تولید می‌کرد، یک سطر از چهار مقدار

کاما بخش سخت است، چون یک کاراکتر اکسل سه معنا حمل می‌کند. از v2.384.55 نویسنده HotXLS موقع ترجمه یک stack پرانتز دنبال می‌کند: یک ( بلافاصله بعد از یک نام یک فراخوانی تابع باز می‌کند که کاماهایش ; می‌شوند؛ هر ( دیگری یک پرانتز گروه‌بندی است که کاماهایش ~ می‌شوند؛ و کاماهای داخل {} جداکننده ستون آرایه‌اند. با این و فیکس namespace، ‏LibreOffice 26.2 هر هشت فرمول probe آرایه و اجتماع را درست ارزیابی کرد، از جمله INDEX و AREAS روی اجتماع‌ها

نمودار HotXLS از stack پرانتزی که کاماهای اکسل را به OpenFormula ترجمه می‌کند: پرانتزی که بلافاصله بعد از نام می‌آید یک فراخوانی تابع باز می‌کند که کاماهایش سمی‌کالن می‌شوند، هر پرانتز دیگری گروه‌بندی است که کاماهایش عملگر اجتماع یعنی مد می‌شوند، و کاماهای داخل آکولاد جداکننده ستون آرایه‌اند، مثل AREAS روی اجتماع A1 و B2
کاما در سینتکس اکسل سه معنا حمل می‌کند و فقط stack پرانتز در حال اجرا آن‌ها را جدا می‌کند؛ یک کامای اجتماع را سمی‌کالن ترجمه کنید و یک آرگومان بی‌سروصدا دو تا می‌شود
uses
  lxHandleX;

var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
begin
  Book := TXLSXWorkbook.Create;
  try
    Sheet := Book.Sheets.Add('Orders');
    Sheet.Cells[1, 1].Value := 120;
    Sheet.Cells[2, 1].Value := 80;
    Sheet.Cells[3, 1].Value := 45;
    Sheet.Cells[1, 2].Value := 0.2;

    // از v2.384.65 نوشته می‌شود به‌شکل of:=SUM([.A:.A])
    Sheet.Cells[1, 4].Formula := 'SUM(A:A)';
    // نوشته می‌شود به‌شکل of:=[.A1]*[.$B$1]؛ علامت‌های $ از v2.384.55 سالم می‌مانند
    Sheet.Cells[2, 4].Formula := 'A1*$B$1';

    Book.SaveAsODS('orders.ods');
  finally
    Book.Free;
  end;
end;

فرمول‌هایی که مترجم مدلشان نمی‌کند به msoxl:= با همان متن اکسل برمی‌گردند، و برای همین اعلان msoxl هم مهم است. در نویسنده فعلی این مسیر شامل ارجاع‌های واجد-نام-شیت مثل Sheet2!A1 و ارجاع‌های ساختاریافته جدول است. HotXLS فرمول‌های msoxl: را موقع import برمی‌گرداند و می‌خواند، پس round-trip خودش عبارت را سالم نگه می‌دارد، اما برنامه دیگری با آن‌ها چه کند از کنترل نویسنده خارج است. اگر فرمولی که مصرف‌کننده‌هایتان به آن تکیه دارند با پیشوند msoxl: دربیاید، قبل از ارسال فایل را در هر دو برنامه باز کنید

چرا Excel فرمت‌های شرطی‌ای که فقط calcext نوشته شده‌اند را نمی‌بیند؟

Excel 16 فرمت‌های شرطی calcext را نمی‌بیند چون فرمت‌های شرطی ODS را انحصاراً از فرزندان <style:map> استایل‌های سلولی می‌خواند و بلاک calcext:conditional-formats را کلاً نادیده می‌گیرد. آزمایشی که این را حل می‌کند کوتاه است: یک ODS ذخیره‌شده توسط LibreOffice بردارید، المان‌های style:map را حذف کنید، و Excel صفر قاعده می‌خواند؛ به‌جایش بلاک calcext را حذف کنید، و Excel همچنان همه را می‌خواند. LibreOffice برعکس رفتار می‌کند. ‏calcext همان namespace افزونه LibreOffice است و بخش استاندارد ODF نیست، و وقتی یک قاعده calcext حاضر باشد LibreOffice همان را برمی‌دارد و style:map را نادیده می‌گیرد

نمودار دوکاناله HotXLS برای فرمت‌های شرطی ODS: هر قاعده مقداری یا فرمولی هم به‌شکل style map روی استایل هر سلول پوشش‌داده‌شده نوشته می‌شود که تنها فرمی است که Excel 16 می‌خواند، هم به‌شکل بلاک فرمت‌های شرطی calcext با عملگر داخل مقدار که فرمی است LibreOffice ترجیح می‌دهد، در حالی که هر برنامه ام وال دیگر را بی‌سروصدا نادیده می‌گیرد
Excel استایل‌مپ‌ها را می‌خواند و calcext را نادیده می‌گیرد، LibreOffice ترجیحش calcext است و مپ‌ها را می‌اندازد، و هیچ‌کدام خطا نشان نمی‌دهند؛ نوشتن هر دو املای آن از یک فراخوانی HotXLS تنها راهی است که فایل در هر دو تأیید شود

قبل از v2.384.69 HotXLS فقط calcext می‌نوشت، پس یک فایل ODS با هایلایت‌های کاملاً سالم در Excel بدون هیچ قاعده مقداری و هیچ قاعده فرمولی باز می‌شد. HotXLS حالا هر دو فرم را می‌نویسد. نیمه style:map از گرامر شرط اسکیمای OpenDocument استفاده می‌کند (بخش 3 از ODF 1.3)، با همین املاهایی که Excel 16 و LibreOffice 26.2 هر دو موقع ذخیره ODS تولید می‌کنند:

<!-- ساده‌شده. استایل حامل برای هر سلول A1:A50 (دو قاعده مقداری) -->
<style:style style:name="ce3" style:family="table-cell">
  <style:map style:condition="cell-content()&gt;100"
             style:apply-style-name="CF_Hit"
             style:base-cell-address="Orders.A1"/>
  <style:map style:condition="cell-content-is-between(1,10)"
             style:apply-style-name="CF_Low"
             style:base-cell-address="Orders.A1"/>
</style:style>

<!-- استایل حامل برای هر سلول C1:C50 (یک قاعده فرمولی) -->
<style:style style:name="ce4" style:family="table-cell">
  <style:map style:condition="is-true-formula(COUNTIF([.$C:.$C];[.C1])&gt;1)"
             style:apply-style-name="CF_Dup"
             style:base-cell-address="Orders.C1"/>
</style:style>

گیر style:map این است که روی استایل‌های سلولی زندگی می‌کند، پس به‌ازای هر سلول است. هر سلول در بازه قاعده باید استایلی داشته باشد که مپ را حمل کند، سلول‌های خالی هم شامل، وگرنه قاعده در Excel آن سلول را اصلاً پوشش نمی‌دهد. HotXLS استایل فرمت موجود هر سلول را کپی می‌کند، مپ‌ها را اضافه می‌کند، و استایل‌های حامل را بر اساس جفت استایل-اصلی و متن-مپ deduplicate می‌کند، پس بازه‌ای از 500 سلول با فرمت یکسان همچنان یک استایل تولید می‌کند. نویسنده جدول نوشته‌شده را تا بازه قاعده هم گسترش می‌دهد، یعنی سطرهای تهی انتهایی داخل یک قاعده صادر می‌شوند نه اینکه افتاده شوند. از v2.384.69 مقدار styles.xml هم یک استایل سلولی خالی به نام Default حمل می‌کند تا style:apply-style-name="Default" همیشه هدف داشته باشد

امالای calcext ای که LibreOffice واقعاً می‌پذیرد

LibreOffice یک قاعده مقداری calcext را فقط وقتی می‌پذیرد که عملگر مقایسه بخشی از متن مقدار باشد، مثل >3 یا between(1,10)، و قاعده فرمولی را فقط وقتی که به‌شکل formula-is(...) نوشته شده باشد. هر دو نکته یک نسخه از HotXLS گرفتند، چون امالای غلط قاعده‌ای تولید می‌کنند که بدون خطا وارد می‌شود و بعد سلول‌های اشتباه را مچ می‌کند

اشتباه اول یک ویژگی calcext:operator کنار calcext:value بود. طبیعی خوانده می‌شود، اما از خودساخته است: LibreOffice آن ویژگی را نمی‌شناسد، پس هر قاعده مقداری را به‌عنوان «مساوی 0» وارد می‌کرد. اشتباه دوم گذاشتن is-true-formula(...)، همان املای style:map، داخل یک شرط calcext بود که LibreOffice آن را هم به‌عنوان مقایسه مقدار-سلولی با 0 وارد می‌کرد. فیکس فرمولی در v2.384.66 و فیکس مقداری در v2.384.69 منتشر شد:

<!-- غلط: LibreOffice مقدار calcext:operator را نادیده می‌گیرد و «مساوی 0» وارد می‌کند -->
<calcext:condition calcext:apply-style-name="CF_Hit"
                   calcext:operator="greater-than" calcext:value="100"/>

<!-- درست: عملگر داخل خود مقدار سفر می‌کند -->
<calcext:condition calcext:apply-style-name="CF_Hit"
                   calcext:value="&gt;100" calcext:base-cell-address=".A1"/>
<calcext:condition calcext:apply-style-name="CF_Low"
                   calcext:value="between(1,10)" calcext:base-cell-address=".A1"/>

<!-- درست: قاعده‌های فرمولی از formula-is استفاده می‌کنند، ارجاع نسبی لنگرشده به سلول پایه -->
<calcext:condition calcext:apply-style-name="CF_Dup"
                   calcext:value="formula-is(COUNTIF([.$C:.$C];[.C1])&gt;1)"
                   calcext:base-cell-address=".C1"/>
نمودار HotXLS که امالای غلط و درست شرط calcext را تضاد می‌دهد: یک ویژگی calcext:operator از خودساخته است و هر قاعده مقداری را به‌عنوان مساوی 0 وارد می‌کند، عملگر باید داخل مقدار باشد مثل بزرگتر از 100 یا بین 1 و 10، و قاعده‌های فرمولی باید formula-is لنگرشده به یک سلول پایه بگویند نه املای style:map یعنی is-true-formula
هر دو امالای غلط بدون خطا وارد می‌شوند و بعد سلول‌های اشتباه را مچ می‌کنند، قاعده‌ای که مساوی 0 خوانده می‌شود هیچ چیزی که خواسته بودید هایلایت نمی‌کند؛ فیکس این است که عملگر داخل مقدار باشد و برای عبارت‌ها formula-is

سلول پایه همان چیزی است که به ارجاع‌های نسبی معنا می‌دهد. HotXLS هر قاعده را در سلول بالا-چپ اولین ناحیه بازه‌اش لنگر می‌کند، پس فرمولی که برای C1 نوشته شده به‌شکل C2 و C3 و همین‌طور به پایین بازه ارزیابی می‌شود، دقیقاً مثل فرمت‌بندی شرطی خود اکسل. عبارت قاعده از همان مترجمی می‌گذرد که فرمول‌های سلولی، پس آرایه‌ها و اجتماع‌ها و ستون‌های کامل و علامت‌های $ به همان فرم‌هایی درمی‌آیند که بالا توضیح داده شد. در سمت Delphi قاعده‌ها را دقیقاً مثل یک فایل .xlsx اضافه می‌کنید

uses
  lxHandleX;

procedure AddOrderHighlights(Book: TXLSXWorkbook; Sheet: TXLSXWorksheet);
var
  Idx: Integer;
  Opts: TODSExportOptions;
begin
  // قاعده‌های مقداری: مقدار style:map یعنی cell-content()>100 به‌علاوه مقدار calcext یعنی ">100"
  Idx := Sheet.AddConditionalFormat('A1:A50', xlsxCfOpGreaterThan, '100');
  Sheet.ConditionalFormats[Idx].Style.SetFillBgColor($00C0C0FF); // BGR: قرمز روشن

  Idx := Sheet.AddConditionalFormat('A1:A50', xlsxCfOpBetween, '1', '10');
  Sheet.ConditionalFormats[Idx].Style.SetFontBold(True);

  // قاعده فرمولی با سینتکس اکسل (جداکننده‌ها کاما، نسبت به C1):
  // مقدار style:map یعنی is-true-formula(...) به‌علاوه مقدار calcext یعنی formula-is(...)
  Idx := Sheet.AddCondFormatExpression('C1:C50', 'COUNTIF($C:$C,C1)>1');
  Sheet.ConditionalFormats[Idx].Style.SetFillBgColor($00CCFFFF); // BGR: زرد روشن

  Opts := TODSExportOptions.Create;
  try
    Opts.Generator := 'OrderExport 3.1';
    Book.SaveAsODS('orders.ods', Opts);
  finally
    Opts.Free;
  end;
end;

خواندن ODS تولیدشده توسط Excel و LibreOffice به دلفی

وقتی HotXLS یک فایل ODS باز می‌کند، reader آن هر دو لهجه فرمت شرطی و هر دو امالای calcext را می‌پذیرد، و وقتی فایل قاعده‌ای را در هر دو فرم حمل کند آن را دوبار نمی‌شمارد. فایل‌های واقعی از سه نویسنده می‌آیند، هر کدام با عادت خودش:

  • calcext قدیمی و جدید. فایل‌های دارای ویژگی calcext:operator، از جمله ODS نوشته‌شده توسط HotXLS قبل از v2.384.69، همچنان از parse قدیمی می‌گذرند. شرط‌های فرمولی هم به‌عنوان formula-is(...) شناخته می‌شوند هم به‌عنوان is-true-formula(...)
  • امالای style:map مربوط به Excel. Excel شرط‌ها را با پیشوند of: می‌نویسد، مثل of:cell-content-is-between(1,10)، و روی قاعده‌های مقداری سلول پایه را حذف می‌کند. هر دو پذیرفته می‌شوند
  • سلول‌های خالی. Excel و LibreOffice هر دو مپ مربوط به سلول‌های خالی را روی استایل پیش‌فرض ستون می‌گذارند نه روی سلول، پس reader استایل‌های پیش‌فرض ستون را برای سلول‌های تکراری قبل از جمع کردن مپ‌ها حل می‌کند
  • بازسازی ناحیه. مپ‌ها به‌ازای هر سلول جمع می‌شوند، پس بعد از خواندن یک شیت، reader سلول‌هایی که شرط و سلول پایه یکسانی دارند را به بازه برمی‌گرداند، اول در طول هر سطر و بعد به پایین در spanهای ستونی هم‌خوان، و هر قاعده‌ای را که از قبل از calcext خوانده حذف می‌کند

فیکس v2.384.72 مربوط به استایل‌های عددی است نه قاعده‌ها. Excel 16 و LibreOffice 26.2 هر دو فرمت General را به‌شکل یک استایل عددی می‌نویسند که المان number:number اش هیچ number:decimal-places ای ندارد، معمولاً <number:number number:min-integer-digits="1"/>. reader مربوط به HotXLS نبود شمارنده را دو رقم اعشار ثابت می‌گرفت، پس هر مقدار زیر استایل Default با 0.00 وارد می‌شد و 1.5 به‌شکل 1.50 نمایش داده می‌شد. از v2.384.72 یک المان عددی ساده بدون رقم اعشار و بدون حداقل اعشار و بدون گروه‌بندی و با حداکثر یک رقم صحیح مپ می‌شود به General، و یک General تنها سلول را بدون هیچ فرمت عددی می‌گذارد. متن دورش نگه داشته می‌شود، مثل General" kg"، و اعداد گروه‌بندی‌شده مپ قبلی را نگه می‌دارند چون اکسل فرمت General گروه‌بندی‌شده ندارد

uses
  SysUtils, lxCondFormat, lxHandleX;

procedure DumpOdsRules(const FileName: string);
var
  Book: TXLSXWorkbook;
  Sheet: TXLSXWorksheet;
  Rule: TXLSXConditionalFormat;
  I: Integer;
begin
  Book := TXLSXWorkbook.Create;
  try
    if Book.Open(FileName) <= 0 then
      raise Exception.Create('cannot open ' + FileName);
    if Book.SourceFormat <> xlsxOpenDocumentSpreadsheet then
      raise Exception.Create('not an ODS package');

    Sheet := Book.Sheets[1]; // اندیس‌گذار Sheets یک-مبناست
    for I := 0 to Sheet.ConditionalFormats.Count - 1 do
    begin
      Rule := Sheet.ConditionalFormats[I];
      case Rule.Kind of
        cfkCellIs:
          Writeln(Rule.Range, ' value rule ', Ord(Rule.Op), ' ',
            Rule.Formula1, ' ', Rule.Formula2);
        cfkExpression:
          Writeln(Rule.Range, ' formula rule ', Rule.Formula1);
      end;
    end;

    // سلولی با استایل General مربوط به اکسل از v2.384.72 بدون هیچ
    // فرمت عددی برمی‌گردد، به‌جای '0.00'
    Writeln('A2 format: "', Sheet.Cells[2, 1].NumberFormat, '"');
  finally
    Book.Free;
  end;
end;

فرمول‌های قاعده با سینتکس اکسل و جداکننده‌های کاما برمی‌گردند، همان فرمی که به AddCondFormatExpression می‌دادید، پس قاعده‌ای که HotXLS نوشته به‌عنوان همان رشته عیناً برمی‌گردد. برای تصویر کلان‌تر از اینکه مسیر import مربوط به ODS چه چیزی را نگه می‌دارد و چه چیزی را می‌اندازد، راهنمای round-trip باز کردن و ذخیره ODS در HotXLS را ببینید؛ و برای اینکه سطرهای تکراری از Excel و LibreOffice موقع import چطور باز می‌شوند، سطرهای تکراری ODS به‌عنوان ران‌های ارتفاع سطر را ببینید

محدودیت‌های interop فرمت شرطی ODS در HotXLS چیست؟

رویکرد نشانه‌گذاری-دوگانه قاعده‌های مقایسه مقداری و قاعده‌های فرمولی را پوشش می‌دهد و همان‌جا می‌ایستد. بقیه چیزها یک‌طرفه‌اند یا اصلاً نوشته نمی‌شوند:

  • مقیاس‌های رنگی و data barها فقط به‌عنوان المان calcext نوشته می‌شوند، پس LibreOffice نشانشان می‌دهد و Excel نه
  • انواع دیگر قاعده مثل مجموعه آیکون و قاعده‌های متنی و top-N و بالاتر-از-میانگین و قاعده‌های تکراری، در نویسنده فعلی خروجی ODS ندارند. یک قاعده متنی معمولاً می‌شود به‌شکل قاعده فرمولی بازنویسیش کرد، مثل ISNUMBER(SEARCH("late",B2)) روی B2:B200 که بعد به هر دو برنامه می‌رسد
  • قاعده‌های کل-ستون و کل-سطر مثل C:C فقط روی ناحیه جدولی گذاشته می‌شوند که واقعاً نوشته شده، نه روی هر 1,048,576 سطر، پس Excel این قاعده‌ها را فقط روی سلول‌هایی می‌بیند که در فایل وجود دارند
  • فایل‌های فقط-style:map. وقتی فایل بلاک calcext ندارد، HotXLS ارجاع‌های نسبی در قاعده‌های فرمولی را از گوشه بالا-چپ بازه بازسازی‌شده تفسیر می‌کند، نه با شیفت از سلول پایه اعلام‌شده
  • قاعده‌های هم‌پوشان از LibreOffice. وقتی یک سلول زیر چند قاعده است، LibreOffice فقط مپ قاعده اول را رویش می‌نویسد. چنین فایل‌هایی را نمی‌شود کامل فقط از style:map خواند، که یک دلیل دیگر برای ترجیح reader به calcext وقتی هر دو هستند

محدودیت فرایندی از همه این‌ها مهم‌تر است. نقص‌های پشت این نسخه‌ها از round-tripهایی سر درمی‌آوردند که ODS می‌نوشتند و با HotXLS برمی‌گرداندند، و بعضی‌ها یک چک دستی در برنامه غلط را هم رد می‌کردند: فرمول‌های کل-ستون در LibreOffice کار می‌کردند در حالی که Excel نشان می‌داد #NAME?، و از v2.384.66 قاعده‌های فرمولی در LibreOffice کار می‌کردند در حالی که Excel تا v2.384.69 هنوز هیچ قاعده‌ای نشان نمی‌داد. اگر interop با ODS یک الزام است، تست پذیرش باز کردن فایل در Excel و در LibreOffice و مقایسه چیزی است که هر یک نشان می‌دهد. همان نظم برای استایل‌هایی که قاعده‌ها به آن‌ها اشاره می‌کنند هم صدق می‌کند؛ مقاله فرمت‌بندی شرطی و استایل‌ها در HotXLS پوشش می‌دهد استایل‌های هایلایت در سمت workbook چطور تعریف می‌شوند

مرجع سریع: ODS ای که هر دو برنامه می‌خوانند

  • روی ریشه content.xml مقدارهای xmlns:of و xmlns:msoxl را اعلان کنید، وگرنه LibreOffice برای هر فرمولی #VALUE! نشان می‌دهد (HotXLS از v2.384.56)
  • ارجاع‌ها را به‌شکل [.A1] بنویسید، همه $ها را نگه دارید، و ستون‌ها و سطرهای کامل را به‌شکل [.A:.A] و [.1:.1] بنویسید (از v2.384.55 و v2.384.65)
  • برای آرگومان‌ها از ;، برای اجتماع ارجاع‌ها از ~، و بین سطرهای آرایه درون‌خطی از | استفاده کنید
  • هر قاعده مقداری یا فرمولی را برای Excel به‌شکل یک <style:map> روی استایل هر سلول پوشش‌داده‌شده بنویسید، و برای LibreOffice به‌شکل یک شرط calcext (از v2.384.69)
  • در calcext عملگر را داخل مقدار بگذارید (‏>3 و between(1,10)) و قاعده‌های فرمولی را به‌شکل formula-is(...) با یک سلول پایه بنویسید (از v2.384.66 و v2.384.69)
  • موقع import انتظار یک استایل عددی General بدون number:decimal-places را داشته باشید؛ HotXLS آن را از v2.384.72 به‌عنوان General می‌خواند
  • هر پروفایل صادرات جدید را با باز کردن فایل در هر دوی Excel و LibreOffice تأیید کنید، هرگز فقط در یکی

HotXLS یک کتابخانه صفحه‌گسترده بومی Delphi و C++Builder است که XLS و XLSX و ODS را بدون نصب بودن Excel یا LibreOffice می‌خواند و می‌نویسد؛ سورس کامل، لیست فیچرها و لایسنس در صفحه کامپوننت صفحه‌گسترده HotXLS در Delphi است