Skip to content

Commit a113768

Browse files
authored
fix(excel-exporter): escape special chars in column headers (#12769)
* fix(excel-exporter): escape special chars in column headers * chore(*): minor fixes for sanitized value
1 parent ddff831 commit a113768

File tree

6 files changed

+51
-18
lines changed

6 files changed

+51
-18
lines changed

projects/igniteui-angular/src/lib/services/excel/excel-exporter-grid.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,21 @@ describe('Excel Exporter', () => {
747747
const grid = fix.componentInstance.grid;
748748
await exportAndVerify(grid, options, actualData.columnsAddedOnInit);
749749
});
750+
751+
it('Should escape special chars in headers', async () => {
752+
const fix = TestBed.createComponent(GridIDNameJobTitleHireDataPerformanceComponent);
753+
fix.detectChanges();
754+
await wait();
755+
756+
const grid = fix.componentInstance.grid;
757+
grid.columnList.get(1).header = '&';
758+
grid.columnList.get(2).header = '<>';
759+
grid.columnList.get(3).header = '"';
760+
grid.columnList.get(4).header = '\'';
761+
762+
763+
await exportAndVerify(grid, options, actualData.exportGridDataWithSpecialCharsInHeaders);
764+
});
750765
});
751766

752767
describe('', () => {

projects/igniteui-angular/src/lib/services/excel/excel-files.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -610,7 +610,7 @@ export class WorksheetFile implements IExcelFile {
610610
? startValue + owner.maxLevel + 2
611611
: this.rowIndex
612612

613-
const columnValue = dictionary.saveValue(currentCol.header, true);
613+
const columnValue = dictionary.saveValue(currentCol.header, true, false);
614614

615615
columnCoordinate = (currentCol.field === GRID_LEVEL_COL
616616
? ExcelStrings.getExcelColumn(worksheetData.columnCount + 1)

projects/igniteui-angular/src/lib/services/excel/test-data.service.spec.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1449,6 +1449,24 @@ export class FileContentData {
14491449
return this.createData();
14501450
}
14511451

1452+
public get exportGridDataWithSpecialCharsInHeaders() {
1453+
this._sharedStringsData =
1454+
`count="18" uniqueCount="15"><si><t>ID</t></si><si><t>&amp;</t></si><si><t>&lt;&gt;</t></si><si><t>&quot;</t></si><si><t>&apos;</t></si><si><t>Performance</t></si><si><t>Casey Houston</t></si><si><t>Vice President</t></si><si><t>2017-06-19T11:43:07.714Z</t></si><si><t>[object Object],[object Object],[object Object],[object Object]</t></si><si><t>Gilberto Todd</t></si><si><t>Director</t></si><si><t>2015-12-18T11:23:17.714Z</t></si><si><t>Tanya Bennett</t></si><si><t>2005-11-18T11:23:17.714Z</t></si>`;
1455+
1456+
this._tableData =
1457+
`ref="A1:F4" totalsRowShown="0">
1458+
<autoFilter ref="A1:F4"/><tableColumns count="6"><tableColumn id="1" name="ID"/><tableColumn id="2" name="&amp;"/><tableColumn id="3" name="&lt;&gt;"/><tableColumn id="4" name="&quot;"/><tableColumn id="5" name="&apos;"/><tableColumn id="6" name="Performance"/></tableColumns>`;
1459+
1460+
this._worksheetData =
1461+
`<dimension ref="A1:F4"/>
1462+
<sheetViews><sheetView tabSelected="1" workbookViewId="0"></sheetView></sheetViews>
1463+
<sheetFormatPr defaultRowHeight="15" x14ac:dyDescent="0.25"/>
1464+
<cols><col min="1" max="1" width="50" customWidth="1"/><col min="2" max="2" width="50" customWidth="1"/><col min="3" max="3" width="50" customWidth="1"/><col min="4" max="4" width="50" customWidth="1"/><col min="5" max="5" width="50" customWidth="1"/><col min="6" max="6" width="50" customWidth="1"/></cols>
1465+
<sheetData><row r="1"><c r="A1" t="s"><v>0</v></c><c r="B1" t="s"><v>1</v></c><c r="C1" t="s"><v>2</v></c><c r="D1" t="s"><v>3</v></c><c r="E1" t="s"><v>4</v></c><c r="F1" t="s"><v>5</v></c></row><row r="2"><c r="A2" s="1"><v>1</v></c><c r="B2" t="s"><v>6</v></c><c r="C2" t="s"><v>7</v></c><c r="D2" s="1"><v>4</v></c><c r="E2" t="s"><v>8</v></c><c r="F2" t="s"><v>9</v></c></row><row r="3"><c r="A3" s="1"><v>2</v></c><c r="B3" t="s"><v>10</v></c><c r="C3" t="s"><v>11</v></c><c r="D3" s="1"><v>6</v></c><c r="E3" t="s"><v>12</v></c><c r="F3" t="s"><v>9</v></c></row><row r="4"><c r="A4" s="1"><v>3</v></c><c r="B4" t="s"><v>13</v></c><c r="C4" t="s"><v>11</v></c><c r="D4" s="1"><v>8</v></c><c r="E4" t="s"><v>14</v></c><c r="F4" t="s"><v>9</v></c></row></sheetData>`;
1466+
1467+
return this.createData();
1468+
}
1469+
14521470
public get exportHierarchicalDataWithSkippedColumns() {
14531471
this._sharedStringsData =
14541472
`count="89" uniqueCount="47"><si><t>Artist</t></si><si><t>Grammy Nominations</t></si><si><t>Grammy Awards</t></si><si><t>Naomí Yepes</t></si><si><t>Launch Date</t></si><si><t>US Billboard 200</t></si><si><t>No.</t></si><si><t>Title</t></si><si><t>Genre</t></si><si><t>Wood Shavifdsafdsafsangs Forever</t></si><si><t>*fdasfsa</t></si><si><t>Wood Shavifdsafdsafsavngs Forever</t></si><si><t>*vxzvczx</t></si><si><t>Wfdsafsaings Forever</t></si><si><t>*fdsacewwwqwq</t></si><si><t>Wood Shavings Forever</t></si><si><t>*rewqrqcxz</t></si><si><t>Wood Shavings Forever - Remix</t></si><si><t>Punk</t></si><si><t>SANTORINI</t></si><si><t>Hip-Hop</t></si><si><t>HEARTBEAT</t></si><si><t>OVERSEAS</t></si><si><t>Zoom</t></si><si><t>Do You?</t></si><si><t>No Photos</t></si><si><t>Tour</t></si><si><t>Started on</t></si><si><t>Location</t></si><si><t>Headliner</t></si><si><t>Faithful Tour</t></si><si><t>Sep 12</t></si><si><t>Worldwide</t></si><si><t>NO</t></si><si><t>Country</t></si><si><t>Attendants</t></si><si><t>Belgium</t></si><si><t>USA</t></si><si><t>Babila Ebwélé</t></si><si><t>Show Out</t></si><si><t>Mood Swings</t></si><si><t>Scenario</t></si><si><t>Astroworld</t></si><si><t>Jul 21</t></si><si><t>Bulgaria</t></si><si><t>Romania</t></si><si><t>Chloe</t></si>`;

projects/igniteui-angular/src/lib/services/excel/worksheet-data-dictionary.ts

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@ export class WorksheetDataDictionary {
4141
return this._columnWidths;
4242
}
4343

44-
public saveValue(value: any, isHeader: boolean): number {
44+
public saveValue(value: any, isHeader: boolean, shouldSanitizeValue: boolean = true): number {
4545
let sanitizedValue = '';
4646
const isDate = value instanceof Date;
4747
const isSavedAsString = isHeader || (typeof value !== 'number' && value !== Number(value) && !Number.isFinite(value) && !isDate);
4848

4949
if (isSavedAsString) {
50-
sanitizedValue = this.sanitizeValue(value);
50+
sanitizedValue = shouldSanitizeValue ? ExportUtilities.sanitizeValue(value) : value;
5151

5252
if (this._dictionary[sanitizedValue] === undefined) {
5353
this._dictionary[sanitizedValue] = this._counter++;
@@ -65,7 +65,7 @@ export class WorksheetDataDictionary {
6565
}
6666

6767
public getValue(value: string): number {
68-
return this.getSanitizedValue(this.sanitizeValue(value));
68+
return this.getSanitizedValue(ExportUtilities.sanitizeValue(value));
6969
}
7070

7171
public getSanitizedValue(sanitizedValue: string): number {
@@ -101,19 +101,6 @@ export class WorksheetDataDictionary {
101101
return this._context;
102102
}
103103

104-
private sanitizeValue(value: any): string {
105-
if (ExportUtilities.hasValue(value) === false) {
106-
return '';
107-
} else {
108-
const stringValue = String(value);
109-
return stringValue.replace(/&/g, '&amp;')
110-
.replace(/</g, '&lt;')
111-
.replace(/>/g, '&gt;')
112-
.replace(/"/g, '&quot;')
113-
.replace(/'/g, '&apos;');
114-
}
115-
}
116-
117104
private dirtyKeyCollections(): void {
118105
this._keysAreValid = false;
119106
}

projects/igniteui-angular/src/lib/services/exporter-common/base-export-service.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1116,7 +1116,7 @@ export abstract class IgxBaseExporter {
11161116
1;
11171117

11181118
const columnInfo: IColumnInfo = {
1119-
header: columnHeader,
1119+
header: ExportUtilities.sanitizeValue(columnHeader),
11201120
dataType: column.dataType,
11211121
field: column.field,
11221122
skip: !exportColumn,

projects/igniteui-angular/src/lib/services/exporter-common/export-utilities.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,17 @@ export class ExportUtilities {
5858
public static isNullOrWhitespaces(value: string): boolean {
5959
return value === undefined || value === null || !value.trim();
6060
}
61+
62+
public static sanitizeValue(value: any): string {
63+
if (!this.hasValue(value)) {
64+
return '';
65+
} else {
66+
const stringValue = String(value);
67+
return stringValue.replace(/&/g, '&amp;')
68+
.replace(/</g, '&lt;')
69+
.replace(/>/g, '&gt;')
70+
.replace(/"/g, '&quot;')
71+
.replace(/'/g, '&apos;');
72+
}
73+
}
6174
}

0 commit comments

Comments
 (0)