Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
b704c8e
Add option to exclude zero/missing rows in CSV export
likp Feb 20, 2026
57f137f
Set the correct zero and option type in the dataformatter
likp Feb 20, 2026
9e1ad39
Add test for CSV exclusion of missing values using TAB2936.px
likp Feb 20, 2026
57c4c99
Set ZeroOption based on ExcludeZerosAndMissingValues
likp Feb 20, 2026
c7e1c69
Some refactoring in the `HtmlSerializer`
likp Feb 20, 2026
011d4a0
Optimize HTML serialization by skipping empty rows
likp Feb 20, 2026
80d612a
Rename StubX to CalculateStubRepeat and make it static
likp Feb 20, 2026
df94346
Add option to exclude zero/missing rows in CSV export
likp Feb 20, 2026
1f1911e
Set the correct zero and option type in the dataformatter
likp Feb 20, 2026
8786433
Add test for CSV exclusion of missing values using TAB2936.px
likp Feb 20, 2026
47066ee
Set ZeroOption based on ExcludeZerosAndMissingValues
likp Feb 20, 2026
a6e91e2
Some refactoring in the `HtmlSerializer`
likp Feb 20, 2026
b06f770
Optimize HTML serialization by skipping empty rows
likp Feb 20, 2026
1f4c2a8
Rename StubX to CalculateStubRepeat and make it static
likp Feb 20, 2026
a05de3c
Merge branch 'feature/exclude-zeros' of https://github.com/PxTools/PC…
likp Apr 22, 2026
22290fb
Merge branch 'main' into feature/exclude-zeros
likp Apr 22, 2026
42f0f09
Add option to exclude zero/missing rows in XLSX export
likp Apr 22, 2026
9e34c7a
Merge branch 'feature/exclude-zeros' of https://github.com/PxTools/PC…
likp Apr 22, 2026
00349f9
Removed unused stuff
likp Apr 23, 2026
0561d9a
Removed unused local variable
likp Apr 23, 2026
b92fb78
Simplified recursive method
likp Apr 23, 2026
ead6bce
Refactored the code to make it less complex
likp Apr 23, 2026
a1fa58c
Remove unused return statement from CsvSerializer.cs
likp Apr 23, 2026
c1ae5b5
Refactor table writing methods to simplify signatures
likp Apr 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 42 additions & 20 deletions PCAxis.Serializers/CsvSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public enum LablePreference

public bool IncludeTitle { get; set; } = false;

public bool ExcludeZerosAndMissingValues { get; set; } = false;


private Delimiters _valueDelimiter = Delimiters.Comma;
public Delimiters ValueDelimiter
Expand Down Expand Up @@ -285,41 +287,59 @@ private StringCollection ConcatStubValues(int stubIndex)
/// <param name="wr">The stream to write to</param>
protected void WriteTable(StreamWriter wr)
{
StringCollection sc;

if (_model.Meta.Stub.Count > 0)
{
WriteTableWithSubVariables(wr);
}
else if (_model.Meta.Heading.Count > 0)
{
WriteTableWithnHeadingVariables(wr);
}
}

private void WriteTableWithnHeadingVariables(StreamWriter wr)
{
string value = "";
DataFormatter df = CreateDataFormater();

// If ExcludeZerosAndMissingValues is true, do not write the data if all values in the first row are zero or missing
if (ExcludeZerosAndMissingValues && df.IsZeroRow(0))
return;

if (_model.Meta.Stub.Count > 0)
for (int c = 0; c < _model.Data.MatrixColumnCount; c++)
{
sc = ConcatStubValues(0);
value = df.ReadElement(0, c);
wr.Write(this._delimiter);
wr.Write(value);
}

if (sc.Count != _model.Data.MatrixRowCount)
{
throw new PXSerializationException("Stub values do not match the data", "");
}
}

for (int i = 0; i < sc.Count; i++)
{
wr.Write(sc[i]);
for (int c = 0; c < _model.Data.MatrixColumnCount; c++)
{
value = df.ReadElement(i, c);
wr.Write(this._delimiter);
wr.Write(value);
}
wr.WriteLine();
}
private void WriteTableWithSubVariables(StreamWriter wr)
{
string value = "";
DataFormatter df = CreateDataFormater();
StringCollection sc = ConcatStubValues(0);
if (sc.Count != _model.Data.MatrixRowCount)
{
throw new PXSerializationException("Stub values do not match the data", "");
}
else if (_model.Meta.Heading.Count > 0)

for (int i = 0; i < sc.Count; i++)
{
// If ExcludeZerosAndMissingValues is true, skip rows with all zero or missing values
if (ExcludeZerosAndMissingValues && df.IsZeroRow(i))
continue;

wr.Write(sc[i]);
for (int c = 0; c < _model.Data.MatrixColumnCount; c++)
{
value = df.ReadElement(0, c);
value = df.ReadElement(i, c);
wr.Write(this._delimiter);
wr.Write(value);
}
wr.WriteLine();
}
}

Expand All @@ -329,6 +349,8 @@ private DataFormatter CreateDataFormater()
df.DecimalSeparator = ".";
df.ShowDataNotes = false;
df.ThousandSeparator = "";
if (ExcludeZerosAndMissingValues)
df.ZeroOption = ZeroOptionType.NoZeroNilAndSymbol;
return df;
}

Expand Down
109 changes: 87 additions & 22 deletions PCAxis.Serializers/HtmlSerializer.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;

using PCAxis.Paxiom;
Expand All @@ -17,7 +18,10 @@ public enum LablePreference

private int[] _subStubValues;
private DataFormatter _fmt;
private Dictionary<int, bool> _emptyRowCache;


public bool ExcludeZerosAndMissingValues { get; set; } = false;
public bool IncludeTitle { get; set; } = false;
public LablePreference ValueLablesDisplay { get; set; } = LablePreference.None;

Expand Down Expand Up @@ -67,6 +71,7 @@ public void Serialize(PXModel model, Stream stream)

private void DoSerialize(PXModel model, StreamWriter wr)
{
_emptyRowCache = new Dictionary<int, bool>();
wr.WriteLine(@"<table id=""" + model.Meta.Matrix + "_" + Guid.NewGuid().ToString() + @""" >"); //@""" aria-describedby="" "

// Only write title if it is set to be included
Expand All @@ -92,13 +97,24 @@ private void DoSerialize(PXModel model, StreamWriter wr)
wr.WriteLine("<tbody>");
int levels = stub.Count;
int row = 0;
_fmt = GetDataFormatter(model);
WriteTable(wr, model, levels, 0, ref row);

wr.WriteLine("</tbody>");
wr.WriteLine("</table>");
wr.Flush();
}

private DataFormatter GetDataFormatter(PXModel model)
{
var df = new DataFormatter(model);
if (ExcludeZerosAndMissingValues)
{
df.ZeroOption = ZeroOptionType.NoZeroNilAndSymbol;
}
return df;
}

private int CalculateSubValues(Variables vars, int level, ref int[] subValues)
{
if ((vars.Count == 0))
Expand Down Expand Up @@ -221,48 +237,97 @@ private void WriteDataLine(System.IO.StreamWriter wr, PCAxis.Paxiom.PXModel mode

}

private static int CalculateStubRepeat(PXModel model, int index)
{
var x = 1;

for (int i = index + 1; i < model.Meta.Stub.Count; i++)
{
x *= model.Meta.Stub[i].Values.Count;
}
return x;
}

private bool AreAllEmptyRows(int row, int count)
{
for (int i = 0; i < count; i++)
{
bool value;

if (!_emptyRowCache.TryGetValue(row + i, out value))
{
value = _fmt.IsZeroRow(row + i);
_emptyRowCache.Add(row + i, value);
}
if (!value)
{
return false;
}
}
return true;
}

private void WriteTable(System.IO.StreamWriter wr, Paxiom.PXModel model, int levels, int level, ref int row)
{
_fmt = new DataFormatter(model);
if (level > levels)
{
return;
}

int nextLevel = level + 1;

if ((level == levels))
// There is not variables in the stub, write the data line and return
if (model.Meta.Stub.Count == 0)
{
// Time to write the data to the file
wr.WriteLine("<tr>");
WriteEmptyHeadingForStub(wr, model);
WriteDataLine(wr, model, row);
// Close this row. The closing tag is not writen if level + 1 < levels, se
// the else clause below
wr.WriteLine("</tr>");
row = (row + 1);
row++;
return;
}
else

var values = model.Meta.Stub[level].Values;

int repeat = CalculateStubRepeat(model, level);
for (int i = 0; (i <= (values.Count - 1)); i++)
{
Paxiom.Values values = model.Meta.Stub[level].Values;
int nextLevel = (level + 1);
for (int i = 0; (i <= (values.Count - 1)); i++)
if (AreAllEmptyRows(row, repeat))
{
row += repeat;
continue;
}
// writes empty cells if this is not the last variable in the stub, and the next level is not empty
if (nextLevel < levels)
{
wr.WriteLine("<tr>");
wr.Write(@"<th scope=""row"">");

wr.Write(GetLabel(values[i]));
wr.WriteLine("</th>");
_fmt = new DataFormatter(model);


if (level + 1 < levels)
for (int y = 0; y <= model.Data.MatrixColumnCount - 1; y++)
{
for (int y = 0; y <= model.Data.MatrixColumnCount - 1; y++)
{
wr.WriteLine("<td></td>");
}
wr.WriteLine("</tr>");
wr.WriteLine("<td></td>");
}


wr.WriteLine("</tr>");
// write the next variable in the stub
WriteTable(wr, model, levels, nextLevel, ref row);
}
else // This is the last variable in the stub, write the data line and close the row
{

wr.WriteLine("<tr>");
wr.Write(@"<th scope=""row"">");
wr.Write(GetLabel(values[i]));
wr.WriteLine("</th>");
// Write the data to the file
WriteDataLine(wr, model, row);
// Close this row. The closing tag is not writen if level + 1 < levels, se
// the else clause below
wr.WriteLine("</tr>");
row++;
}
}

}
}
}
Expand Down
Loading
Loading