JavaScript Csv file generator, part 3 of 3
This is part 3 of the JavaScript Csv file generator series. If you haven't read the first part, here it is: JavaScript Csv file generator, part 1 of 3
The Csv file generator is almost done. All we need to do is to enclose and escape certain special characters. Values containing the separator need to be enclosed in double quotes. Values containing double quotes need to be escaped and, just to be sure, enclosed in double quotes.
Two more requirements and two more unit tests coming up...
Requirements
- Values containing the current separator must be enclosed in double quotes.
- Values containing double quotes must be escaped (by doubling the double quote characters), and also enclosed in double quotes.
// Tests
engine.add("Csv.getFileContents should quote fields containing the separator",
function(testContext, the) {
// Arrange
var properties = ["name", "age"];
var csv = new Csv(properties);
csv.add({"name" : "Doe, John", "age" : "Unknown"});
csv.add({"name" : "Bunny", "age" : "2"});
// Act
var file = csv.getFileContents();
// Assert
the(file).shouldBeSameAs("\"Doe, John\",Unknown\r\nBunny,2");
});
engine.add("Csv.getFileContents should quote and escape fields containing double quotes",
function(testContext, the) {
// Arrange
var properties = ["model", "size"];
var csv = new Csv(properties);
csv.add({"model" : "Punysonic", "size" : "28\""});
csv.add({"model" : "Philip", "size" : "42\""});
// Act
var file = csv.getFileContents();
// Assert
the(file).shouldBeSameAs('Punysonic,"28"""\r\nPhilip,"42"""');
});
// Implementation
// Helper function to create one line of text
function createTextLine(values, separator) {
var result = [];
var doubleQuotes = new RegExp("\"", "g");
values.forEach(function(value) {
var text = value.toString();
if (text.indexOf(separator) == -1 && text.indexOf("\"") == -1) {
result.push(text);
} else {
result.push("\"" + text.replace(doubleQuotes, "\"\"") + "\"");
}
});
return result.join(separator);
}
// New getFileContents implementation
Csv.prototype.getFileContents = function(separator, includePropertyNames) {
separator = separator || ",";
var textLines = [];
if (includePropertyNames) {
textLines.push(createTextLine(this.propertyOrder, separator));
}
this.items.forEach((function(item) {
var values = [];
this.propertyOrder.forEach(function(propertyName) {
values.push(item[propertyName]);
});
textLines.push(createTextLine(values, separator));
}).bind(this));
return textLines.join("\r\n");
};
And it's done!
The latest version of the code is always available in the GitHub repository.
Articles in this series: