Reputation: 5637
I need to convert a server response from an array to an array of JSON object format.
The rows of data coming fron the server needs to be converted in order for the Kendo UI grid widget to work properly.
I have converted the schema and column definitions into a Json format, but having some difficulty with the actual data rows.
Here's the RAW server response where
1) the "data" array contains the data schema
2) the "rows" array contains the actual values :
{"status":"SUCCESS", "messages":[],
"data":[{"attributes":[{"name":"BookingLocation","type":"string"},{"name":"SUM(CDSStress A:USD 10Y X -1.25)","type":"double"},{"name":"SUM(CDSStress A:USD 10Y X 1.25)","type":"double"},{"name":"SUM(CDSStress A:USD 8Y X 1.25)","type":"double"}],
"rows":[{"id":0,"values":["London",0,0,0]},{"id":1,"values":["Paris",0,0,0]},{"id":2,"values":["Dubai",1564.92711931719,-171.934775655824,-54539.9112355565]},{"id":3,"values":["New York",0,0,0]},{"id":4,"values":["Stockholm",0,0,0]},{"id":5,"values":["World",0,0,0]}]}]}
Essentially I need to pull the "attributes" array, and match them up with the "rows" array - and do this all dynamically for any server response.
Now pulling the schema information from the "attributes" array (within "data"), I can build the schema JSON object dynamically, then plug it into the Kendo grid - something like this :
var myModel = { // sample schema object; actually built dynamically in javascript
"id": "Id",
"fields": {
"BookingCountry": {
"type": "string"
},
"SUM(CDSStress A:USD 10Y X -1.25)": {
"type": "number"
},
"SUM(CDSStress A:USD 10Y X 1.25)": {
"type": "number"
},
"SUM(CDSStress A:USD 8Y X 1.25)": {
"type": "number"
}
}
}
var myColumns = $rootScope.reptWizard.colDefs; // build the columns def
var myData = $rootScope.reptWizard.aggrResults; // convert data rows to JSON object
var ds = {
schema: {
model: myModel
},
vm.mainHierGridOptions = {
dataSource: ds,
columns: myColumns
};
pageSize: 10,
data: myData
};
{
However, the 'myData' object needs to look like this :
[
{ "id": 0,
"BookingCountry": "London",
"SUM(CDSStress A:USD 10Y X -1.25)": 1564.92711,
"SUM(CDSStress A:USD 10Y X 1.25)": -171.9347756,
"SUM(CDSStress A:USD 8Y X 1.25)": -54539.911235
},
{ "id": 0,
"BookingCountry": "Dubai",
"SUM(CDSStress A:USD 10Y X -1.25)": 1564.92711,
"SUM(CDSStress A:USD 10Y X 1.25)": -171.9347756,
"SUM(CDSStress A:USD 8Y X 1.25)": -54539.911235
}
]
As you can see, I need to iterate the "values" array and create a nicely-formatted JSON object with the correct field:value - i.e. "BookingCountry": "London".
Here's a function I created to format the myCols var :
function buildDynamicColumnDefs(fieldAttribs) {
// creates an array of Json objects; to be used as input to the Grid's 'columns' property
var numAttribs = fieldAttribs.length;
var myType = '';
var myCols = [];
if (numAttribs > 0) {
_.each(fieldAttribs, function (field) {
myCols.push({field: field, title: field});
});
}
return myCols;
}
and another function to create the myModel var :
function buildDynamicDataSourceModel(fieldAttribs) {
// creates a valid Json object {name:value} to be used in Kendo Grid DataSource
var jsonExample = {
"BookingLocation": { "type": "string" },
"SUM(CDSStress A:USD 10Y X -1.25)": { "type": "number" },
"SUM(CDSStress A:USD 10Y X 1.25)": { "type": "number" },
"SUM(CDSStress A:USD 8Y X 1.25)": { "type": "number" }
};
var numAttribs = fieldAttribs.length;
var myType = '';
var myFields = {};
if (numAttribs > 0) {
_.each(fieldAttribs, function (field) {
myType = (field.type == "double" ? "number" : field.type); // 'number' is valid type for Kendo Grid schema
myFields[field.name] = { type: myType };
});
}
var myModel = {
id: "Id",
fields: myFields
/*fields: {
dimensions: { type: "string" },
values: { editable: false, type: "number" }
}*/
};
return myModel;
}
But now I need to create the buildJSONGridData(), and your help is greatly appreciated.
regards,
Bob
Upvotes: 0
Views: 1551
Reputation: 15175
Here is a function I used to help in exporting a Kendo UI Grid to pdf and Reporting services . This function takes the client blob values (title,columns,data) and build a collection ofg strongly types objects. You could probally do the same on the client side. Notice where the if(dataObject!=null)
is located that is where the data json objects are deserialzed. Hope it helps.
//------------------------------------------------------------------------------------------------------------------------------------
private CustomReportData CreateReportFromKendoData(string title, string columns, string data)
{
List<int> _ignoredColumns=new List<int>();
var columnObject = (columns == null) ? null : JsonConvert.DeserializeObject<dynamic>(columns);
var dataObject = (data == null) ? null : JsonConvert.DeserializeObject<dynamic>(data);
CustomReportData reportData = new CustomReportData();
reportData.ReportTitle = title;
if (columnObject != null)
for (int columnCount = 0; columnCount < columnObject.Count; columnCount++)
{
string fieldName = columnObject[columnCount].title == null ? columnObject[columnCount].field.ToString() : columnObject[columnCount].title.ToString();
if (ShouldDisplay(columnObject[columnCount].ToString()))
{
//IF WIDTH IS NULL THEN COLUMNS ARE EVNLY SPREAD THIS WILL BOMB
reportData.Columns.Add(new CustomReportColumn
{
FieldName = fieldName,
DataType = "",
Width = (columnObject[columnCount].width!=null)?this.GetFirstNumeric(columnObject[columnCount].width.ToString(), 250) :250
});
}
else
_ignoredColumns.Add(columnCount);
}
if (dataObject != null)
{
bool hasGrouping = dataObject[0].value != null;
for (int rowCount = 0; rowCount < dataObject.Count; rowCount++)
{
if (hasGrouping)
{
CustomReportGroup group = new CustomReportGroup();
group.GroupName = dataObject[rowCount].field.ToString();
group.GroupValue = ApplyFormat(dataObject[rowCount].value.ToString(),null);
this.RecursiveProcessGroups(group, dataObject[rowCount].items.ToString(), columnObject.ToString(),_ignoredColumns);
reportData.Groups.Add(group);
}
else
{
CustomReportDataRow row = new CustomReportDataRow();
for (int columnCount = 0; columnCount < columnObject.Count; columnCount++)
{
if (!_ignoredColumns.Contains(columnCount))
{
string format = (columnObject[columnCount].format == null ? "" : columnObject[columnCount].format.ToString());
string value = dataObject[rowCount][columnObject[columnCount].field.ToString()].ToString();
value = ApplyFormat(value, format);
row.Fields.Add(value);
}
}
reportData.DataRows.Add(row);
}
}
reportData.GroupDepth = this.GetGroupDepth(reportData.Groups);
}
return reportData;
}
Recursive function for group nesting
//------------------------------------------------------------------------------------------------------------------------------------
private void RecursiveProcessGroups(CustomReportGroup parentGroup, string items, string columns, List<int> ignoredColumns)
{
var groupItems = (items == null) ? null : JsonConvert.DeserializeObject<dynamic>(items);
var columnObject = (columns == null) ? null : JsonConvert.DeserializeObject<dynamic>(columns);
bool hasGrouping = groupItems[0]["value"] != null;
if (hasGrouping)
{
for (int rowCount = 0; rowCount < groupItems.Count; rowCount++)
{
CustomReportGroup group = new CustomReportGroup();
group.GroupName = groupItems[rowCount].field.ToString();
group.GroupValue = ApplyFormat(groupItems[rowCount].value.ToString(),null);
parentGroup.Groups.Add(group);
RecursiveProcessGroups(group, groupItems[rowCount].items.ToString(), columns.ToString(), ignoredColumns);
}
}
else
{
for (int groupItemCount = 0; groupItemCount < groupItems.Count; groupItemCount++)
{
CustomReportDataRow row = new CustomReportDataRow();
for (int columnCount = 0; columnCount < columnObject.Count; columnCount++)
if (!ignoredColumns.Contains(columnCount))
{
string value = groupItems[groupItemCount][columnObject[columnCount].field.ToString()].ToString();
string format = (columnObject[columnCount].format == null ? "" : columnObject[columnCount].format.ToString());
value = ApplyFormat(value, format);
row.Fields.Add(value);
}
parentGroup.DataRows.Add(row);
}
}
}
Domain Objects
public class CustomReportColumn
{
public string FieldName { get; set; }
public string DataType { get; set; }
public float Width { get; set; }
}
public class CustomReportColumns : List<CustomReportColumn> { }
public class CustomReportDataRow
{
public CustomReportDataRow()
{
Fields = new List<string>();
}
public List<string> Fields { get; set; }
}
public class CustomReportDataRows : List<CustomReportDataRow> { }
public class CustomReportGroup
{
public CustomReportGroup()
{
DataRows = new CustomReportDataRows();
Groups = new CustomReportGroups();
}
public string GroupName { get; set; }
public string GroupValue { get; set; }
public CustomReportGroups Groups { get; set; }
public CustomReportDataRows DataRows { get; set; }
}
public class CustomReportGroups : List<CustomReportGroup> { }
public class CustomReportData
{
public CustomReportData()
{
Groups = new CustomReportGroups();
Columns = new CustomReportColumns();
DataRows = new CustomReportDataRows();
}
public int GroupDepth { get; set; }
public CustomReportColumns Columns { get; set; }
public CustomReportGroups Groups { get; set; }
public CustomReportDataRows DataRows { get; set; }
public string ReportTitle { get; set; }
}
PDF Conversion
using iTextSharp.text; using iTextSharp.text.pdf; using Svg;
public class PDFServiceiTextSharp:IPDFService
{
private int _GroupDepth=0;
private int _ColumnCount = 0;
//-----------------------------------------------------------------------------------------------------------------------------------------
public byte[] RenderCustomReport(CustomReportData data)
{
try
{
using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("INMEMORYPDF.pdf", 1000000))
{
PDFPageMargins margins = new PDFPageMargins(10, 10, 10, 10);
_GroupDepth = data.GroupDepth;
_ColumnCount = data.Columns.Count;
float _pageWidth = this.GetPageWidth(data.Columns, margins);
var document=new Document((_pageWidth>540)?PageSize.A4.Rotate(): PageSize.A4, margins.Left,margins.Right, margins.Top, margins.Bottom);
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
PdfWriter.GetInstance(document, stream);
document.Open();
var pdfTable = new PdfPTable(_ColumnCount + _GroupDepth);
int[] columnWidths = new int[_ColumnCount + _GroupDepth];
for(int x=0;x<_GroupDepth;x++)
columnWidths[x]=3;
for(int y=0;y<data.Columns.Count;y++)
columnWidths[_GroupDepth + y] = Convert.ToInt32(data.Columns[y].Width);
pdfTable.SetWidths(columnWidths);
pdfTable.DefaultCell.Padding = 3;
pdfTable.DefaultCell.BorderWidth = 1;
pdfTable.DefaultCell.HorizontalAlignment = Element.ALIGN_TOP;
this.CreateHeaderColumns(pdfTable, data.Columns);
pdfTable.HeaderRows = 1;
pdfTable.DefaultCell.BorderWidth = 1;
if (data.Groups.Count > 0)
this.CreateGroupData(pdfTable, data.Groups, 0);
else
for (int x = 0; x < data.DataRows.Count; x++)
this.CreateDetailColumns(pdfTable, data.DataRows[x]);
document.Add(pdfTable);
document.Close();
}
byte[] content;
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
BinaryReader rdr = new BinaryReader(stream);
content = new byte[mmf.CreateViewStream().Length];
rdr.Read(content, 0, (int)mmf.CreateViewStream().Length);
}
return content;
}
}
catch
{
throw;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
public float GetPageWidth(CustomReportColumns columns, PDFPageMargins margins)
{
float width=0;
foreach (CustomReportColumn c in columns)
width += c.Width;
return width + margins.Left + margins.Right + (_GroupDepth * 3);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateHeaderColumns(PdfPTable table,CustomReportColumns columns)
{
Font headerFont = this.GetHeaderFont();
for(int gc=0;gc<_GroupDepth;gc++)
{
PdfPCell cell = new PdfPCell(new Phrase("", headerFont));
cell.BorderWidth=0;
table.AddCell(cell);
}
for (int x = 0; x < columns.Count; x++)
{
PdfPCell cell = new PdfPCell(new Phrase(columns[x].FieldName, headerFont));
cell.BorderColor = new BaseColor(100, 149, 237);
cell.HorizontalAlignment = Element.ALIGN_CENTER;
cell.BorderWidth=0.75f;
cell.Border = Rectangle.BOTTOM_BORDER | Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.LEFT_BORDER;
cell.PaddingBottom = 10;
cell.PaddingLeft = 3;
cell.PaddingRight = 3;
cell.PaddingTop = 10;
table.AddCell(cell);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateGroupData(PdfPTable table, CustomReportGroups parentgroups, int groupDepth)
{
if ((parentgroups == null)||(parentgroups.Count==0))
return;
groupDepth++;
foreach (CustomReportGroup group in parentgroups)
{
this.CreateGroupHeader(table, group, groupDepth);
for (int x = 0; x < group.DataRows.Count; x++)
this.CreateDetailColumns(table, group.DataRows[x]);
CreateGroupData(table, group.Groups, groupDepth);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateDetailColumns(PdfPTable table, CustomReportDataRow row)
{
Font detailFont = this.GetDetailFont();
for (int gc = 1; gc <= _GroupDepth; gc++)
{
BaseColor groupColor = this.GetGroupHeaderColor(_GroupDepth);
PdfPCell cell = new PdfPCell(new Phrase("", detailFont));
cell.BackgroundColor = groupColor;
cell.BorderColor = groupColor;
cell.BorderWidth = 0.75f;
table.AddCell(cell);
}
for (int x = 0; x < row.Fields.Count; x++)
{
PdfPCell cell = new PdfPCell(new Phrase(row.Fields[x], detailFont));
cell.BorderColor = new BaseColor(211, 211, 211);
cell.HorizontalAlignment = Element.ALIGN_CENTER;
cell.BorderWidth = 0.75f;
cell.Border = Rectangle.BOTTOM_BORDER | Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.LEFT_BORDER;
cell.PaddingBottom = 1;
cell.PaddingLeft = 3;
cell.PaddingRight = 3;
cell.PaddingTop = 1;
table.AddCell(cell);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateGroupHeader(PdfPTable table, CustomReportGroup group, int depth)
{
Font detailFont = this.GetDetailFont();
for (int gc = 1; gc <= _GroupDepth; gc++)
{
BaseColor depthColor = this.GetGroupHeaderColor(depth);
PdfPCell ecell = new PdfPCell(new Phrase("", detailFont));
ecell.BackgroundColor = depthColor;
ecell.BorderColor = depthColor;
ecell.BorderWidth = 0.75f;
table.AddCell(ecell);
}
BaseColor groupColor = this.GetGroupHeaderColor(depth);
PdfPCell cell = new PdfPCell(new Phrase( group.GroupValue, detailFont));
cell.Colspan = _ColumnCount + ((_GroupDepth - depth));
cell.BorderColor = groupColor;
cell.BackgroundColor = groupColor;
cell.HorizontalAlignment = Element.ALIGN_LEFT;
cell.BorderWidth = 0.75f;
cell.Border = Rectangle.BOTTOM_BORDER | Rectangle.TOP_BORDER | Rectangle.RIGHT_BORDER | Rectangle.LEFT_BORDER;
cell.PaddingBottom = 3;
cell.PaddingLeft = 3;
cell.PaddingRight = 3;
cell.PaddingTop = 3;
table.AddCell(cell);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private Font GetHeaderFont()
{
return FontFactory.GetFont("Arial", 10, Font.BOLD, BaseColor.BLACK);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private Font GetDetailFont()
{
return FontFactory.GetFont("Arial", 8, Font.NORMAL, BaseColor.BLACK);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private BaseColor GetGroupHeaderColor(int groupDepth)
{
switch (groupDepth)
{
case 1: return new BaseColor(211,211,211);
case 2: return new BaseColor(100, 149, 237);
case 3: return new BaseColor(255,165,0);
case 4: return new BaseColor(169,169,169);
case 5: return new BaseColor(211, 211, 211);
default: return new BaseColor(211, 211, 211);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
public void MergeFiles(System.Collections.Generic.List<string> sourceFiles, string destinationFile)
{
Document document=null;
if (System.IO.File.Exists(destinationFile))
System.IO.File.Delete(destinationFile);
try
{
PdfCopy writer = null;
int numberOfPages=0;
foreach(string sourceFile in sourceFiles)
{
PdfReader reader = new PdfReader(sourceFile);
reader.ConsolidateNamedDestinations();
numberOfPages = reader.NumberOfPages;
if(document==null)
{
document = new Document(reader.GetPageSizeWithRotation(1));
writer = new PdfCopy(document, new FileStream(destinationFile, FileMode.Create));
document.Open();
}
for (int x = 1;x <= numberOfPages;x++ )
{
if (writer != null)
{
PdfImportedPage page = writer.GetImportedPage(reader, x);
writer.AddPage(page);
}
}
PRAcroForm form = reader.AcroForm;
if (form != null && writer != null)
{
writer.CopyAcroForm(reader);
}
}
}
catch
{
throw;
}
finally
{
if (document != null && document.IsOpen())
document.Close();
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
public byte[] RenderReportFromSVG(string svgFileContents)
{
System.Drawing.Bitmap _bitmap=null;
byte[] byteArray = Encoding.ASCII.GetBytes(svgFileContents);
using (var stream = new MemoryStream(byteArray))
{
XmlDocument xdoc=new XmlDocument();
xdoc.LoadXml(svgFileContents);
var svgDocument = SvgDocument.Open(xdoc);
_bitmap = svgDocument.Draw();
}
using (MemoryMappedFile mmf = MemoryMappedFile.CreateNew("INMEMORYPDF.pdf", 1000000))
{
PDFPageMargins margins = new PDFPageMargins(10, 10, 10, 10);
float _pageWidth = margins.Left + margins.Right + _bitmap.Width;
var document = new Document((_pageWidth > 540) ? PageSize.A4.Rotate() : PageSize.A4, margins.Left, margins.Right, margins.Top, margins.Bottom);
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
PdfWriter.GetInstance(document, stream);
document.Open();
iTextSharp.text.Image pdfImage = iTextSharp.text.Image.GetInstance(_bitmap, System.Drawing.Imaging.ImageFormat.Bmp);
var pdfTable = new PdfPTable(1);
pdfTable.SetWidths(new int[]{_bitmap.Width});
pdfTable.DefaultCell.HorizontalAlignment = Element.ALIGN_TOP;
PdfPCell cell = new PdfPCell(pdfImage);
//cell.FixedHeight = fixedHeight;
cell.HorizontalAlignment = Element.ALIGN_CENTER;
cell.VerticalAlignment = Element.ALIGN_MIDDLE;
//img.ScaleAbsolute(200, fixedHeight);
pdfTable.AddCell(cell);
document.Add(pdfTable);
document.Close();
}
byte[] content;
using (MemoryMappedViewStream stream = mmf.CreateViewStream())
{
BinaryReader rdr = new BinaryReader(stream);
content = new byte[mmf.CreateViewStream().Length];
rdr.Read(content, 0, (int)mmf.CreateViewStream().Length);
}
return content;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
}
Finally the ExcelService to render grid to excel with column groupings
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
public class ExcelServiceNPOI:IExcelService
{
//-----------------------------------------------------------------------------------------------------------------------------------------
public byte[] RenderCustomReport(CustomReportData data)
{
try
{
if (data == null)
throw new ArgumentNullException("Report data cannot be null");
HSSFWorkbook workBook = new HSSFWorkbook();
ISheet sheet = workBook.CreateSheet(data.ReportTitle);
if (data.Groups.Count > 0)
{
int maxDepth = data.GroupDepth;// this.GroupDepth(data.Groups, 0);
this.CreateColumnHeader(sheet,maxDepth, data.Columns );
this.CreateGroupData(sheet, data.Groups, 0, maxDepth);
}
else
{
this.CreateColumnHeader(sheet, data.Columns);
this.CreateRowData(sheet, data.DataRows);
}
this.SetColumnWidth(sheet, data.Columns);
sheet.CreateFreezePane(0, 1);
MemoryStream ms = new MemoryStream();
workBook.Write(ms);
return ms.ToArray();
}
catch
{
throw;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateColumnHeader(ISheet sheet,CustomReportColumns columns)
{
this.CreateColumnHeader(sheet, 0, columns);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateColumnHeader(ISheet sheet, int columnOffset, CustomReportColumns columns )
{
if (columns == null || columns.Count == 0)
return;
IRow headerRow = sheet.CreateRow(0);
int colCount = columnOffset;
foreach (CustomReportColumn column in columns)
{
headerRow.CreateCell(colCount).SetCellValue(column.FieldName);
colCount++;
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateGroupData(ISheet sheet, CustomReportGroups parentgroups,int groupDepth, int maxDepth)
{
if (parentgroups == null)
return;
groupDepth++;
foreach (CustomReportGroup group in parentgroups)
{
CustomReportDataRow groupHeader = new CustomReportDataRow();
groupHeader.Fields.Add(group.GroupValue);
this.CreateRowData(sheet,groupDepth-1, groupHeader);
int groupBeginRowNum = sheet.LastRowNum+1;
this.CreateRowData(sheet,maxDepth, group.DataRows);
CreateGroupData(sheet,group.Groups, groupDepth, maxDepth);
sheet.GroupRow(groupBeginRowNum, sheet.LastRowNum);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateRowData(ISheet sheet, int startColumnIndex, CustomReportDataRow row)
{
int colNum = startColumnIndex;
IRow newRow = sheet.CreateRow(sheet.LastRowNum + 1);
foreach (string field in row.Fields)
newRow.CreateCell(colNum++).SetCellValue(field);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateRowData(ISheet sheet, CustomReportDataRows rows)
{
CreateRowData(sheet, 0, rows);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void CreateRowData(ISheet sheet, int startColumnIndex, CustomReportDataRows rows)
{
foreach (CustomReportDataRow row in rows)
{
int colNum = startColumnIndex;
IRow newRow = sheet.CreateRow(sheet.LastRowNum + 1);
foreach (string field in row.Fields)
newRow.CreateCell(colNum++).SetCellValue(field);
}
}
//-----------------------------------------------------------------------------------------------------------------------------------------
private void SetColumnWidth(ISheet sheet, CustomReportColumns columns)
{
if (columns == null || columns.Count == 0)
return;
for (int x = 0; x < columns.Count;x++ )
sheet.AutoSizeColumn(x);
}
//-----------------------------------------------------------------------------------------------------------------------------------------
}
Feel free to use it. It works with the latest version of Kendo. I have also added a function RenderReportFromSVG()
It will print a Kendo Chart to pdf using chart.svgContents
Upvotes: 1