Για να παράξετε ODS αρχείο που διαβάζουν σωστά και η Excel και η LibreOffice, το HotXLS γράφει κάθε τύπο σε OpenFormula σύνταξη κάτω από δηλωμένο namespace of:, και γράφει κάθε value ή formula conditional format δύο φορές: ως <style:map> στο style κάθε καλυμμένου κελιού, που είναι η μόνη μορφή που διαβάζει η Excel 16, και ως block calcext:conditional-formats, που είναι η μορφή στην οποία εμπιστεύεται η LibreOffice. Κάθε εφαρμογή αγνοεί το μισό που προορίζεται για την άλλη, οπότε αρχείο που εμφανίζεται σωστά στη μία δεν αποδεικνύει τίποτα για την άλλη
Η τελευταία εκείνη πρόταση είναι το μάθημα πίσω από έξι releases του HotXLS μεταξύ v2.384.55 και v2.384.72. Κάθε διόρθωση ξεκίνησε με αρχείο που το HotXLS έγραψε, διάβασε πίσω τέλεια, και μία από τις δύο εφαρμογές-στόχους διάβασε λάθος. Ακολουθεί τι δέχεται στην πραγματικότητα κάθε εφαρμογή, το markup που ικανοποιεί και τις δύο, και οι κλήσεις API του HotXLS που το παράγουν από Delphi
Γιατί ένα ODS αρχείο φαίνεται εντάξει στη μία εφαρμογή και χαλασμένο στην άλλη;
Ένα ODS αρχείο φαίνεται εντάξει στη μία εφαρμογή και χαλασμένο στην άλλη επειδή η Excel και η LibreOffice διαβάζουν διαφορετικά μέρη του ίδιου package. Το OpenDocument δίνει στους τύπους και στα conditional formats περισσότερες από μία νόμιμες γραφές, η LibreOffice προσθέτει από πάνω το δικό της extension namespace, και κάθε καταναλωτής διαλέγει το υποσύνολο που υλοποιεί. Writer τεσταρισμένος πάνω σε έναν μόνο καταναλωτή θα συγκλίνει ευχαρίστως σε markup που ο άλλος διαβάζει σιωπηλά λάθος
Καμία εφαρμογή δεν αναφέρει σφάλμα. Η LibreOffice δείχνει #VALUE! σε κελιά των οποίων τους τύπους δεν μπόρεσε να κάνει parse· η Excel ανοίγει το workbook με τα conditional formats απλώς απόντα, ή με τύπο ξαναγραμμένο σε κάτι που αποτιμάται σε #NAME? ή τη σταθερά 0. Writer που κάνει round-trip τη δική του έξοδο δεν βλέπει τίποτα από αυτά. Το HotXLS χτύπησε ακριβώς εκείνη την παγίδα με το formula namespace: ο reader του ταιρίαζε το πρόθεμα of: ως σκέτο κείμενο, οπότε κάθε self round trip περνούσε ενώ η LibreOffice έδειχνε #VALUE! σε κάθε κελί τύπου
| Δυνατότητα | Διαβάζει Excel 16 | Διαβάζει LibreOffice 26.2 |
|---|---|---|
Ολόκληρη στήλη γραμμένη ως A:A | Κακοδιαβασμένη ως A:(A) | Ανέχεται |
Ολόκληρη στήλη γραμμένη ως [.A:.A] | Ναι | Ναι |
Conditional formats σε <style:map> | Ναι, η μόνη μορφή που διαβάζει | Αγνοούνται όταν υπάρχει calcext |
Conditional formats σε calcext:conditional-formats | Αγνοούνται | Ναι, προτιμώνται |
calcext value rule με attribute calcext:operator | Αγνοείται | Εισάγεται ως "ίσο με 0" |
calcext formula rule γραμμένη is-true-formula(...) | Αγνοείται | Εισάγεται ως σύγκριση τιμής με 0 |
OpenFormula σε ODS: δηλώστε το namespace, μετά φτιάξτε τη σύνταξη
Ένα κελί τύπου σε ODS διαβάζεται από τη LibreOffice μόνο όταν το πρόθεμα of: στο table:formula αναλύεται σε δηλωμένο XML namespace. Το πρόθεμα δεν είναι διακόσμηση. Το of: αντιστοιχεί στο urn:oasis:names:tc:opendocument:xmlns:of:1.2, και το msoxl:, το πρόθεμα που χρησιμοποιεί το HotXLS για τύπους που ο OpenFormula translator του δεν μοντελοποιεί, αντιστοιχεί στο 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: και τα δύο formula namespaces δηλωμένα στη ρίζα -->
<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, όπως ορίζεται στο OpenDocument 1.3 Part 4. Οι παγίδες είναι τα σημεία όπου η σύνταξη Excel και το OpenFormula μοιάζουν αλλά δεν είναι τα ίδια:
- Cell references μπαίνουν σε αγκύλες με πρόθεμα τελείας, και οι σημάνσεις
$είναι μέρος του reference: τα[.$A$1]και[.A$1:.$B2]είναι έγκυρο OpenFormula. Πριν το v2.384.55 ο writer του HotXLS πετούσε κάθε$, οπότε απόλυτα references γύριζαν σχετικά και πήγαιναν στραβά μόνο μόλις κάποιος αντιγράψει το κελί - Ολόκληρες στήλες και σειρές πρέπει να χρησιμοποιούν τη μορφή με αγκύλες
[.A:.A],[.$A:.$B],[.1:.1],[.$1:.$2]. Ένα σκέτοof:=SUM(A:A)το ανέχεται η LibreOffice, αλλά η Excel 16 το ανοίγει ως=SUM(A:(A))με#NAME?, και μετατρέπει τις row references και το$A:$Bστη σταθερά 0. Το HotXLS γράφει τη μορφή με αγκύλες από το v2.384.65 - Ορίσματα συναρτήσεων χωρίζονται με
;, όχι, - Reference unions χρησιμοποιούν τον τελεστή
~: το ExcelAREAS((A1,B2))γίνεταιAREAS(([.A1]~[.B2])). Η μετάφραση εκείνου του κόμματος σε;αντί αυτού κάνει ένα όρισμα union δύο ορίσματα - Inline arrays χωρίζουν στήλες με
;και σειρές με|: το Excel{1,2;3,4}γίνεται{1;2|3;4}. Πριν το v2.384.55 το HotXLS παρήγαγε{1;2;3;4}, μία σειρά τεσσάρων τιμών
Το κόμμα είναι το δύσκολο κομμάτι, γιατί ένας χαρακτήρας Excel κουβαλά τρεις σημασίες. Από το v2.384.55 ο writer του HotXLS κρατά parenthesis stack όσο μεταφράζει: ένα ( αμέσως μετά από όνομα ανοίγει κλήση συνάρτησης, της οποίας τα κόμματα γίνονται ;· κάθε άλλο ( είναι παρένθεση ομαδοποίησης, της οποίας τα κόμματα γίνονται ~· και κόμματα μέσα σε {} είναι διαχωριστικά στηλών array. Με αυτό και τη διόρθωση namespace, η LibreOffice 26.2 αποτίμησε σωστά και τους οκτώ probe τύπους array και union, με INDEX και AREAS πάνω σε unions συμπεριλαμβανομένων
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;
// Γράφεται ως of:=SUM([.A:.A]) από το v2.384.65
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;
Τύποι που ο translator δεν μοντελοποιεί πέφτουν πίσω σε msoxl:= με το κείμενο Excel αμετάβλητο, γι’ αυτό η δήλωση msoxl έχει κι αυτή σημασία. Στον τρέχοντα writer εκείνη η διαδρομή περιλαμβάνει references με προδιάκριση sheet όπως Sheet2!A1 και structured table references. Το HotXLS διαβάζει τύπους msoxl: πίσω κατά την εισαγωγή, οπότε το δικό του round trip κρατά την έκφραση άθικτη, αλλά πώς θα τις μεταχειριστεί άλλη εφαρμογή είναι εκτός ελέγχου του writer. Αν τύπος στον οποίο βασίζονται οι καταναλωτές σας βγαίνει με πρόθεμα msoxl:, ανοίξτε το αρχείο και στις δύο εφαρμογές πριν το στείλετε
Γιατί η Excel δεν βλέπει conditional formats γραμμένα μόνο ως calcext;
Η Excel 16 δεν βλέπει calcext conditional formats επειδή διαβάζει ODS conditional formats αποκλειστικά από παιδιά <style:map> των cell styles και αγνοεί τελείως το block calcext:conditional-formats. Το πείραμα που το κλείνει είναι σύντομο: πάρε ένα ODS αποθηκευμένο από LibreOffice, σβήσε τα στοιχεία style:map, και η Excel διαβάζει μηδέν κανόνες· σβήσε αντί αυτού το calcext block, και η Excel εξακολουθεί να διαβάζει όλους. Η LibreOffice συμπεριφέρεται ανάποδα. Το calcext είναι extension namespace της LibreOffice, όχι μέρος του standard ODF, και όταν υπάρχει κανόνας calcext η LibreOffice τον παίρνει και αγνοεί το style:map
Πριν το v2.384.69 το HotXLS έγραφε μόνο calcext, οπότε ODS αρχείο με απολύτως σωστό highlighting άνοιγε στην Excel χωρίς κανέναν value κανόνα και χωρίς κανέναν formula κανόνα. Το HotXLS τώρα γράφει και τις δύο μορφές. Το μισό style:map χρησιμοποιεί τη γραμματική συνθηκών του σχήματος OpenDocument (ODF 1.3 Part 3), με τις ακριβείς γραφές που παράγουν τόσο η Excel 16 όσο και η LibreOffice 26.2 όταν σώζουν ODS:
<!-- Απλοποιημένο. Carrier style για κάθε κελί των A1:A50 (δύο value κανόνες) -->
<style:style style:name="ce3" style:family="table-cell">
<style:map style:condition="cell-content()>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>
<!-- Carrier style για κάθε κελί των C1:C50 (ένας formula κανόνας) -->
<style:style style:name="ce4" style:family="table-cell">
<style:map style:condition="is-true-formula(COUNTIF([.$C:.$C];[.C1])>1)"
style:apply-style-name="CF_Dup"
style:base-cell-address="Orders.C1"/>
</style:style>
Η παγίδα με το style:map είναι ότι ζει σε cell styles, άρα είναι ανά κελί. Κάθε κελί στο range του κανόνα πρέπει να κουβαλά style που κρατά το map, και κενά κελιά συμπεριλαμβανομένων, αλλιώς ο κανόνας απλώς δεν καλύπτει εκείνο το κελί στην Excel. Το HotXLS αντιγράφει το υπάρχον formatting style κάθε κελιού, προσαρτά τα maps, και αφυλοποιεί carrier styles κατά το ζεύγος αρχικού style και κειμένου map, οπότε range 500 κελιών με πανομοιότυπο formatting εξακολουθεί να παράγει ένα style. Ο writer επίσης επεκτείνει τον γραφόμενο πίνακα στο range του κανόνα, που σημαίνει ότι κενές ουραίες σειρές μέσα σε κανόνα εκπέμπονται αντί να πετιούνται. Από το v2.384.69 το styles.xml κουβαλά επίσης κενό cell style Default, ώστε το style:apply-style-name="Default" να έχει πάντα στόχο
Η γραφή calcext που δέχεται στην πραγματικότητα η LibreOffice
Η LibreOffice δέχεται calcext value κανόνα μόνο όταν ο τελεστής σύγκρισης είναι μέρος του κειμένου τιμής, όπως >3 ή between(1,10), και formula κανόνα μόνο όταν γράφεται formula-is(...). Και τα δύο σημεία κόστισαν στο HotXLS ένα release, γιατί οι λάθος γραφές παράγουν κανόνα που εισάγεται χωρίς σφάλμα και μετά ταιριάζει λάθος κελιά
Το πρώτο λάθος ήταν attribute calcext:operator δίπλα στο calcext:value. Διαβάζεται φυσικά, αλλά είναι εφευρεμένο: η LibreOffice δεν ξέρει εκείνο το attribute, οπότε εισήγαγε κάθε value κανόνα ως «ίσο με 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=">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 κανόνες χρησιμοποιούν formula-is, σχετικά refs αγκυρωμένα στο base cell -->
<calcext:condition calcext:apply-style-name="CF_Dup"
calcext:value="formula-is(COUNTIF([.$C:.$C];[.C1])>1)"
calcext:base-cell-address=".C1"/>
Το base cell είναι αυτό που δίνει στα σχετικά references τη σημασία τους. Το HotXLS αγκυρώνει κάθε κανόνα στο πάνω αριστερό κελί της πρώτης περιοχής range του, οπότε τύπος γραμμένος για το C1 αποτιμάται ως C2, C3 και συνεχώς κάτω από το range, ακριβώς όπως κάνει το ίδιο το conditional formatting της Excel. Η έκφραση του κανόνα περνά από τον ίδιο translator με τους τύπους κελιών, οπότε arrays, unions, ολόκληρες στήλες και σημάνσεις $ βγαίνουν στις μορφές που περιγράφηκαν παραπάνω. Στην πλευρά Delphi προσθέτετε κανόνες ακριβώς όπως θα κάνατε για αρχείο .xlsx
uses
lxHandleX;
procedure AddOrderHighlights(Book: TXLSXWorkbook; Sheet: TXLSXWorksheet);
var
Idx: Integer;
Opts: TODSExportOptions;
begin
// Value κανόνες: style:map cell-content()>100 συν calcext value ">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);
// Formula κανόνας σε σύνταξη Excel (διαχωριστικά κόμματα, σχετικό ως προς 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 πίσω στο Delphi
Όταν το HotXLS ανοίγει ODS αρχείο, ο reader του δέχεται και τις δύο διαλέκτους conditional formats και τις δύο γραφές calcext, και δεν μετράει κανόνα δύο φορές όταν το αρχείο τον κουβαλά και στις δύο μορφές. Τα πραγματικά αρχεία έρχονται από τρεις writers, ο καθένας με τις συνήθειές του:
- Παλιό και νέο calcext. Αρχεία με attribute
calcext:operator, συμπεριλαμβανομένων ODS γραμμένων από HotXLS πριν το v2.384.69, εξακολουθούν να περνάνε από το legacy parse. Formula συνθήκες αναγνωρίζονται είτε ωςformula-is(...)είτε ωςis-true-formula(...) - Η γραφή style:map της Excel. Η Excel βάζει πρόθεμα
of:στις συνθήκες, όπως στοof:cell-content-is-between(1,10), και παραλείπει το base cell στους value κανόνες. Και τα δύο γίνονται δεκτά - Κενά κελιά. Excel και LibreOffice βάζουν και οι δύο το map για κενά κελιά στο column default style αντί σε κελί, οπότε ο reader αναλύει column default styles για επαναλαμβανόμενα κελιά πριν συλλέξει maps
- Ξαναχτίσιμο περιοχών. Τα maps συλλέγονται ανά κελί, οπότε αφού διαβαστεί ένα sheet ο reader συγχωνεύει κελιά που μοιράζονται την ίδια συνθήκη και base cell πίσω σε ranges, πρώτα κατά μήκος κάθε σειράς και μετά προς τα κάτω σε αντίστοιχα column spans, και πετάει κανόνα ήδη διαβασμένο από calcext
Η διόρθωση v2.384.72 αφορά number styles, όχι κανόνες. Η Excel 16 και η LibreOffice 26.2 γράφουν και οι δύο το General format ως number style του οποίου το στοιχείο number:number δεν έχει number:decimal-places, τυπικά <number:number number:min-integer-digits="1"/>. Ο reader του HotXLS μεταχειριζόταν το απόν πλήθος ως δύο σταθερά δεκαδικά, οπότε κάθε τιμή στο style Default εισαγόταν με 0.00 και το 1.5 εμφανιζόταν 1.50. Από το v2.384.72 σκέτο number στοιχείο χωρίς δεκαδικά, χωρίς ελάχιστα δεκαδικά, χωρίς grouping και με το πολύ ένα ψηφίο ακεραίου αντιστοιχίζεται σε General, και μοναχικό General αφήνει το κελί χωρίς καθόλου number format. Κείμενο γύρω του κρατιέται, όπως στο General" kg", και grouped αριθμοί κρατούν την προηγούμενη αντιστοίχιση επειδή η Excel δεν έχει grouped General format
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]; // ο indexer Sheets βασίζεται στο 1
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 style της Excel διαβάζεται πίσω χωρίς number format
// από το v2.384.72, αντί για '0.00'
Writeln('A2 format: "', Sheet.Cells[2, 1].NumberFormat, '"');
finally
Book.Free;
end;
end;
Οι τύποι κανόνων γυρίζουν πίσω σε σύνταξη Excel με διαχωριστικά κόμματα, την ίδια μορφή που θα δίνατε στο AddCondFormatExpression, οπότε κανόνας γραμμένος από HotXLS διαβάζεται πίσω ως το πανομοιότυπο string. Για τη γενικότερη εικόνα του τι κρατά και τι πετάει η διαδρομή εισαγωγής ODS, δείτε τον οδηγό round-trip ανοίγματος και αποθήκευσης ODS του HotXLS· για το πώς απλώνονται οι επαναλαμβανόμενες σειρές από Excel και LibreOffice κατά την εισαγωγή, δείτε ODS επαναλαμβανόμενες σειρές ως runs ύψους σειράς
Ποια είναι τα όρια του ODS conditional format interop του HotXLS;
Η προσέγγιση διπλού markup καλύπτει κανόνες σύγκρισης τιμής και formula κανόνες, και σταματά εκεί. Όλα τα άλλα είναι μονομερή ή δεν γράφονται καθόλου:
- Color scales και data bars γράφονται μόνο ως στοιχεία calcext, οπότε η LibreOffice τα δείχνει και η Excel όχι
- Άλλα είδη κανόνων, όπως icon sets, text κανόνες, top-N, above-average και duplicate κανόνες, δεν έχουν ODS έξοδο στον τρέχοντα writer. Ένας text κανόνας συνήθως μπορεί να ειπωθεί ξανά ως formula κανόνας, για παράδειγμα
ISNUMBER(SEARCH("late",B2))πάνω στοB2:B200, που τότε φτάνει και στις δύο εφαρμογές - Κανόνες ολόκληρης στήλης και ολόκληρης σειράς όπως
C:Cαπλώνονται μόνο πάνω στην περιοχή πίνακα που γράφεται στην πραγματικότητα, αντί πάνω σε όλες τις 1.048.576 σειρές, οπότε η Excel βλέπει εκείνους τους κανόνες μόνο σε κελιά που υπάρχουν στο αρχείο - Αρχεία μόνο με style:map. Όταν αρχείο δεν έχει calcext block, το HotXLS ερμηνεύει σχετικά references σε formula κανόνες από την πάνω αριστερή γωνία του ξαναχτισμένου range, όχι με μετατόπιση από το δηλωμένο base cell
- Επικαλυπτόμενοι κανόνες από LibreOffice. Όταν ένα κελί καλύπτεται από πολλούς κανόνες, η LibreOffice γράφει πάνω του μόνο το map του πρώτου κανόνα. Τέτοια αρχεία δεν μπορούν να διαβαστούν πλήρως από σκέτο
style:map, γεγονός που είναι ένας ακόμα λόγος ο reader να προτιμά το calcext όταν υπάρχουν και τα δύο
Το όριο διεργασίας μετράει περισσότερο από όλα αυτά. Οι αστοχίες πίσω από αυτά τα releases πέρασαν από round trips που έγραφαν ODS και το διάβαζαν πίσω με HotXLS, και μερικά θα περνούσαν επίσης χειροκίνητο έλεγχο στη λάθος εφαρμογή: whole-column τύποι δούλευαν στη LibreOffice ενώ η Excel έδειχνε #NAME?, και από το v2.384.66 οι formula κανόνες δούλευαν στη LibreOffice ενώ η Excel εξακολουθούσε να μη δείχνει κανέναν κανόνα μέχρι το v2.384.69. Αν το ODS interop είναι απαίτηση, το acceptance test είναι να ανοίξεις το αρχείο στην Excel και στη LibreOffice και να συγκρίνεις τι δείχνει η καθεμία. Η ίδια πειθαρχία ισχύει και για τα styles στους οποίους δείχνουν οι κανόνες· το άρθρο HotXLS για conditional formatting και styles καλύπτει πώς ορίζονται τα highlight styles από την πλευρά του workbook
Σύντομη αναφορά: ODS που διαβάζουν και οι δύο εφαρμογές
- Δηλώστε
xmlns:ofκαιxmlns:msoxlστη ρίζα τουcontent.xml, αλλιώς η LibreOffice δείχνει#VALUE!για κάθε τύπο (HotXLS από το v2.384.56) - Γράφετε references ως
[.A1], κρατήστε κάθε$, και γράφετε ολόκληρες στήλες και σειρές ως[.A:.A]και[.1:.1](από το v2.384.55 και v2.384.65) - Χρησιμοποιήστε
;για ορίσματα,~για reference unions, και|ανάμεσα σε σειρές inline array - Γράφετε κάθε value ή formula κανόνα ως
<style:map>στο style κάθε καλυμμένου κελιού για την Excel, και ως συνθήκη calcext για τη LibreOffice (από το v2.384.69) - Στο calcext, βάλτε τον τελεστή μέσα στην τιμή (
>3,between(1,10)) και γράφετε τους formula κανόνεςformula-is(...)με base cell (από το v2.384.66 και v2.384.69) - Περιμένετε General number style χωρίς
number:decimal-placesκατά την εισαγωγή· το HotXLS το διαβάζει ως General από το v2.384.72 - Επαληθεύστε κάθε νέο export profile ανοίγοντας το αρχείο και σε Excel και σε LibreOffice, ποτέ μόνο σε μία από τις δύο
Το HotXLS είναι εγγενής βιβλιοθήκη spreadsheet για Delphi και C++Builder που διαβάζει και γράφει XLS, XLSX και ODS χωρίς Excel ή LibreOffice εγκατεστημένα· πλήρης πηγαίος κώδικας, λίστα δυνατοτήτων και αδειοδότηση στη σελίδα HotXLS Delphi spreadsheet component