Skip to content

Commit d2b0e98

Browse files
Merge pull request #2034 from Syncfusion-Content/hotfix/hotfix-v32.1.19
DOCINFRA-2341_merged_using_automation
2 parents ee0f651 + f56071b commit d2b0e98

2 files changed

Lines changed: 349 additions & 0 deletions

File tree

Document-Processing/Excel/Spreadsheet/Blazor/open-and-save.md

Lines changed: 310 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,316 @@ An Excel file encoded as a Base64 string can be loaded into the Spreadsheet comp
7272
{% endhighlight %}
7373
{% endtabs %}
7474

75+
### Open an Excel file from JSON data
76+
77+
The Blazor Spreadsheet component accepts data only as a byte array through the [DataSource](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Spreadsheet.SfSpreadsheet.html#Syncfusion_Blazor_Spreadsheet_SfSpreadsheet_DataSource) property. To load JSON data into the Spreadsheet, convert the JSON data into an Excel file format using [XlsIO](https://help.syncfusion.com/file-formats/xlsio/overview), then convert it to a byte array. This approach allows importing JSON data from a local file or a remote URL.
78+
79+
#### Load an Excel file from a local JSON file
80+
81+
JSON data can be loaded from a local JSON file, converted to Excel format using XlsIO, and displayed in the Spreadsheet component. This approach is useful when working with static JSON data files within the application. The implementation reads the JSON file, converts it to Excel format using XlsIO, and binds it to the Spreadsheet as a byte array.
82+
83+
{% tabs %}
84+
{% highlight razor tabtitle="Index.razor" %}
85+
86+
@using System.Text.Json
87+
@using Syncfusion.XlsIO
88+
@using Syncfusion.Blazor.Spreadsheet
89+
90+
<SfSpreadsheet DataSource="DataSourceBytes">
91+
<SpreadsheetRibbon></SpreadsheetRibbon>
92+
</SfSpreadsheet>
93+
94+
@code {
95+
96+
public byte[] DataSourceBytes { get; set; }
97+
98+
protected override void OnInitialized()
99+
{
100+
// Build the file path to the JSON data source
101+
// Note: Replace "wwwroot" and "sample.json" with the actual folder and file name where your JSON is stored.
102+
string jsonFilePath = Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "sample.json");
103+
104+
// Read the entire JSON file content as a string
105+
string jsonData = File.ReadAllText(jsonFilePath);
106+
107+
// Convert the JSON content to an Excel byte array for Spreadsheet binding
108+
DataSourceBytes = ConvertJsonToExcel(jsonData);
109+
}
110+
111+
// Converts a JSON string into an Excel workbook byte array using Syncfusion XlsIO
112+
private byte[] ConvertJsonToExcel(string jsonData)
113+
{
114+
// Parse the JSON string into a JsonDocument for processing
115+
using JsonDocument jsonDocument = JsonDocument.Parse(jsonData);
116+
JsonElement rootJsonElement = jsonDocument.RootElement;
117+
118+
// Normalize the JSON structure into a list of row dictionaries
119+
List<Dictionary<string, JsonElement>> dataRows = NormalizeJsonToRows(rootJsonElement);
120+
121+
// Extract all unique column headers (keys) from all rows
122+
List<string> columnHeaders = dataRows
123+
.SelectMany(row => row.Keys)
124+
.Distinct()
125+
.ToList();
126+
127+
// Initialize the Excel engine
128+
using ExcelEngine excelEngine = new ExcelEngine();
129+
IApplication excelApplication = excelEngine.Excel;
130+
131+
// Create a new workbook with one worksheet
132+
IWorkbook workbook = excelApplication.Workbooks.Create(1);
133+
IWorksheet worksheet = workbook.Worksheets[0];
134+
135+
// Write header row with column names
136+
int columnCount = columnHeaders.Count;
137+
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
138+
{
139+
IRange headerCell = worksheet.Range[1, columnIndex + 1];
140+
headerCell.Text = columnHeaders[columnIndex];
141+
headerCell.CellStyle.Font.Bold = true;
142+
}
143+
144+
// Write data rows starting from the second row
145+
int currentRowIndex = 2;
146+
foreach (var dataRow in dataRows)
147+
{
148+
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
149+
{
150+
string columnKey = columnHeaders[columnIndex];
151+
152+
// Write cell value if the key exists in the current row
153+
if (dataRow.TryGetValue(columnKey, out var cellValue))
154+
{
155+
worksheet.Range[currentRowIndex, columnIndex + 1].Value2 = cellValue;
156+
}
157+
}
158+
currentRowIndex++;
159+
}
160+
161+
// Save the workbook to a memory stream and return as byte array
162+
using MemoryStream memoryStream = new MemoryStream();
163+
workbook.SaveAs(memoryStream);
164+
return memoryStream.ToArray();
165+
}
166+
167+
// Normalizes various JSON structures (array, object, or single value) into a uniform list of row dictionaries
168+
private List<Dictionary<string, JsonElement>> NormalizeJsonToRows(JsonElement rootJsonElement)
169+
{
170+
// Case 1: JSON is an array - convert each element to a dictionary
171+
if (rootJsonElement.ValueKind == JsonValueKind.Array)
172+
{
173+
return rootJsonElement.EnumerateArray()
174+
.Select(JsonToDictionaryList)
175+
.ToList();
176+
}
177+
178+
// Case 2: JSON is an object
179+
if (rootJsonElement.ValueKind == JsonValueKind.Object)
180+
{
181+
// Check if the object contains array properties (wrapper pattern)
182+
foreach (var property in rootJsonElement.EnumerateObject())
183+
{
184+
if (property.Value.ValueKind == JsonValueKind.Array)
185+
{
186+
return property.Value.EnumerateArray()
187+
.Select(JsonToDictionaryList)
188+
.ToList();
189+
}
190+
}
191+
192+
// Single object record - wrap in a list
193+
return new List<Dictionary<string, JsonElement>>
194+
{
195+
JsonToDictionaryList(rootJsonElement)
196+
};
197+
}
198+
199+
// Case 3: Fallback for primitive values - wrap in a dictionary with "value" key
200+
return new List<Dictionary<string, JsonElement>>
201+
{
202+
new Dictionary<string, JsonElement> { ["value"] = rootJsonElement }
203+
};
204+
}
205+
206+
// Converts a JsonElement to a dictionary of property names and values
207+
private Dictionary<string, JsonElement> JsonToDictionaryList(JsonElement jsonElement)
208+
{
209+
// If not an object, wrap the value in a dictionary with "value" key
210+
if (jsonElement.ValueKind != JsonValueKind.Object)
211+
{
212+
return new Dictionary<string, JsonElement> { ["value"] = jsonElement };
213+
}
214+
215+
// Enumerate all properties and convert to dictionary
216+
return jsonElement.EnumerateObject()
217+
.ToDictionary(
218+
property => property.Name,
219+
property => property.Value,
220+
StringComparer.OrdinalIgnoreCase
221+
);
222+
}
223+
}
224+
225+
{% endhighlight %}
226+
{% endtabs %}
227+
228+
#### Load an Excel file from a remote JSON URL
229+
230+
Remote JSON data can be integrated into the Spreadsheet component by converting it into an Excel-compatible format. The process begins with asynchronous retrieval of JSON from the specified endpoint using HttpClient. The fetched data is then transformed into an Excel workbook through XlsIO, and the resulting byte array is passed to the Spreadsheet for rendering. This approach is particularly useful for integrating real-time data from REST APIs or other web services.
231+
232+
{% tabs %}
233+
{% highlight razor tabtitle="Index.razor" %}
234+
235+
@using System.Text.Json
236+
@using Syncfusion.XlsIO
237+
@using Syncfusion.Blazor.Spreadsheet
238+
@inject HttpClient HttpClient
239+
240+
@if (IsDataLoaded)
241+
{
242+
<SfSpreadsheet DataSource="DataSourceBytes">
243+
<SpreadsheetRibbon></SpreadsheetRibbon>
244+
</SfSpreadsheet>
245+
}
246+
@code {
247+
248+
public byte[] DataSourceBytes { get; set; }
249+
250+
// Flag to indicate whether the data has been loaded
251+
public bool IsDataLoaded { get; set; }
252+
253+
protected override async Task OnInitializedAsync()
254+
{
255+
// Define the remote JSON URL
256+
// Note: Replace with your actual JSON endpoint URL
257+
string jsonUrl = "https://jsonplaceholder.typicode.com/todos";
258+
259+
// Fetch JSON data from the remote URL
260+
string jsonData = await HttpClient.GetStringAsync(jsonUrl);
261+
262+
// Transform the JSON data to an Excel byte array for Spreadsheet binding
263+
DataSourceBytes = ConvertJsonToExcel(jsonData);
264+
265+
// Set flag to indicate data is loaded
266+
IsDataLoaded = true;
267+
}
268+
269+
// Transforms a JSON string into an Excel workbook byte array using Syncfusion XlsIO
270+
private byte[] ConvertJsonToExcel(string jsonData)
271+
{
272+
// Parse the JSON string into a JsonDocument for processing
273+
using JsonDocument jsonDocument = JsonDocument.Parse(jsonData);
274+
JsonElement rootJsonElement = jsonDocument.RootElement;
275+
276+
// Normalize the JSON structure into a list of row dictionaries
277+
List<Dictionary<string, JsonElement>> dataRows = NormalizeJsonToRows(rootJsonElement);
278+
279+
// Extract all unique column headers (keys) from all rows
280+
List<string> columnHeaders = dataRows
281+
.SelectMany(row => row.Keys)
282+
.Distinct()
283+
.ToList();
284+
285+
// Initialize the Excel engine
286+
using ExcelEngine excelEngine = new ExcelEngine();
287+
IApplication excelApplication = excelEngine.Excel;
288+
289+
// Create a new workbook with one worksheet
290+
IWorkbook workbook = excelApplication.Workbooks.Create(1);
291+
IWorksheet worksheet = workbook.Worksheets[0];
292+
293+
// Write header row with column names
294+
int columnCount = columnHeaders.Count;
295+
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
296+
{
297+
IRange headerCell = worksheet.Range[1, columnIndex + 1];
298+
headerCell.Text = columnHeaders[columnIndex];
299+
}
300+
301+
// Write data rows starting from the second row
302+
int currentRowIndex = 2;
303+
foreach (var dataRow in dataRows)
304+
{
305+
for (int columnIndex = 0; columnIndex < columnCount; columnIndex++)
306+
{
307+
string columnKey = columnHeaders[columnIndex];
308+
309+
// Write cell value if the key exists in the current row
310+
if (dataRow.TryGetValue(columnKey, out JsonElement cellValue))
311+
{
312+
worksheet.Range[currentRowIndex, columnIndex + 1].Value2 = cellValue;
313+
}
314+
}
315+
currentRowIndex++;
316+
}
317+
318+
// Save the workbook to a memory stream and return as byte array
319+
using MemoryStream memoryStream = new MemoryStream();
320+
workbook.SaveAs(memoryStream);
321+
return memoryStream.ToArray();
322+
}
323+
324+
// Normalizes various JSON structures (array, object, or single value) into a uniform list of row dictionaries
325+
private List<Dictionary<string, JsonElement>> NormalizeJsonToRows(JsonElement rootJsonElement)
326+
{
327+
// Case 1: JSON is an array - convert each element to a dictionary
328+
if (rootJsonElement.ValueKind == JsonValueKind.Array)
329+
{
330+
return rootJsonElement.EnumerateArray()
331+
.Select(JsonToDictionaryList)
332+
.ToList();
333+
}
334+
335+
// Case 2: JSON is an object
336+
if (rootJsonElement.ValueKind == JsonValueKind.Object)
337+
{
338+
// Check if the object contains array properties (wrapper pattern)
339+
foreach (var property in rootJsonElement.EnumerateObject())
340+
{
341+
if (property.Value.ValueKind == JsonValueKind.Array)
342+
{
343+
return property.Value.EnumerateArray()
344+
.Select(JsonToDictionaryList)
345+
.ToList();
346+
}
347+
}
348+
349+
// Single object record - wrap in a list
350+
return new List<Dictionary<string, JsonElement>>
351+
{
352+
JsonToDictionaryList(rootJsonElement)
353+
};
354+
}
355+
356+
// Case 3: Fallback for primitive values - wrap in a dictionary with "value" key
357+
return new List<Dictionary<string, JsonElement>>
358+
{
359+
new Dictionary<string, JsonElement> { ["value"] = rootJsonElement }
360+
};
361+
}
362+
363+
// Parses a JsonElement into a dictionary of property names and values
364+
private Dictionary<string, JsonElement> JsonToDictionaryList(JsonElement jsonElement)
365+
{
366+
// If not an object, wrap the value in a dictionary with "value" key
367+
if (jsonElement.ValueKind != JsonValueKind.Object)
368+
{
369+
return new Dictionary<string, JsonElement> { ["value"] = jsonElement };
370+
}
371+
372+
// Enumerate all properties and convert to dictionary
373+
return jsonElement.EnumerateObject()
374+
.ToDictionary(
375+
property => property.Name,
376+
property => property.Value,
377+
StringComparer.OrdinalIgnoreCase
378+
);
379+
}
380+
}
381+
382+
{% endhighlight %}
383+
{% endtabs %}
384+
75385
### Open an Excel file from Google Drive
76386
To load an Excel file from `Google Drive` in the Blazor Spreadsheet, follow the steps below.
77387

