HTML client portable file creation - no external resources or server calls

I have the following situation:

I created a series of Cron jobs on the company's internal server to run various PHP scripts designed to verify data integrity. Each PHP script queries the company database, formats the returned request data in an HTML file containing one or more <tables> , and then sends the HTML file to several client emails as an attachment. In my experience, most PHP scripts generate HTML files with only a few tables, however there are several PHP scripts to create HTML files with about 30 tables. HTML files were chosen as the distribution format for these scans, since HTML makes it easy to view many tables at once in a browser window.

I would like to add functionality for clients to load a table in an HTML file as a CSV file. I expect clients to use this feature when they suspect a data integrity problem based on table data. It would be ideal if they could take the table in question, export the data to a CSV file, and then examine it further.

Since the need to export the data in CSV format at the discretion of the client is unpredictable as to which table will be controlled and periodically used, I do not want to create CSV files for each table.

Normally, creating a CSV file would not be too complicated using JavaScript / jQuery to pre-process DOM traversal and generate CSV file data into a string using a server call or flash library to facilitate the loading process; but I have one limitation: the HTML file must be "portable".

I would like clients to be able to accept their HTML file and analyze data preforms outside the company intranet. It is also likely that these HTML files will be archived, so using the export functions "on their own" in HTML files is a highly desirable feature for the two previous reasons.

A “portable” restriction on generating a CSV file from an HTML file means:

  • I can not call the server. This means that ALL file generation must be done on the client side.

  • I want a single HTML file attached to an email to contain all the resources for creating a CSV file. This means that I cannot use jQuery or flash libraries to create a file.

For obvious security reasons, I understand that writing files to disk using JavaScript is not supported by any browser. I do not want to create a file without user knowledge; I would like to generate a file using JavaScript in memory, and then ask the user to “load” the file from memory.

I learned how to create a CSV file as a URI, however, according to my research and testing, this approach has several problems:

  • File URIs are not supported by IE ( see here )

  • Firefox URI saves a file with a random file name and as a .part file

As far as this helps me, I can agree that IE <= v9 will not create URIs for files. I would like to create a semi-cross-browser solution in which Chrome, Firefox and Safari create a URI to load a CSV file after the DOM code bypass compiles the data.

My example table:

 <table> <thead class="resulttitle"> <tr> <th style="text-align:center;" colspan="3"> NameOfTheTable</th> </tr> </thead> <tbody> <tr class="resultheader"> <td>VEN_PK</td> <td>VEN_CompanyName</td> <td>VEN_Order</td> </tr> <tr> <td class='resultfield'>1</td> <td class='resultfield'>Brander Ranch</td> <td class='resultfield'>Beef</td> </tr> <tr> <td class='resultfield'>2</td> <td class='resultfield'>Super Tree Produce</td> <td class='resultfield'>Apples</td> </tr> <tr> <td class='resultfield'>3</td> <td class='resultfield'>John Distilery</td> <td class='resultfield'>Beer</td> </tr> </tbody> <tfoot> <tr> <td colspan="3" style="text-align:right;"> <button onclick="doSomething(this);">Export to CSV File</button></td> </tr> </tfoot> </table> 

My JavaScript example:

 <script type="text/javascript"> function doSomething(inButton) { /* locate elements */ var table = inButton.parentNode.parentNode.parentNode.parentNode; var name = table.rows[0].cells[0].textContent; var tbody = table.tBodies[0]; /* create CSV String through DOM traversal */ var rows = tbody.rows; var csvStr = ""; for (var i=0; i < rows.length; i++) { for (var j=0; j < rows[i].cells.length; j++) { csvStr += rows[i].cells[j].textContent +","; } csvStr += "\n"; } /* temporary proof DOM traversal was successful */ alert("Table Name:\t" + name + "\nCSV String:\n" + csvStr); /* Create URI Here! * (code I am missing) */ /* Approach #1 : Auto-Download From Browser * Attempts to redirect the browser to the URI * and have the browser download the data as a file * * Approach does downloads CSV data but: * In FireFox downloads as randomCharacers.part instead of name.csv * In Chrome downloads without prompting the user and without correct file name * In Safari opens the files in browser (textfile) */ /* Approach #1 Code: var hrefData = "data:text/csv;charset=US-ASCII," + encodeURIComponent(csvStr); document.location.href = hrefData; */ /* Approach #2 : Right-Click Save As Link... * Attempts to remove "Download Button" * and replace the it with an anchor tag <a> * that the user can use to download the data * * Approach sort of works better: * When clicking on the link: * In FireFox downloads as randomCharacers.part instead of name.csv * In Chrome downloads without prompting the user (uses correct name) * In Safari opens the files in browser (textfile) * * When right-click "Save As" on the link: * In FireFox prompts the user with filename: randomCharacers.part * In Chrome prompts the user with filename: "download" * In Safari prompts the user with filename: "Unknown" */ /* Approach #2 Code: var hrefData = "data:text/csv;charset=US-ASCII," + encodeURIComponent(csvStr); var fileLink = document.createElement("a"); fileLink.href = hrefData; fileLink.type = "text/csv"; fileLink.innerHTML = "CSV Download Link"; fileLink.setAttribute("download",name+".csv"); // for Chrome parentTD = inButton.parentNode; parentTD.appendChild(fileLink); parentTD.removeChild(inButton); */ } </script> 

