--- source_files: - Common/DTS.Common.Import/XML/XMLPre20ParseGroupTemplates.cs - Common/DTS.Common.Import/XML/XMLParseMMECustomDirections.cs - Common/DTS.Common.Import/XML/XMLParseMMECustomTestObjects.cs - Common/DTS.Common.Import/XML/XMLParseMMECustomPositions.cs - Common/DTS.Common.Import/XML/XMLParseMMECustomFineLoc3s.cs - Common/DTS.Common.Import/XML/XMLParseMMECustomFineLoc2s.cs - Common/DTS.Common.Import/XML/XMLParseMMECustomFineLoc1s.cs - Common/DTS.Common.Import/XML/XMLParseSensorModels.cs - Common/DTS.Common.Import/XML/XMLParseMMECustomFilterClasses.cs - Common/DTS.Common.Import/XML/XMLParseMMECustomChannels.cs - Common/DTS.Common.Import/XML/XMLParseMMECustomMainLocations.cs - Common/DTS.Common.Import/XML/XMLParseMMECustomPhysicalDimensions.cs - Common/DTS.Common.Import/XML/XMLPre20ParseSensors.cs - Common/DTS.Common.Import/XML/XMLParseUsers.cs - Common/DTS.Common.Import/XML/XMLParseBase.cs - Common/DTS.Common.Import/XML/XMLParseTestEngineerDetails.cs - Common/DTS.Common.Import/XML/XMLParseLabDetails.cs - Common/DTS.Common.Import/XML/XMLParseGlobalSettings.cs - Common/DTS.Common.Import/XML/XMLPre20ParseDASList.cs - Common/DTS.Common.Import/XML/XMLParseCustomerDetails.cs - Common/DTS.Common.Import/XML/XMLParseSensors.cs - Common/DTS.Common.Import/XML/XMLParseDASList.cs - Common/DTS.Common.Import/XML/XMLParseGroupTemplates.cs - Common/DTS.Common.Import/XML/XMLParseCalibrations.cs - Common/DTS.Common.Import/XML/XMLPre20ParseCalibrations.cs - Common/DTS.Common.Import/XML/XMLParseGroups.cs - Common/DTS.Common.Import/XML/XMLParseTestSetups.cs generated_at: "2026-04-16T02:07:16.226597+00:00" model: "Qwen/Qwen3-Coder-Next-FP8" schema_version: 1 sha256: "87dec39982bd8179" --- # XML Import Parsers Module Documentation ## 1. Purpose This module provides a family of XML parsing classes responsible for deserializing versioned XML export files into the system’s in-memory `ImportObject` representation during data import operations. Each concrete parser targets a specific data domain (e.g., sensors, groups, channels, test setups, calibration data, MME custom objects) and handles both direct parsing and migration logic for pre-2.0 XML formats. These parsers implement the `IParseVariant` interface, inherit from `XMLParseBase`, and coordinate with other parsers (e.g., via constructor injection) to resolve cross-references and normalize identifiers across related entities. The module serves as the core deserialization layer for backward-compatible XML imports, ensuring robust handling of schema evolution and data integrity constraints. ## 2. Public Interface All classes inherit from `XMLParseBase` and implement the abstract method `Parse(ref ImportObject importObject)`. Below are the public classes and their key behaviors. ### `XMLParseBase` - **Constructor**: `XMLParseBase(XmlElement root, double importedVersion, Func isCancelled = null, bool skipNormalizing = false)` - Stores the XML root node, imported file version, cancellation token, and normalization flag. - Initializes internal XML writer and mapping dictionaries (`_dasIdMapping`, `_groupIdMapping`, `_sensorIdMapping`, `_channelIdMapping`) for cross-entity ID normalization. - **Protected Methods**: - `XmlElement GetXmlElement()` – Finalizes XML writing and returns the constructed `XmlElement`. - `bool IsCancelled()` – Invokes the cancellation token (defaults to `() => false`). ### `XMLParseSensors` - **Constructor**: `XMLParseSensors(XmlElement root, double importedVersion, Func isCancelled = null, bool skipNormalizing = false)` - **Public Methods**: - `XmlElement ConvertSensors(IEnumerable sensors)` – Normalizes sensor `DatabaseId`s (assigns negative IDs starting at -2), updates `_sensorIdMapping`, and writes normalized XML. - `IEnumerable ParseSensors(XmlElement root)` – Parses `SensorData` objects from XML nodes; skips non-`XmlElement` nodes. ### `XMLPre20ParseSensors` - **Constructor**: `XMLPre20ParseSensors(XmlElement root, double importedVersion, XMLParseSensors xmlParseSensors, Func isCancelled = null)` - **Public Methods**: - `XmlElement MigrateSensors(IEnumerable sensors)` – Migrates pre-2.0 sensor data by assigning negative `DatabaseId`s (starting at -1) and writing to XML. - **Behavior**: Parses sensors, migrates them to the new schema, then delegates to `_xmlParseSensors.ParseSensors()` for final parsing. ### `XMLParseDASList` - **Constructor**: `XMLParseDASList(XmlElement root, double importedVersion, Func isCancelled = null, bool skipNormalizing = false)` - **Public Methods**: - `List ParseDASList(XmlElement root)` – Parses `DASHardware` objects; filters out entries with invalid `DASType` (logs serial numbers to `invalidDAS` list, but does not report errors). - `XmlElement ConvertDASList(List dasList)` – Normalizes `DASId`s (starting at -2) and updates `_dasIdMapping`. - **Behavior**: On import, validates `DASType` enum values; skips invalid entries silently. ### `XMLPre20ParseDASList` - **Constructor**: `XMLPre20ParseDASList(XmlElement root, double importedVersion, XMLParseDASList xmlParseDASList, Func isCancelled = null)` - **Public Methods**: - `List ParsePre20DASList(XmlElement root)` – Parses pre-2.0 `DASHardware` objects. - `XmlElement MigratePre20DASList(List dasList)` – Assigns negative `DASId`s (starting at -1) and writes to XML. - **Behavior**: Migrates pre-2.0 DAS list, then delegates to `_xmlParseDASList.ParseDASList()`. ### `XMLParseGroups` - **Constructor**: `XMLParseGroups(XmlElement root, double importedVersion, Func isCancelled = null)` - **Public Methods**: - `List ParseGroups(XmlElement root, ref ImportObject importObject)` – Parses groups, resolving channel references to imported sensors/DAS via lookup dictionaries. Handles both pre-2.0 (name-based) and post-2.0 (ID-based) group IDs in `_groupIdMapping`. - `XmlElement ConvertGroups(List staticGroups)` – Normalizes group `Id`s (starting at -2), DAS/sensor IDs in channels (using `_dasIdMapping`/`_sensorIdMapping`), and writes to XML. Silently sets `SensorId = 0` for deleted sensors (FB 14308). - **Behavior**: Normalizes group and channel IDs; handles sensor deletion gracefully. ### `XMLParseGroupTemplates` - **Constructor**: `XMLParseGroupTemplates(XmlElement root, double importedVersion, ISO.ISO13499FileDb iSO13499FileDb, Func isCancelled = null)` - **Public Methods**: - `IEnumerable ParseGroupTemplates(ref ImportObject importObject, XmlElement root)` – Parses group templates, resolving channels from `importObject.CustomChannels()`. Enforces that referenced ISO test objects exist in `importObject.TestObjects()` (throws `NotSupportedException` if missing, FB 8790). - **Behavior**: Requires pre-parsed custom channels and test objects; validates test object existence. ### `XMLParseTestSetups` - **Constructor**: `XMLParseTestSetups(XmlElement root, double importedVersion, Func isCancelled = null, bool skipNormalizing = false)` - **Public Methods**: - `XmlElement ConvertTestTemplates(IEnumerable testTemplates, ImportObject importObject)` – Normalizes group IDs, channel IDs (using `_groupIdMapping`, `_channelIdMapping`), and DAS/sensor IDs in channels. Handles missing static group IDs (sets to `null`) and deleted sensors (sets `SensorId = 0`, FB 14308). - `IEnumerable ParseTestTemplate(ImportObject importObject, XmlElement root)` – Parses test setups using lookup dictionaries for test objects, groups, customer/lab details, sensors, etc. Catches and logs parsing errors as warnings (FB 36879). - **Behavior**: Requires pre-parsed entities (groups, sensors, etc.) to resolve references; handles missing/invalid references gracefully. ### `XMLParseCalibrations` - **Constructor**: `XMLParseCalibrations(XmlElement root, double importedVersion, Func isCancelled = null)` - **Public Methods**: - `XmlElement ConvertCalibrations(IEnumerable calibrations)` – Writes normalized calibration XML. - `IEnumerable ParseCalibrations(XmlElement root)` – Parses calibrations with version-specific logic: - For `importedVersion >= DataPROPre20XmlVersion`: Direct parsing. - For `importedVersion == 1.0`: Sets `AtCapacity = false` and infers `SensitivityUnits` (mV/EU, mV/V/EU, or NONE) based on calibration type. ### `XMLPre20ParseCalibrations` - **Constructor**: `XMLPre20ParseCalibrations(XmlElement root, double importedVersion, XMLParseCalibrations xmlParseCalibrations, Func isCancelled = null)` - **Behavior**: Parses pre-2.0 calibrations, adds them to sensors via `AddToSensor()`, then delegates normalization and re-parsing to `_xmlParseCalibrations`. ### `XMLParseMMECustom*` Parsers (e.g., `XMLParseMMECustomChannels`, `XMLParseMMECustomPositions`, etc.) - **Common Pattern**: - **Constructor**: `XMLParseMMECustom* (XmlElement root, double importedVersion, Func isCancelled = null)` - **Public/Protected Methods**: - `ParseCustom* (XmlElement root)` – Parses a list of MME objects (e.g., `ISO.MMEPossibleChannels`, `ISO.MMEPositions`) from XML child nodes. - `Parse(ref ImportObject importObject)` – Adds parsed list to `importObject` via `AddCustom*()` methods. - **Behavior**: Iterates child `XmlElement`s, calls `ReadXML()` on each, and respects cancellation. No normalization or migration logic (assumes current-version format). ### `XMLPre20ParseGroupTemplates` - **Constructor**: `XMLPre20ParseGroupTemplates(XmlElement root, double importedVersion, XMLParseGroupTemplates xmlParseGroupTemplates, Func isCancelled = null)` - **Behavior**: Delegates parsing to `_xmlParseGroupTemplates.ParseGroupTemplates()`; no migration logic visible. ### `XMLParseUsers` - **Constructor**: `XMLParseUsers(XmlElement root, double importedVersion, IEnumerable uiItems, Func isCancelled = null)` - **Behavior**: Parses `User` objects using `User.ReadXML()`, passing `uiItems` for UI context. ### `XMLParseTestEngineerDetails`, `XMLParseLabDetails`, `XMLParseCustomerDetails` - **Pattern**: Parse → Convert → Re-parse → Add to `importObject`. - `Parse*()` – Initial parse. - `Convert*()` – Writes parsed objects to XML. - Re-parse normalized XML to ensure consistency. - **Behavior**: All use `Convert*()` to normalize and re-parse; no ID mapping beyond XML structure. ### `XMLParseGlobalSettings` - **Constructor**: `XMLParseGlobalSettings(XmlElement root, double importedVersion, Func isCancelled = null)` - **Behavior**: Parses `` and `` child elements into a `Dictionary`. ## 3. Invariants - **ID Normalization**: All parsers that normalize IDs (e.g., `XMLParseSensors`, `XMLParseDASList`, `XMLParseGroups`, `XMLParseTestSetups`) assign negative integer IDs starting at -1 or -2 (to avoid conflicts with database IDs). Mappings are stored in static dictionaries (`_sensorIdMapping`, `_dasIdMapping`, `_groupIdMapping`, `_channelIdMapping`) and used during cross-entity resolution. - **Cancellation Handling**: All parsers check `IsCancelled()` before processing each node and return partial results if cancelled. - **XML Node Validation**: All parsers skip non-`XmlElement` nodes (e.g., whitespace, comments) during iteration. - **Version-Specific Parsing**: Calibrations and sensors have distinct parsing logic for `importedVersion == 1.0` vs. newer versions. - **Group Template Validation**: `XMLParseGroupTemplates` enforces that referenced ISO test objects exist in `importObject.TestObjects()`; throws `NotSupportedException` if missing. - **DAS Type Validation**: `XMLParseDASList` filters out `DASHardware` with invalid `DASType` enums but does not report errors (silently drops entries). - **Sensor Deletion Handling**: Group and Test Setup parsers set `SensorId = 0` for deleted sensors (FB 14308) to avoid import failures. ## 4. Dependencies ### Internal Dependencies - **Imports**: - `DTS.Common.Import.Interfaces` (`ImportObject`, `IParseVariant`, `IImportNotification`, `ImportStatus`, `ImportError`, `ImportSeverityError`) - `DTS.Common.Interface.*` (e.g., `GroupTemplate`, `Groups.GroupList`, `Sensors`, `Channels`) - `DTS.SensorDB` (`SensorModel`, `SensorData`, `SensorCalibration`) - `DataPROWin7.DataModel` (`DASHardware`, `TestObjectTemplate`) - `ISO.*` (e.g., `MMEPossibleChannels`, `MMETestObjects`, `MMEPositions`, `TestEngineerDetails`, `CustomerDetails`, `LabratoryDetails`) - `System.Xml` (`XmlElement`, `XmlDocument`, `XmlWriter`) - **Shared State**: - Static dictionaries in `XMLParseBase` (`_dasIdMapping`, `_groupIdMapping`, `_sensorIdMapping`, `_channelIdMapping`) are shared across parsers in the same import session. - `ImportNotification` property used for status updates (settable via property). - **Constructor Injection**: - Pre-2.0 parsers (`XMLPre20ParseSensors`, `XMLPre20ParseDASList`, `XMLPre20ParseCalibrations`, `XMLPre20ParseGroupTemplates`) depend on their post-2.0 counterparts to perform normalization and final parsing. ### External Dependencies - `DataPROWin7.DataModel.DASHardware.ReadXML()` – Static method for pre-2.0 DAS parsing. - `ISO.*.ReadXML()` – Static methods for MME object parsing (e.g., `ISO.MMEPossibleChannels.ReadXML()`). - `User.ReadXML()` – Static method for user parsing. - `SensorData.ReadXML()`, `SensorCalibration.ReadXML()` – Static methods for sensor/calibration parsing. - `DataPROWin7.DataModel.TestObjectTemplate.ReadXML()` – Static method for group template parsing. ## 5. Gotchas - **Silent DAS Filtering**: `XMLParseDASList.ParseDASList()` silently drops DAS entries with invalid `DASType` enums (no error logged or reported). - **ID Mapping Side Effects**: Static ID mappings in `XMLParseBase` are shared across parsers; clearing them (e.g., in `XMLParseDASList` constructor) may affect other parsers if not coordinated. - **Version-Specific Calibration Logic**: For `importedVersion == 1.0`, `XMLParseCalibrations` mutates calibration records (e.g., sets `AtCapacity = false`, infers `SensitivityUnits`). This logic is duplicated in `XMLPre20ParseCalibrations`. - **FB References**: Several parsers reference internal bug IDs (e.g., FB 8790, FB 14308, FB 36879) in comments or exceptions; these are internal tracking references. - **Test Setup Reference Resolution**: `XMLParseTestSetups.ParseTestTemplate()` uses lookup dictionaries built from `importObject` entities; if entities are not parsed in the correct order, lookups may fail (e.g., missing groups/sensors). - **Group Template Test Object Validation**: `XMLParseGroupTemplates` throws `NotSupportedException` if a referenced ISO test object is missing; this is a hard failure. - **XML Writer State**: `XMLParseBase` uses a shared `XmlWriter` instance per parser; reusing the same writer across multiple `Convert*()` calls without reinitialization may cause issues (though current code creates a new `_doc` per instance). - **Pre-2.0 Migration Assumptions**: `XMLPre20Parse*` parsers assume the target parser (`_xmlParse*`) handles normalization; no validation that the target parser is compatible with the migrated XML structure. - **Group ID Mapping Ambiguity**: `XMLParseGroups` uses `_groupIdMapping` with keys as `g.Id.ToString()` (post-2.0) or `g.Name` (pre-2.0); this dual-key approach may cause issues if group names collide with numeric IDs. - **Channel ID Normalization**: `XMLParseTestSetups` normalizes channel IDs *after* normalizing group IDs; order of normalization matters for cross-references.