Click here to Skip to main content
15,887,304 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello all,

I am able to successfully generate and populate a rdlc report (invoice type document {DTE}) from a xml file by means of a dataset.

This rdlc has various sections, some require single fields, and some require matrices. So far, so good!

Here's a sample of such xml file:

<?xml version="1.0" encoding="ISO-8859-1"?>
<SetDTE>
<DTE version="1.0" >
<Documento ID="MiPE76266617-2495">
    <Encabezado>
    	...
    </Encabezado>
    <Detalle>
    	...
    </Detalle>
</DTE>
</SetDTE>

and this is how I assign/populate each DataSource:
RepVwer.LocalReport.DataSources.Clear();
RepVwer.LocalReport.DataSources.Add(new ReportDataSource("Documento", dsXML.Tables[0]));
RepVwer.LocalReport.DataSources.Add(new ReportDataSource("Emisor", dsXML.Tables[1]));
RepVwer.LocalReport.DataSources.Add(new ReportDataSource("Receptor", dsXML.Tables[2]));
RepVwer.LocalReport.DataSources.Add(new ReportDataSource("IdDoc", dsXML.Tables[3]));


The situation is that a these xml files can now have more that one document; i.e.
entire identical node structures (children), where each one represents a document {DTE}.

Example:

<?xml version="1.0" encoding="ISO-8859-1"?>
<SetDTE>
<DTE version="1.0" >
<Documento ID="MiPE76266617-720">
    <Encabezado>
    	...
    </Encabezado>
    <Detalle>
			...
    </Detalle>
    <Detalle>
			...
    </Detalle>
</DTE>
<DTE version="1.0" >
<Documento ID="MiPE76266617-2495">
    <Encabezado>
    	...
    </Encabezado>
    <Detalle>
    	...
    </Detalle>
</DTE>
</SetDTE>


How can I re-write the rdlc to accommodate such scenario? It should duplicate the entire structure (single fields and matrices) for each document.

I noticed that in this scenario, each table within the dataset has an ID field which help identify/link related records in between datatables.

What I have tried:

I have been looking around the web for insight, but have found nothing relevant so far (not really sure what to look for). 2018/01/09 :: So far, it seems nested matrices only work when all data is contained within the same data source; since I have several data sources, it might not be possible to achieve what I am after.

I tried to use the List control, but so far have been unable to figure out how to work the groups, inner matrices, etc.

Thank you all in advance for your input!.

2018/01/09 16:54 (UTC -04:00) :: After some more research, I came across how to merge data tables (first time). Such approach allowed me to successfully merge most datatable objects into a large on, which in turn, allowed me to set a standard grouped matrix to display each document's static fields.

However, I have not been able to integrate the datatables with detail data {n records for each document}. suggestions?
Posted
Updated 10-Jan-18 5:28am
v3

I have written an article in .Net/VB.Net that might be useful to read XML your data into a .Net model/convert the model and do what ever you want with the data model:

Reading and Writing XML in C#/VB.Net[^]

You would not find this article via search because its focussed on tree structured data but your question sounds like you are looking at something similar to tree structured data so this read might be useful - hope it helps, dirk
 
Share this answer
 
Comments
alexvw 9-Jan-18 14:45pm    
Hi Dirk,

I glanced the article, although it seems quite extensive in terms of reading/writing xml data, it does shed light on my issue about building a rdlc an populating it using nested matrices from several datasets.

Thanks as lot anyway; I appreciate your willingness to help.
Hello everyone,

I was able to come up with a working solution; however, if anybody has a better one, the rest of us will certainly appreciate to learn about it.

Case:
Populate a rdlc from a xml file which contains 1-n children objects, which have both static and dynamic data.

Structure Sample
<?xml version="1.0" encoding="ISO-8859-1"?>
<SetDTE>
<DTE version="1.0" > <!-- Children {1-n} (node of interest) -->
<Documento ID="MiPE76266617-720">
    <Encabezado> <!-- static data = single group -->
    	... 
    </Encabezado>
    <Detalle> <!-- dynamic data = 0-n groups -->
	... 
    </Detalle>
    <Detalle>
	...
    </Detalle>
</DTE>
<DTE version="1.0" >
<Documento ID="MiPE76266617-2495">
    <Encabezado> <!-- static data = single group -->
    	...
    </Encabezado>
    <Detalle> <!-- dynamic data = 0-n groups -->
    	...
    </Detalle>
</DTE>
</SetDTE>


At first I tried to populate it using a standard report with the many data tables generated by a dataset loaded from the source xml file:

