Files
2026-04-17 14:55:32 -04:00

13 KiB

source_files, generated_at, model, schema_version, sha256
source_files generated_at model schema_version sha256
Common/DTS.Common.SerializationPlus/XLSX/Excel.File.cs
Common/DTS.Common.SerializationPlus/XLSX/Excel.File.Writer.cs
2026-04-16T03:30:27.540490+00:00 Qwen/Qwen3-Coder-Next-FP8 1 6f0085250a497f9b

XLSX Export Module Documentation

1. Purpose

This module implements XLSX (Excel) file export functionality for test data within the DTS.Serialization framework. It extends Serialization.File and implements IWritable<Test> to provide structured export of Test objects to Excel spreadsheets. The module supports exporting engineering units (EU), millivolt (mV), and analog-to-digital converter (ADC) values based on configurable flags, and includes support for filtered/unfiltered data, time-based slicing (Start/Stop), and user-selected export headers. It uses the DocumentFormat.OpenXml library to generate compliant XLSX files, leveraging a template file (XLSXExportTemplate.xlsx) and performing two-pass writing: first for metadata/headers, then for numeric data using SAX-style streaming for performance.

2. Public Interface

DTS.Serialization.XLSX.File

  • public File()
    Constructor that initializes the XLSX file handler with type name "XLSX".

  • public IWriter<Test> Exporter { get; }
    Returns the IWriter<Test> instance used to write test data. Lazily instantiates a Writer on first access using DefaultEncoding. Throws a wrapped exception if instantiation fails.

  • public bool ExportADC { set; }
    Sets the ExportADC property on the underlying Writer instance. Controls whether raw ADC values are exported.

  • public bool ExportEU { set; }
    Sets the ExportEU property on the underlying Writer instance. Controls whether engineering units (EU) values are exported. Default is true.

  • public bool ExportMV { set; }
    Sets the ExportMv property on the underlying Writer instance. Controls whether millivolt (mV) values are exported.