Document-Processing/PDF/Conversions/HTML-To-PDF/NET/troubleshooting.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1452,6 +1452,45 @@ After the service restarts, try the conversion or operation again to ensure the
14521452

14531453
</table>
14541454

1455+
## Ubuntu 24.04 dependency install fails: libasound2 migrated to libasound2t64; libgconf-2-4 removed
1456+
1457+
<table>
1458+
<th style="font-size:14px" width="100px">Exception</th>
1459+
<th style="font-size:14px">Installing dependencies on Ubuntu 24.04 fails when attempting to install libasound2 and libgconf-2-4, leading to build/launch errors
1460+
</th>
1461+
<tr>
1462+
<th style="font-size:14px" width="100px">Reason
1463+
</th>
1464+
<td>
1465+
<b>Time64 transition:</b> Ubuntu 24.04 adopted 64-bit timestamp support, renaming several libraries with the t64 suffix. libasound2 is now a virtual package provided by libasound2t64, so installing libasound2 directly fails.
1466+
1467+
<b>Deprecated removal:</b> libgconf-2-4 was deprecated and removed starting with Ubuntu 23.10 and is not available in 24.04 repositories.
1468+
</td>
1469+
</tr>
1470+
<tr>
1471+
<th style="font-size:14px" width="100px">Solution</th>
1472+
<td>
1473+
Update the dependency installation script to use t64 packages and omit libgconf-2-4. The following command installs the supported libraries on Ubuntu 24.04:
1474+
1475+
{% tabs %}
1476+
{% highlight C# %}
1477+
1478+
Run apt-get update && apt-get install -yq --no-install-recommends \
1479+
libasound2t64 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 \
1480+
libfontconfig1 libgcc-s1 libgdk-pixbuf2.0-0 libglib2.0-0t64 libgtk-3-0t64 \
1481+
libnspr4 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 \
1482+
libxcb1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 \
1483+
libxrender1 libxss1 libxtst6 libnss3 libgbm1
1484+
1485+
{% endhighlight %}
1486+
{% endtabs %}
1487+
1488+
After applying this change, all required dependencies are installed successfully.
1489+
</td>
1490+
</tr>
1491+
1492+
</table>
1493+
14551494
## Localized Content Not Reflected in PDF Output When Using Blink HTML-to-PDF Conversion Despite Browser Culture Change
14561495

14571496
<table>

0 commit comments

Comments
 (0)