C#
string xmlSource = System.IO.File.ReadAllText(DTEPath);

DataSet dsXML = new DTE(xmlSource);


Where DTE is a customized class inheriting from DataSet, which makes use of its ReadXml method to populate the object. I then extract the required tables from the source and add them to the base:

base.Tables.Add(dsXML.Tables["Documento"] == null ? new Documento() : dsXML.Tables["Documento"].Copy());


Where Documento is a customized class that inherits from datatable, which purpose is to provide a consistent structure shall the source not have the expected node. This approach is valid, but only for xml files with a single node "of interest".

When faced with xml files with multiple nodes "of interest", the standard report does not cut it. I tried to apply a List control or nested matrices, but not only they require a single datasource, but also, detail rows only allow static data.

The workaround I found was to:
a) Merge all static datatables into a single one by means of setting the respective primary keys (method I ignored and was able to implement thanks to this post).

b) Generate and apply sub-reports to handle the dynamic areas.

Procedure:
1) Generate a base report including a table(tablix), which must be configured to have as many group rows as needed. In this case a main group and a child group; I expanded the single row/column left in the tablix to cover the entire area of the report's body.

2) Added, to this single cell, all required textboxes, rectangles, lines, etc. to allocate the static data; i.e. the data that with unique values per group row. (The rectangles I added are the placeholders for the needed sub-reports)

3) Built the sub-reports (I needed two), and made sure to add the required input parameter, and filter to them. In this case, each sub-report has a data source, and the appropriate table to accommodate its values.

4) Added the sub-reports to the main one; each inside its designated rectangle.

5) The Code:

a) Hosting form (winform); must link the event handler required to process the sub-report(s):

private void FrmMain_Load(object sender, EventArgs e) 
        {
            .... //unrelated code
            RepVwer.LocalReport.SubreportProcessing += new SubreportProcessingEventHandler(SetSubDataSource);

        }

b) The main void: which gets the data, configures the ReportViewer control, and triggers the visualization of the report:

private void LoadXmlDTE(string DTEPath)
        {
            try
            {
                DataSet dsXML = new DTE(System.IO.File.ReadAllText(DTEPath));
                
                RepVwer.ProcessingMode = ProcessingMode.Local;
                RepVwer.LocalReport.ReportEmbeddedResource = "DTEViewer.rdlc.EncabezadoDTE.rdlc";
                RepVwer.LocalReport.DataSources.Clear();

                //Datos estáticos por documento
                DataTable auxData = GenerateStaticGlobalData(dsXML);
                RepVwer.LocalReport.DataSources.Add(new ReportDataSource("Global", auxData));
                
                //Datos dinámicos por documento {Sub-Reportes}
                _detalle = dsXML.Tables[6];
                _referencia = dsXML.Tables[7];
                
                this.RepVwer.RefreshReport();

                //... irrelevant code
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, "...", "...", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
        }

c) The GenerateStaticGlobalData method is the one in charged of merging all static datatables into a single one, which will be the report's core data source:
private DataTable GenerateStaticGlobalData(DataSet dsXML)
       {
           DataTable auxData = dsXML.Tables[0].Copy();

           auxData.PrimaryKey = new DataColumn[] { auxData.Columns["Documento_Id"] }; //Documento_Id {0}
           dsXML.Tables[1].PrimaryKey = new DataColumn[] { dsXML.Tables[1].Columns["Documento_Id"] };
           auxData.Merge(dsXML.Tables[1]);

           auxData.PrimaryKey = new DataColumn[] { auxData.Columns["Encabezado_Id"] }; //Encabezado_Id {4}
           for (int i = 2; i < 6; i++)
           {
               dsXML.Tables[i].PrimaryKey = new DataColumn[] { dsXML.Tables[i].Columns["Encabezado_Id"] };
               auxData.Merge(dsXML.Tables[i]);
           }

           return auxData; //output
       }

Note: I was able to use a for statement in the above code because my DTE class organized those datatables in such order.

d) Let's not forget the event handler to assign the data source(s) to the sub-report(s):
public void SetSubDataSource(object sender, SubreportProcessingEventArgs e)
       {
           e.DataSources.Add(new ReportDataSource("Detalle", _detalle));
           e.DataSources.Add(new ReportDataSource("Referencias", _referencia));
       }


That's it; I now have a report (with two integrated sub-reports), which can be presented on screen as expected by the client; i.e. a document per page, which they can either export or print as desired.

Hopefully, this can be useful for someone else.

Again, thank you all who took the time to read my question, and now my own answer.
 
Share this answer
 
v2

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900