DTS.Serialization.XLSX.File.Writer

  • internal File WriterParent { get; }
    Reference to the owning File instance.

  • public bool ExportADC { get; set; }
    Gets or sets whether to export raw ADC values.

  • public bool ExportEU { get; set; }
    Gets or sets whether to export engineering units (EU) values. Default is true.

  • public bool ExportMv { get; set; }
    Gets or sets whether to export millivolt (mV) values.

  • public double Start { get; set; }
    Start time (in seconds) for data slicing.

  • public double Stop { get; set; }
    Stop time (in seconds) for data slicing.

  • public bool Filtered { get; set; }
    Indicates whether filtered data should be exported.

  • public List<IExportHeader> ExportHeaders { get; set; }
    List of user-selected headers to include in the export (FB 6410). Only headers with IsSelected == true are written.

  • public void Write(string pathname, string id, Test test, bool bFiltering, bool includeGroupNameInISOExport, double minStartTime, int dataCollectionLength)
    Note: This method is declared but has no body in the provided source. Likely a legacy or stub signature.

  • public void Write(string pathname, string id, string dataFolder, Test test, bool bFiltering, bool includeGroupNameInISOExport, FilteredData fd, Test.Module.Channel tmChannel, int channelNumber, BeginEventHandler beginEventHandler, CancelEventHandler cancelEventHandler, EndEventHandler endEventHandler, TickEventHandler tickEventHandler, ErrorEventHandler errorEventHandler, CancelRequested cancelRequested, double minStartTime, int dataCollectionLength)
    Main export method. Writes a Test object to an XLSX file at pathname. Performs:

    • Template file copy and OpenXML document opening.
    • Header row indexing via _headerRowLineIndex (FB 6410).
    • Metadata writing (test date/time, ID, description, channel info, scaling, filter settings).
    • Data scaling via GetDataScaler and precomputation of scalers in _aicToScaler.
    • Optional filtering of EU data using SaeJ211Filter.
    • Two-pass writing: first pass writes headers/metadata; second pass streams data using SAX-style OpenXmlReader/OpenXmlWriter.
    • Interpolation for resampling channels with different sample rates.
    • Progress updates every 1000 samples (UPDATE_INTERVAL).
    • Cleanup: unsets channel data, logs errors, invokes event handlers.
  • public static Common.DAS.Concepts.DataScaler GetDataScaler(Test.Module.AnalogInputChannel currentAnalogChannel)
    Constructs and configures a DataScaler instance from an AnalogInputChannel, including linearization, scaling factors, zero methods, digital channel settings (FB 14469), and excitation voltage properties.

  • protected Cell GetCell(Worksheet worksheet, string xColumn, uint rowIndex, bool bLookForCell = true)
    Retrieves or inserts a cell at the specified location. Uses _rowIndexToRow cache for performance.

  • private static Cell InsertCellInWorksheet(string columnName, uint rowIndex, WorksheetPart worksheetPart, string cellReference, bool bLookForCell)
    Inserts a cell into the worksheet, maintaining OpenXML cell ordering by CellReference.

  • private void WriteTime(WorksheetPart ws, string column, uint row, DateTime time, SharedStringTablePart sharedString)
    Writes a time value as a shared string with number format ID 14 (time format).

  • private void WriteTime(WorksheetPart ws, string column, string headerName, DateTime time, SharedStringTablePart sharedString)
    Overload that writes to the row index associated with headerName (FB 6410).

  • private void WriteDate(WorksheetPart ws, string column, uint row, DateTime date)
    Writes a date as an OLE Automation date (OADate) with number format.

  • private void WriteDate(WorksheetPart ws, string column, string headerName, DateTime date)
    Overload that writes to the row index associated with headerName (FB 6410).

  • private void WriteDouble(WorksheetPart ws, string column, uint row, double value)
    Writes a numeric value directly to a cell.

  • private void WriteDouble(WorksheetPart ws, string column, string headerName, double value)
    Overload that writes to the row index associated with headerName (FB 6410).

  • private void WriteString(WorksheetPart ws, string column, uint row, SharedStringTablePart sharedStringTablePart, string value)
    Writes a string as a shared string.

  • private void WriteString(WorksheetPart ws, string column, string headerName, SharedStringTablePart sharedStringTablePart, string value)
    Overload that writes to the row index associated with headerName (FB 6410). Skips duplicate entries via _alreadyEnteredHeader.

  • private int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
    Adds or retrieves a shared string index. Uses _stringLookup dictionary for O(1) lookup.

  • private static string GetColumn(int index)
    Converts a zero-based column index to Excel column letters (e.g., 0 → "B"). Starts at column B (index 0 → "B").

  • private void AddStyleSheet(SpreadsheetDocument sp)
    Adds a date/time number format (ID 14) to the stylesheet and caches its index in _dateFormatIndex.

  • private void InsertRow(WorksheetPart worksheetPart)
    Inserts an empty row after the last row in the worksheet.

  • private void UpdateProgress(double dValue, TickEventHandler tickEventHandler)
    Invokes the progress event handler if non-null.

  • internal Writer(File fileType, int encoding)
    Constructor initializing Writer base class, setting default export flags (ExportEU = true, others false), and storing WriterParent.

  • public void Initialize(...)
    Note: This method is declared but has no body in the provided source. Likely a stub or unused legacy method.

3. Invariants

  • Export flags are mutually exclusive in practice: While ExportADC, ExportEU, and ExportMV are independently settable, the current implementation writes only EU data by default and does not appear to conditionally include ADC/mV in the final data rows (only scaling factors are written regardless of flags). The flags control writer behavior but may not yet fully gate data output.
  • Header row indexing is precomputed: _headerRowLineIndex is built before writing data and must remain consistent during the export. Headers not in this dictionary are skipped.
  • Channel ordering is deterministic: Channels are sorted by AbsoluteDisplayOrder, then by Number to ensure reproducible column order.
  • Data slicing respects Start/Stop: Pre- and post-trigger sample counts are clamped to Start * SampleRateHz and Stop * SampleRateHz, respectively.
  • Sample rate resampling uses ceiling: Channels with lower sample rates are resampled using rate = ceil(maxSampleRate / channelSampleRate).
  • Interpolation is linear: When step > 0, values are interpolated using a linear increment based on neighboring samples.
  • Shared string table is cached: _stringLookup is initialized once per export and reused for performance.
  • Row caching is per-export: _rowIndexToRow is cleared at the start of Write and reused within a single export.