I am looking for an example solution in which the above example table can be downloaded as a CSV file:

  • using URI
  • using <button> or <a>
  • works as described in modern versions of FireFox, Safari and Chrome
  • AND (1. OR 2.):
      • the user is prompted to save the file
      • user doesn’t need “Right Click Save As”
      • automatically saves the file to the default browser save folder.
      • The default file name is the name of the table with the extension .csv.

I added a <script> with a DOM traversal function doSomething() . The real help I need is formatting the URI for what I want in the doSomething() function. Approach No. 2 (see. My code) seems to be the most promising.

I agree that my desired functionality cannot be achieved using only HTML and JavaScript, if the statement is presented by evidence; such as browser documentation, DOM standards, JavaScript / ECMAscript documentation, or an example of a logical display demonstrating impossibility.

As I said, I think that a solution is possible with someone with deeper experience / more experience working with URIs, even if the solution is a bit hacked.

+4
source share
3 answers

As long as you don't mind just supporting IE10 +, when it comes to IE, use FileSaver.js . You can create a CSV and add it to Blob, then saveAs() blob. You can save the file name of the saved file in browsers that support <a download> , such as Chrome.

+3
source

You indicate in the comments that “you don’t need to create separate HTML and CSV files,” but in this case your fundamental need is to provide data in two formats - getting two copies of the data is not an unreasonable restriction, I repeat, what you ask for not doable.

The closest solution I can imagine is to pack the CSV data into an HTML file (via display: none div or similar) and dynamically load it into HTML tables using JavaScript in download mode. This will be slow if you have large records, but it would just add a button to display and select CSV text to copy-paste. Tasteless? Yeah sorry. There is a reason HTML is not an exchange format.

In this case, you can pack your tabular data into a PDF file and include the CSV inside it as attachments.

+1
source

I want a single HTML file attached to an email to contain all the resources for creating a CSV file. This means that I cannot use jQuery

This is a false statement. If you want to use the jQuery function in a single HTML file without calling the server, just copy / paste the jQuery mini-library into the HTML itself. This will make each HTML 32K file larger, which isn’t a big deal if you don’t send hundreds of emails at a time.

So, if you are familiar with jQuery and it’s convenient for you to use it to refactor data on a page, feel free to use it. I would suggest that your automatically generated HTML have data in a javascript array, and when the page loads, it creates the table (s). Then, if the user clicks the CSV parameter, they can clear and reorganize it.

 var data = { title: 'NameOfTable', headers: ['VEN_PK', 'VEN_CompanyName', 'VEN_Order'], data: [ ['1', 'Brander Ranch' 'Beef'], ['2', 'Super Tree Produce' 'Apples'], ['3', 'John\ Distilery' 'Beer'] ] } $(document).ready(function() { var html = '<table>'; html += '<thead>'; html += '<tr><th style="text-align:center;" colspan="' + data.headers.length +'">' + data.title + '</th></tr>'; html += '</thead><tbody>'; html += '<tr class="resultheader">'; for (i in data.headers) { html += '<td>'+data.headers[i]+'</td>'; } html += '</tr>'; for (i in data.data) { var row = data.data[i]; html += '<tr>'; for (j in row) { html += '<td class="resultfield">'+row[j]+'</td>'; } html += '</tr>'; } html += '</table>'; $('#container').html(html); }); function showCSV() { var csv = ''; for (i in data.headers) { csv += data.headers[i] + ','; } csv += "\n"; for (i in data.data) { var row = data.data[i]; for (j in row) { csv += row[j] + ','; } csv += "\n"; } $('#container').html(csv); } 
-1
source

All Articles