SaveSemanticSnapshot 和 ComputeSemanticHash 方法
流式输出带版本号的工作簿语义规范表示,或计算恰好这些字节的 SHA-256
语法
procedure SaveSemanticSnapshot(AStream: TStream); overload; procedure SaveSemanticSnapshot(AStream: TStream; AProfile: TXLSSemanticSnapshotProfile; AOptions: TXLSSemanticSnapshotOptions); overload; function ComputeSemanticHash: WideString; overload; function ComputeSemanticHash( AProfile: TXLSSemanticSnapshotProfile; AOptions: TXLSSemanticSnapshotOptions): WideString; overload;
The methods are exposed by Classic IXLSWorkbook and TXLSWorkbook in lxHandle, and by TXLSXWorkbook in lxHandleX
配置文件和选项类型声明于 lxSemanticSnapshot ,并通过两个工作簿单元均可见
配置文件
| 值 | 含义 |
|---|---|
xlsspContent | 规范的工作簿内容,适用于常规的语义同一性检查 |
xlsspSecurityComplete | 内容加上受支持的不透明安全与保留状态,这些状态被有意排除在常规内容同一性之外 |
选项
| 值 | 包含的状态 |
|---|---|
xlssoIncludeViewerState | 选择、活动视图状态以及其他受支持的面向查看器的状态 |
xlssoIncludeVolatileMetadata | 受支持的时间戳、生产者元数据以及其他有意易变的字段 |
xlssoIncludeFormulaCachedResults | 存储的公式结果和受支持的外部链接缓存,不进行重新计算或外部 I/O |
The option set has type TXLSSemanticSnapshotOptions = set of TXLSSemanticSnapshotOption无参数重载使用 xlsspContent 和空的选项集合
流式输出与同一性规则
SaveSemanticSnapshot写入目标流的当前位置,不会定位、拥有或释放该流- 下游写入失败可能在目标中留下前缀,因此需要原子发布的调用方应先写入临时目标,再替换最终目标
ComputeSemanticHash返回 64 个小写十六进制字符,并以增量方式计算哈希,而无需分配完整的快照缓冲区- 该快照是 HotXLS 语义协议,不是 XLS、XLSX、ODS、CSV 或 PDF 文档
- 仅在协议版本、配置文件和选项集合都一致时才比较快照或哈希
- 该操作不会保存、重新计算、刷新链接、访问外部资源或修改工作簿缓存
现代单元格功能
TXLSSemanticCellStyle.CellControlKind 的类型是 TXLSSemanticCellControlKind,含 xlssControlNone、 xlssControlUnknown和 xlssControlCheckbox; CellControlDefaultState 的类型是 TXLSSemanticCheckboxDefaultState,含 xlssCheckboxUnchecked、 xlssCheckboxChecked和 xlssCheckboxBlank
XLSX 样式读取在不创建单元格的情况下解析直接与继承的控件;规范样式序列化会拒绝 xlssControlUnknown,而不是把未知的属性包当作普通单元格
快照和哈希包含规范化的有效控件矩形,会合并相邻的相等区域,而不把整列展开成单元格;无关的非默认样式叠加保留其既有的不受支持规范化边界
TXLSXWorkbook.ReadSemanticFeatures(xlsxSemanticCellImages, Sheet, AMaxBytes, AMaxItems) 返回按单元格地址为键的分离条目,包括精确编码的 PNG 或 JPEG 字节、内容类型、替代文本和装饰元数据;配额覆盖规范字节和图像条目,超大负载在复制前被拒绝
选择 lcoDrawings 时工作簿比较包含这些图像定义,而 lcoCellStyles和 lcoBlankStyleRegions 包含有效的 Checkbox 格式;仅回退错误匹配不能让不同的图像相等
未知的富值图像图在选定功能比较或快照遍历期间引发 EXLSSemanticSnapshot;这些操作保留工作簿读取租约,不计算被检查的单元格
并发与错误
两个方法在整个遍历期间都持有工作簿读取租约
并发的公开修改会在更改工作簿状态之前以 EXLSWorkbookWriteGuardUnavailable失败,而检测到的世代变更或不受支持的歧义语义结构会引发 EXLSSemanticSnapshot
Delphi 示例
var
Snapshot: TFileStream;
Hash: WideString;
begin
Snapshot:= TFileStream.Create('workbook.semantic', fmCreate);
try
Workbook.SaveSemanticSnapshot(Snapshot,
xlsspSecurityComplete,
[xlssoIncludeFormulaCachedResults]);
finally
Snapshot.Free;
end;
Hash:= Workbook.ComputeSemanticHash;C++Builder 示例
TFileStream *snapshot = new TFileStream(
L"workbook.semantic", fmCreate);
try
{
workbook->SaveSemanticSnapshot(snapshot);
}
__finally
{
delete snapshot;
}
WideString hash = workbook->ComputeSemanticHash();另请参阅
快照引擎不绑定工作簿对象:下面的一切都声明于 lxSemanticSnapshot, and the workbook methods are thin wrappers over the same global entry points
扩展接口
实现 IXLSSemanticWorkbookSource 即可对任意来源生成快照或计算其哈希;还可以选择实现 IXLSSemanticFormulaResolver ,让生成的公式携带已解析的外部引用和已定义名称信息
IXLSSemanticWorkbookSource = interface
procedure WriteCommon(AWriter: TXLSSemanticCanonicalWriter);
end;
IXLSSemanticFormulaResolver = interface
function ResolveFormulaReference(AExternID: Integer;
out AInfo: TXLSSemanticFormulaReferenceInfo): Boolean;
function ResolveFormulaName(ANameID, AExternID: Integer;
out AInfo: TXLSSemanticFormulaNameInfo): Boolean;
end;
TXLSSemanticFormulaReferenceInfo = record
LinkKind: TXLSSemanticFormulaLinkKind;
BookName: WideString;
FirstSheetName: WideString;
LastSheetName: WideString;
end;
TXLSSemanticFormulaNameInfo = record
NameKind: TXLSSemanticFormulaNameKind;
LinkKind: TXLSSemanticFormulaLinkKind;
Name: WideString;
ScopeSheetName: WideString;
BookName: WideString;
end;Inside WriteCommon the writer is an opaque handle: do not call its primitive methods — BeginContainer / EndContainer frame a tagged container and WriteNull, WriteBoolean, WriteUInt32, WriteUInt64, WriteInt32, WriteInt64, WriteBinary64, WriteWideString, and WriteBytes encode one canonical primitive each, with Finish sealing the stream and Finished 报告完成 — 把它传回下方的输出辅助方法,让每个生产者产生完全相同的字节
入口点全局例程
procedure XLSSaveSemanticSnapshot(AStream: TStream; const ASource: IXLSSemanticWorkbookSource; AProfile: TXLSSemanticSnapshotProfile; AOptions: TXLSSemanticSnapshotOptions); function XLSComputeSemanticHash( const ASource: IXLSSemanticWorkbookSource; AProfile: TXLSSemanticSnapshotProfile; AOptions: TXLSSemanticSnapshotOptions): WideString; procedure XLSInitializeSemanticCellStyle(out AStyle: TXLSSemanticCellStyle); function XLSBuiltinSemanticNumberFormat(AId: Word): WideString;
XLSInitializeSemanticCellStyle 会先用规范默认值填充样式记录,再逐个编辑各字段; XLSBuiltinSemanticNumberFormat 把内置数字格式 id(低于 164)映射到其格式字符串,消费方解读生成的样式和解码流时需要它
模型词汇
| Group | Types |
|---|---|
| Sheet | TXLSSemanticSheetKind (worksheet、macro、chart、VBA、unknown)、 TXLSSemanticSheetVisibility (visible、hidden、very hidden)、 TXLSSemanticDefinedNameScope (工作簿或工作表)、 TXLSSemanticRange / TXLSSemanticRanges (合并单元格、条件格式和表格使用的矩形区域) |
| Cell | TXLSSemanticCellKind (blank、number、datetime、text、boolean、error、formula) |
| Style | TXLSSemanticCellStyle (完整规范单元格样式)、带 TXLSSemanticColor (none、automatic、system、ARGB、theme、indexed)和 tint 的 TXLSSemanticColorKind 、 TXLSSemanticBorderEdge / TXLSSemanticBorderStyle、 TXLSSemanticFillPattern、 TXLSSemanticGradientKind / TXLSSemanticGradientStop / TXLSSemanticGradientStops、 TXLSSemanticUnderline、 TXLSSemanticFontVerticalAlign |
| Formula | TXLSSemanticFormulaEncoding (解析树还是不透明文本)、 TXLSSemanticFormulaArrayKind (none、CSE、dynamic)、 TXLSSemanticFormulaNodeKind、 TXLSSemanticFormulaRangeKind、 TXLSSemanticFormulaLinkKind (同表、内部、外部、加载项、DDE、OLE、其他)、 TXLSSemanticFormulaNameKind |
| 绘图与图表 | TXLSSemanticDrawingKind (image、textbox、chart、group、form control)、 TXLSSemanticDrawingAnchorMode (移动且调整大小、仅移动、绝对)、 TXLSSemanticImageFormat、 TXLSSemanticChartFamily |
输出辅助例程
这些全局例程把一个模型片段写入传给 WriteCommon的写入器: XLSWriteSemanticLiteralCell、 XLSWriteSemanticCellStyle、 XLSWriteSemanticColor、 XLSWriteSemanticRanges、 XLSWriteSemanticMerge、 XLSWriteSemanticAxisEntry、 XLSWriteSemanticFormulaTree、 XLSWriteSemanticFormulaDefinition和 XLSWriteSemanticFormulaCell (公式单元格携带数组边界和可选的缓存结果)。 XLSWriteSemanticWorkbookCommon 打开工作簿容器并调用 WriteCommon,自定义来源通常首先调用它