tbf/TBF/Rig/Output/DB/ResultsWriter/ResultsWriterResultsDlg.cs
Marek Frniak 054075a341 <Feat>: Add XML result generation with file and MSSQL output support, increase revision to 3.9.3145.100
Cause:

- ResultsWriter required a generic way to generate customer-specific XML result data from TBF measurement results.
- The customer reference XML contains example runtime values and repeated result structures, so it cannot be used directly as the generated output.
- TBF result variables must be explicitly mapped to destinations in the customer XML structure.
- The generated XML result data must support two output targets:
  - direct creation of an XML file,
  - delivery of the XML payload to a Microsoft SQL stored procedure.
- Preview generation must allow the XML structure and configured mappings to be verified without executing the production database write.
- Increase revision to 3.9.3145.100.

Solution:

1. Added XML reference analysis
   - Creates a clean base XML structure.
   - Extracts the repeating result prototype.
   - Prevents sample runtime values from the customer reference XML from leaking into generated results.
2. Added configurable TBF-to-XML result mapping
   - Allows explicit mapping of TBF result variables to customer XML destinations.
   - Supports one-time and repeating XML destinations.
   - Keeps the mapping independent of the semantic meaning of customer XML attribute names.
3. Added XML destination viewer and configurator
   - Shows the current mapping.
   - Highlights repeating destinations.
   - Identifies already used one-time destinations.
4. Added runtime XML result generation
   - Uses the configured TBF-to-XML mappings.
   - Uses measurement procedure result data.
   - Builds the output from the clean base XML and repeating XML prototype.
   - Generates repeated result records according to the executed measurement procedure.
5. Added simulation-based Preview request
   - Generates a complete XML payload using simulation values.
   - Allows XML structure and mapping verification before production execution.
   - Does not execute the production stored procedure.
6. Added direct XML file output support to UniDataStorageWriter
   - Supports File / .xml as a physical output target.
   - Creates the generated XML result file in the configured output directory.
7. Added Microsoft SQL stored-procedure XML output
   - Supports Microsoft SQL / StoredProcedure as a physical output target.
   - Passes the generated XML payload through the configured stored procedure parameter.
8. Added optional XML payload archiving
   - Allows generated XML payloads to be stored in the configured Payload archive.
   - Can be used together with the Microsoft SQL stored-procedure output.
9. Kept ResultsWriter independent of the physical output target
   - ResultsWriter generates the result payload.
   - UniDataStorageWriter decides how and where the payload is physically written.
   - The same ResultsWriter XML generation mechanism is therefore used for both XML file and MSSQL outputs.
10. Increased revision
   - Updated revision to 3.9.3145.100.
2026-09-02 12:05:10 +02:00

192 lines
4.8 KiB
C#

///
/// Copyright (c) 2026 Sensus Slovensko a.s.
///
using Results;
using Results.Forms;
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using TBF.Resources;
namespace TBF.Rig.Output.DB.ResultsWriter
{
/// <summary>
/// Configures ResultsWriter result items and optional XML destinations.
/// </summary>
public partial class ResultsWriterResultsDlg : Form
{
private string payloadTemplatePath;
public IList<WMeterRsltItemSpec> SelectedItems
{
set { resultsConfigCtrl.SelectedItems = value; }
get { return resultsConfigCtrl.SelectedItems; }
}
/// <summary>
/// Gets or sets the customer XML reference path.
/// </summary>
public string PayloadTemplatePath
{
get { return payloadTemplatePath; }
set { payloadTemplatePath = value; }
}
public ResultsWriterResultsDlg()
{
InitializeComponent();
Icon =
Properties.Resources.TBF_icon;
resultsConfigCtrl.SupressTestIDColumn =
true;
}
private void ResultsWriterResultsDlg_Load(
object sender,
EventArgs e)
{
Text =
"ResultsWriter configuration";
okButton.Text =
Strings.OkBtnText;
cancelButton.Text =
Strings.CancelBtnText;
resultsConfigCtrl.Unlocked =
true;
ConfigureCaptionEditor();
}
private void ConfigureCaptionEditor()
{
bool xmlMode =
!string.IsNullOrWhiteSpace(
PayloadTemplatePath);
if (!xmlMode)
{
resultsConfigCtrl.CaptionPicker =
null;
resultsConfigCtrl.CaptionColumnText =
"Caption";
return;
}
resultsConfigCtrl.CaptionPicker =
PickXmlDestination;
resultsConfigCtrl.CaptionColumnText =
"Destination [...]";
}
private string PickXmlDestination(
WMeterRsltItemSpec editedItem)
{
if (editedItem == null)
return null;
using (XmlDestinationPickerDlg dlg =
new XmlDestinationPickerDlg())
{
dlg.TemplatePath =
PayloadTemplatePath;
dlg.CurrentSourceName =
editedItem.Name;
dlg.CurrentDestinationPath =
editedItem.Caption;
dlg.ConfiguredMappings =
BuildConfiguredMappings(
editedItem);
if (dlg.ShowDialog(this) ==
DialogResult.OK)
{
return dlg.SelectedDestinationPath;
}
}
return null;
}
private IDictionary<string, IList<string>> BuildConfiguredMappings(
WMeterRsltItemSpec editedItem)
{
Dictionary<string, IList<string>> mappings =
new Dictionary<string, IList<string>>(
StringComparer.Ordinal);
if (resultsConfigCtrl.SelectedItems != null)
{
foreach (WMeterRsltItemSpec item
in resultsConfigCtrl.SelectedItems)
{
if (item == null ||
object.ReferenceEquals(
item,
editedItem) ||
string.IsNullOrWhiteSpace(
item.Caption))
{
continue;
}
AddMapping(
mappings,
item.Caption,
item.Name);
}
}
return mappings;
}
private void AddMapping(
IDictionary<string, IList<string>> mappings,
string path,
string sourceName)
{
if (string.IsNullOrWhiteSpace(path))
return;
IList<string> names;
if (!mappings.TryGetValue(
path,
out names))
{
names =
new List<string>();
mappings.Add(
path,
names);
}
if (!names.Contains(sourceName))
names.Add(sourceName);
}
private void okButton_Click(
object sender,
EventArgs e)
{
DialogResult =
DialogResult.OK;
Close();
}
}
}