Skip to content

Commit

Permalink
fix(excel-exporter): escape special chars in column headers (#12784)
Browse files Browse the repository at this point in the history
Co-authored-by: Maria Tsvyatkova <mtsvyatkova@infragistics.com>
  • Loading branch information
onlyexeption and mtsvyatkova committed Mar 17, 2023
1 parent a47c2e6 commit 9bb851c
Show file tree
Hide file tree
Showing 6 changed files with 51 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,21 @@ describe('Excel Exporter', () => {
const grid = fix.componentInstance.grid;
await exportAndVerify(grid, options, actualData.columnsAddedOnInit);
});

it('Should escape special chars in headers', async () => {
const fix = TestBed.createComponent(GridIDNameJobTitleHireDataPerformanceComponent);
fix.detectChanges();
await wait();

const grid = fix.componentInstance.grid;
grid.columnList.get(1).header = '&';
grid.columnList.get(2).header = '<>';
grid.columnList.get(3).header = '"';
grid.columnList.get(4).header = '\'';


await exportAndVerify(grid, options, actualData.exportGridDataWithSpecialCharsInHeaders);
});
});

describe('', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ export class WorksheetFile implements IExcelFile {
? startValue + owner.maxLevel + 2
: this.rowIndex

const columnValue = dictionary.saveValue(currentCol.header, true);
const columnValue = dictionary.saveValue(currentCol.header, true, false);

columnCoordinate = (currentCol.field === GRID_LEVEL_COL
? ExcelStrings.getExcelColumn(worksheetData.columnCount + 1)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1449,6 +1449,24 @@ export class FileContentData {
return this.createData();
}

public get exportGridDataWithSpecialCharsInHeaders() {
this._sharedStringsData =
`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>`;

this._tableData =
`ref="A1:F4" totalsRowShown="0">
<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>`;

this._worksheetData =
`<dimension ref="A1:F4"/>
<sheetViews><sheetView tabSelected="1" workbookViewId="0"></sheetView></sheetViews>
<sheetFormatPr defaultRowHeight="15" x14ac:dyDescent="0.25"/>
<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>
<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>`;

return this.createData();
}

public get exportHierarchicalDataWithSkippedColumns() {
this._sharedStringsData =
`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>`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ export class WorksheetDataDictionary {
return this._columnWidths;
}

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

if (isSavedAsString) {
sanitizedValue = this.sanitizeValue(value);
sanitizedValue = shouldSanitizeValue ? ExportUtilities.sanitizeValue(value) : value;

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

public getValue(value: string): number {
return this.getSanitizedValue(this.sanitizeValue(value));
return this.getSanitizedValue(ExportUtilities.sanitizeValue(value));
}

public getSanitizedValue(sanitizedValue: string): number {
Expand Down Expand Up @@ -101,19 +101,6 @@ export class WorksheetDataDictionary {
return this._context;
}

private sanitizeValue(value: any): string {
if (ExportUtilities.hasValue(value) === false) {
return '';
} else {
const stringValue = String(value);
return stringValue.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
}

private dirtyKeyCollections(): void {
this._keysAreValid = false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1116,7 +1116,7 @@ export abstract class IgxBaseExporter {
1;

const columnInfo: IColumnInfo = {
header: columnHeader,
header: ExportUtilities.sanitizeValue(columnHeader),
dataType: column.dataType,
field: column.field,
skip: !exportColumn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,17 @@ export class ExportUtilities {
public static isNullOrWhitespaces(value: string): boolean {
return value === undefined || value === null || !value.trim();
}

public static sanitizeValue(value: any): string {
if (!this.hasValue(value)) {
return '';
} else {
const stringValue = String(value);
return stringValue.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
}
}
}

0 comments on commit 9bb851c

Please sign in to comment.