4. Dependencies

External Dependencies

  • DocumentFormat.OpenXml: Core library for XLSX manipulation.
  • DTS.Common.Enums / DTS.Common.Enums.Sensors: For SensorConstants, IsoViewMode, and digital channel enums.
  • DTS.Common.Interface.ExportData: For IExportHeader and FilteredData.
  • DTS.Common.SerializationPlus: Base classes Serialization.File, Writer<File>, IWriter<Test>, BeginEventHandler, etc.
  • DTS.Common.Utilities.Logging: For APILogger.
  • DTS.Slice.Control: For SaeJ211Filter and UseLegacyTDCSoftwareFiltering.

Internal Dependencies

  • DTS.Common.Concepts.DataScaler: Used for channel scaling and linearization.
  • DTS.Common.DAS.Concepts.DataScaler: Full namespace path used in GetDataScaler.
  • DTS.Test: Test, Test.Module.Channel, Test.Module.AnalogInputChannel, Test.Module.ChannelInfo, Test.Module.Module.
  • DTS.Common.Enums.IsoViewMode: Controls ISO/User code display in header.
  • XLSXExportHeaderLine: Enum-like class (likely static class with GetDescription() methods) defining header names.

Inferred Dependencies

  • XLSXExportTemplate.xlsx: Must exist at runtime relative to AppDomain.CurrentDomain.BaseDirectory\ReportTemplates\.
  • UseLegacyTDCSoftwareFiltering: Global/static flag used in filtering logic (not defined in source).

5. Gotchas

  • ExportADC, ExportEU, ExportMV flags may not fully gate data output: While setters exist and are passed to the Writer, the Write method only writes EU data to the data rows. ADC/mV export may be incomplete or unimplemented.
  • Write(string pathname, string id, Test test, ...) overload has no body: Likely a stub or legacy method; only the 14-parameter overload is implemented.
  • Initialize(...) method has no body: May be unused or intended for future implementation.
  • _rowIndexToRow is a static field: Shared across all Writer instances in the AppDomain. This could cause race conditions in multi-threaded export scenarios (though current code clears it per export).
  • _stringLookup is not thread-safe: Used without locking; safe only because Write is single-threaded per instance.
  • GetColumn starts at index 0 → "B": Column A is skipped; likely intentional for header/data layout.
  • Filtered flag affects both data filtering and filter name display: When Filtered == false, the software filter name is written as "NONE" and cutoff frequency is omitted or set to 0.
  • FB 18024 and FB 6410 references: Bug fixes embedded in comments (e.g., "FB 6410") indicate historical quirks around header row handling and filter display.
  • FB 14469 fix for digital channels: Digital channel properties (Digital, DigitalMode, DigitalMultiplier) must be explicitly set on the scaler; otherwise EU values may be incorrect.
  • FB 14513 rounding error mitigation: Uses Decimal for time offset calculations to avoid double-precision rounding issues.
  • FB 14659 channel ordering fix: Uses AbsoluteDisplayOrder (not display order) to ensure correct channel indexing.
  • Performance optimizations removed: GC calls were commented out due to performance impact (likely legacy 32-bit concern).
  • Two-pass writing complexity: First pass writes headers/metadata; second pass streams data. This is necessary for SAX-style writing but increases code complexity and potential for bugs.
  • minStartTime vs. dStartTime alignment: Time alignment logic (channelOffsetStart) is critical for correct sample indexing across channels with different start times.