Skip to content

Latest commit

 

History

History
307 lines (229 loc) · 9.36 KB

File metadata and controls

307 lines (229 loc) · 9.36 KB

RDL to TX Text Control Template Converter

This solution contains a reusable converter for importing Microsoft SSRS RDL report definitions and generating editable TX Text Control templates.

The converter is intentionally not an SSRS renderer. It reads the report structure, extracts the template intent, and creates a DOCX or TX Text Control template that can be edited and used with TX Text Control MailMerge.

Projects

  • TextControl.RdlImport: reusable conversion engine.
  • TextControl.RdlImport.Tests: parser, mapper, generator, and integration tests.
  • TextControl.RdlImport.Tests/TestData/Rdl: sample RDL fixtures.
  • TextControl.RdlImport.Tests/TestOutput: generated DOCX, TX, and JSON files from test runs.

Architecture

The library is split into small layers:

  • Parsing: reads RDL XML into a neutral RDL model.
  • Model: contains RDL concepts such as reports, textboxes, tablix regions, groups, page settings, images, subreports, and styles.
  • Analysis: creates a JSON-friendly conversion report with supported features, warnings, unsupported items, and a quality score.
  • Mapping: maps the RDL model to a neutral template document model.
  • Generation: writes the template model with TX Text Control ServerTextControl.

TX-specific code is isolated in TxTemplateGenerator. It sets:

ServerTextControl.EntryAssembly = typeof(TxTemplateGenerator).Assembly;

This keeps licensing/package ownership in the reusable library assembly.

Supported Features

Current supported RDL features include:

  • root-level Body/Page
  • RDL 2016 ReportSections
  • page size and margins
  • page headers and footers
  • textboxes
  • positioned textboxes as paragraphs with indentation
  • same-row positioned textboxes as layout tables
  • embedded images
  • inline and fixed-position images
  • tablix tables
  • nested tablix tables
  • tablix row hierarchy parsing
  • detail/group-aware merge block placement
  • TX merge blocks as SubTextParts named txmb_<DataSetName>
  • nested merge blocks when the parent block is created before nested block insertion
  • ApplicationField merge fields with visible text such as «InvoiceNo»
  • INCLUDETEXT fields for subreports
  • subreport parameter mappings as adjacent merge fields
  • RDL report variables for literal style values, for example color variables
  • table column widths
  • table row heights
  • cell background colors
  • cell borders
  • cell padding
  • vertical alignment
  • paragraph alignment
  • font family
  • font size
  • text color
  • bold
  • italic
  • underline
  • strikeout
  • static text, field expressions, parameter expressions, and simple concatenation

Unsupported or partial areas are reported in the conversion JSON. Subreports are converted as INCLUDETEXT fields; referenced child RDL files are not expanded inline.

Public API

The converter supports file, stream, and in-memory workflows.

File To File

var converter = new RdlToTxConverter();

RdlConversionResult result = converter.Convert(new RdlConversionOptions
{
    InputFile = @"C:\Reports\invoice.rdl",
    OutputFile = @"C:\Reports\invoice.docx",
    ReportFile = @"C:\Reports\invoice.json",
    OutputFormat = TxTemplateFormat.Docx
});

To save native TX Text Control format:

converter.Convert(new RdlConversionOptions
{
    InputFile = @"C:\Reports\invoice.rdl",
    OutputFile = @"C:\Reports\invoice.tx",
    OutputFormat = TxTemplateFormat.InternalUnicode
});

Stream To Stream

Use this for web uploads, database blobs, cloud storage, or any pipeline that should avoid file paths.

using Stream rdlInput = GetUploadedRdlStream();
using MemoryStream txOutput = new();
using MemoryStream reportJson = new();

var converter = new RdlToTxConverter();

RdlConversionResult result = converter.Convert(new RdlStreamConversionOptions
{
    InputStream = rdlInput,
    OutputStream = txOutput,
    ReportStream = reportJson,
    ReportName = "invoice",
    OutputFormat = TxTemplateFormat.InternalUnicode
});

byte[] txBytes = txOutput.ToArray();
byte[] reportBytes = reportJson.ToArray();

By default, stream conversion leaves caller-provided streams open. Set LeaveOpen = false if the converter should dispose them.

Byte Array / Memory

Use this when the RDL is already loaded as bytes and the generated template should also be returned as bytes.

byte[] rdlBytes = File.ReadAllBytes(@"C:\Reports\invoice.rdl");

var converter = new RdlToTxConverter();

RdlMemoryConversionResult result = converter.ConvertToMemory(
    rdlBytes,
    TxTemplateFormat.Docx,
    "invoice");

byte[] docxBytes = result.Document;
byte[] reportJsonBytes = result.ReportJson;
ConversionReport report = result.Conversion.ConversionReport;

For document bytes only:

byte[] txBytes = converter.ConvertDocumentToMemory(
    rdlBytes,
    TxTemplateFormat.InternalUnicode,
    "invoice");

Analyze Only

RdlConversionResult analysis = converter.Analyze(@"C:\Reports\invoice.rdl");

Console.WriteLine(analysis.ConversionReport.QualityScore);

Output Formats

TxTemplateFormat.Docx

  • Saved through TX Text Control as WordprocessingML/DOCX.
  • Useful for inspection, Word editing, and compatibility checks.

TxTemplateFormat.InternalUnicode

  • Native TX Text Control format.
  • Preserves TX structures such as SubTextPart merge blocks.
  • Recommended for runtime TX Text Control template workflows.

The generator uses the TX byte-array save API:

tx.Save(out byte[] documentBytes, BinaryStreamType.WordprocessingML);
tx.Save(out byte[] documentBytes, BinaryStreamType.InternalUnicodeFormat);

Test Fixtures

The test project contains realistic fixtures that exercise different features:

  • invoice-basic.rdl: basic invoice with line-item merge block.
  • inventory-tabular.rdl: simple inventory table.
  • letter-parameters.rdl: parameter fields.
  • sales-order-alignment.rdl: paragraph and numeric alignment.
  • positioned-layout.rdl: positioned paragraphs.
  • multi-textbox-row.rdl: same-row positioned textboxes as layout tables.
  • embedded-image-logo.rdl: fixed-position embedded image.
  • embedded-image-inline.rdl: inline embedded image.
  • header-footer-basic.rdl: headers, footers, and fields in header/footer parts.
  • styled-table-cells.rdl: table cell colors, borders, padding, row heights, text color, and inline image inside a cell.
  • nested-tables.rdl: nested tablix and nested merge blocks.
  • report-sections-subreports.rdl: RDL 2016 sections, variables, subreports as INCLUDETEXT.
  • complex-invoice-supported-features.rdl: broad feature sample with header/footer, images, nested merge blocks, cell styling, INCLUDETEXT, and typography.
  • grouped-tablix-detail-row.rdl: TablixRowHierarchy detail-row detection.
  • text-decorations.rdl: bold, italic, underline, and strikeout.

Running Tests

dotnet test tx-rdl2tx.slnx

The integration test converts every fixture to:

  • .docx
  • .tx
  • .json

Generated files are written to:

TextControl.RdlImport.Tests/TestOutput

The tests also verify:

  • stream-to-stream conversion
  • byte-array conversion
  • generated DOCX package contents
  • native TX files can be loaded by ServerTextControl
  • expected merge blocks exist
  • header/footer fields are placed in the correct DOCX parts
  • supported formatting is serialized into the output

Conversion Report

Each conversion can produce a JSON report:

{
  "ReportName": "complex-invoice-supported-features",
  "QualityScore": 95,
  "TextboxCount": 28,
  "TablixCount": 2,
  "ImageCount": 1,
  "LineCount": 0,
  "Supported": [
    "Textboxes: 28",
    "Simple tablix regions: 2",
    "Embedded images: 1",
    "Subreport INCLUDETEXT fields: 1",
    "Page header content",
    "Page footer content"
  ],
  "Warnings": [
    "Subreports: 1 INCLUDETEXT field(s) generated. Parameter mappings are emitted as adjacent merge fields."
  ],
  "Unsupported": []
}

The score is a practical confidence indicator, not a proof of visual equivalence.

Notes On Merge Blocks

Repeated tablix rows are converted to TX Text Control SubTextParts. The subtextpart name is:

txmb_<DataSetName>

For example:

txmb_InvoiceItems

The converter now uses TablixRowHierarchy when available to choose the correct detail/group row. If no useful hierarchy is present, it falls back to the first row containing merge fields.

For nested merge blocks, the parent merge block is created first, then nested content is inserted so TX Text Control accepts both subtextparts.

Notes On Subreports

SSRS subreports normally reference separate reports. They are not embedded in the parent RDL. The converter maps them to INCLUDETEXT fields:

INCLUDETEXT "Report Documentation Variables"

Parameter mappings are emitted next to the include as regular text and merge fields, for example:

(ItemID: «ItemID»)

Resolving the include target to a converted .tx or .docx file is intentionally left to the consuming application or a later include-path strategy.

Known Limitations

The converter does not currently implement:

  • full SSRS expression evaluation
  • conditional visibility
  • conditional formatting beyond simple literal variable references
  • charts, maps, gauges, and report viewer specific items
  • full subreport expansion from referenced RDL files
  • drillthrough/hyperlink action conversion
  • exact SSRS rendering behavior

The design goal is a maintainable TX Text Control template, not pixel-perfect SSRS output.