HotXLSはインポートしたExcelチャートの元のChartMLを保持し、型付きモデル内で何も変更されなかったときはバイト単位で再生的する。だからブックを開いて保存し直しても、オブジェクトモデルが表現しないチャートの部分が静かに削ぎ落とされることはない。タイトル、系列、軸を編集すると、HotXLSはゼロからチャートを再生成するのではなく、新しい型付きノードを元のツリーに構造的にマージする
この区別——触れなければ再生、編集すればマージ——こそが、Delphiアプリケーションを、アナリストがExcelで組んだチャートに安全に向けるものだ。型付きモデルからチャートを再生成すると、モデルが知らないものは常に失われる。そしてExcelチャートは、ライブラリが知らないもので満ちている。カスタムスタイル、拡張リスト、代替コンテンツの分岐、アドイン由来の名前空間修飾付き書式設定などだ
なぜブックの保存し直しがチャートを平坦化するのか
通常の実装が、理解できるものを読み、理解できるものを書くからだ。その間にあるすべて——新しいExcelビルドからのextLst、mc:AlternateContentの分岐、モデルにプロパティのない図形効果——はファイルの中に存在し、オブジェクトモデルの中に居場所がなく、保存時に消える。ユーザーが見るのは、グラデーションやカスタムデータラベル、3D効果を失ったチャートだ。そしてブックは理由を説明できない
ブックでPreserveUnsupportedPartsを有効にしておくと、HotXLSはインポート時に元のUTF-8のチャートバイトを、長さとモデル化されたコンテンツの64ビットフィンガープリントとともに保存する。型付きモデルが保存時までに変わっていなければ、元のバイトを書き戻す。XMLの並べ替えも、ホワイトスペースのドリフトも、誰も編集していないチャートのためにUTF-16のコピーがメモリに居座ることもない
var
Workbook: TXLSXWorkbook;
Chart: TXLSXChart;
begin
Workbook := TXLSXWorkbook.Create(nil);
try
Workbook.PreserveUnsupportedParts := True; // set before Open
Workbook.Open('quarterly-review.xlsx');
Chart := Workbook.Sheets[1].Charts[0]; // Sheets[] is 1-based
if Chart.HasPreservedXml then
Log('original ChartML retained; untouched charts replay exactly');
Chart.Title := 'Revenue by region, Q3 2026'; // now the merge path runs
Workbook.SaveAs('quarterly-review-out.xlsx');
finally
Workbook.Free;
end;
end;
マージが保つものとモデルが持つもの
ルールは所有権だ。公開モデルノード——タイトル、系列、キャッシュ、プロットグループ、軸——は新しく生成されたツリーによって決定される。モデル化されていないサブツリーは元のものから持ち越される。この非対称性は意図的であり、少し時間をかけて内面化すべき部分だ。系列の削除が、保存されたXMLから古い系列を蘇らせてはならない。だからモデルが持つものは、モデルが「なくなった」と言っても、モデルから取られる
所有者のないコンテンツは、かつて隣り合っていた一致ノードの隣に再挿入され、extLstはスキーマが要求する場所だから親の最後に留まる。既知のプロパティのクリア——太字フラグの削除、色のドロップ——は、元のツリーから埋めるべきギャップとしてではなく、クリアとして扱われる。同じ近隣の未知の属性は場所を保つ
マークアップ互換性コンテンツは個別の扱いを受ける。パース時にHotXLSはmc:Choiceをスキップしてmc:Fallbackを読む。そのフォールバック分岐がモデルの知るプロットグループを包んでいれば、マージは新しい型付きコンテンツをフォールバックサブツリーの中に書き戻す。このステップがなければ、保存は新しいプロットグループを吐き出し、古いものをフォールバックの中に残し、チャートは2つを抱えることになる
1つのチャートをオプトアウトする
ClearPreservedXmlは1つのチャートの元のXMLとフィンガープリントを落とし、次回の保存はそのチャートを純粋に型付きモデルから再ビルドする。これはチャートごとの決定であり、ブックレベルのPreserveUnsupportedPartsは、インポート時に保存状態を構築するかどうかを相変わらず支配する
忠実なチャートではなくクリーンなチャートが欲しいときに手を伸べること。たとえば、テンプレートチャートが古い企業テーマからの書式を持ち、操作の要点がそれを捨てることである場合だ。デバッグの反射として手を伸べてはいけない。編集後に間違って描画されるチャートは、保存の問題よりもモデリングの問題であることが多く、保存されたXMLをクリアすると証拠を破壊する
複合チャートと第2の軸
AddPlotGroupは、各プロットグループが独自のチャートファミリーと独自の主軸・第2軸の割り当てを保つ、順序付き複合チャートを構築する。これこそ、遍在するビジネスチャートが求めるものだ。左軸に列としての売上、右に線としてのマージン率
チャートは主と第2のカテゴリ軸・値軸に加え系列軸を公開し、位置、識別子、交差、日付単位、ラベル間隔、可視性をカバーする型付きのカテゴリ、値、日付、系列軸の設定を持つ。以前のフラットなAPI——ChartType、AddSeries、フラットなSeriesコレクション——は引き続き主プロットグループをアドレス指定し、既存のコードはその下のモデルがすべての順序付きグループを保持したまま動き続ける
var
Chart: TXLSXChart;
Line: TXLSXChartPlotGroup;
begin
// Column chart anchored over rows 1..15, columns 5..12
Chart := Sheet.Charts.Add(xlsxChartColumn, 'Revenue and margin',
1, 5, 15, 12);
Chart.AddSeries('Revenue', 'Data!$A$2:$A$13', 'Data!$B$2:$B$13');
// Second plot group: a line, read against the secondary value axis
Line := Chart.AddPlotGroup(xlsxChartLine, xlsxAxisSecondary);
Line.AddSeries('Margin %', 'Data!$A$2:$A$13', 'Data!$C$2:$C$13');
end;
このモデルが存在する前は、複合チャートを開いて保存し直すと、1つのチャートファミリーに潰れ、第2、日付、系列の各軸を失った。チャートの数式参照とキャッシュされた系列値は、ブックのコピーや開き・保存のサイクルを同じように生き残り、チャートアンカーはリレーションシップ識別子でチャートパーツと突合される。だからリレーションシップエントリを並べ替えるアプリケーションが、ワークシートの位置の間でチャートの内容を入れ替えることはもうない
マニュアルレイアウトの罠
プロットエリア、タイトル、軸タイトル、凡例を手作業で配置するときは、4つの座標をすべて書くこと。Officeはx、y、w、hがそのうち1つでも存在するときは完全なグループとして要求し、そうでなければmanualLayout全体を無視する。HotXLSはその理由から常に完全な矩形を吐き出し、SetPositionAndSizeが1回の呼び出しでそれを設定し有効にする
もう2つの細部が、仕様の完全な自由度ではなくExcelに従う。位置はxModeとyModeをedgeに設定して書かれ、サイズはwModeとhModeにfactorを使う。それがExcelが書くものであり、他の組合せを変換するものだからだ。そしてlayoutTargetはプロットエリアにだけ書かれ、タイトルや凡例には決して書かれない。Microsoftの実装ノートがそこではそれを禁じているからだ
ブックのラウンドトリップにこれを組み込む
チャート保存は、一般的なポリシーの1つのインスタンスである。よそで作成されたドキュメントを編集するライブラリは、頼まれたことだけを変え、それ以外は変えるべきでないというポリシーだ。同じ推理が、テーマ、計算チェーン、ワークシート拡張に関するHotXLSを駆動する。テーマ、extLst、calcChainのロスレスラウンドトリップ、VBAと外部リンクの保存のノートで説明されている。チャートオーサリング面そのもの、つまりDelphiからのチャート作成、画像と図の配置については、HotXLSのチャート、画像、図の解説を参照のこと
HotXLSはネイティブのDelphiとC++BuilderコードからXLSXチャートを読み、編集し、書き出し、マシンにExcelのインストールを必要としない。これこそが忠実度をオートメーションの問題ではなくライブラリの問題にするものだ。HotXLSスプレッドシートコンポーネントページにチャート機能一覧とトライアルダウンロードがある