我有以下情况:
我在公司内部服务器上设置了一系列 Cron 作业来运行旨在检查数据完整性的各种 PHP 脚本。每个 PHP 脚本都会查询公司数据库,将返回的查询数据格式化为包含一个或多个<tables>
. 根据我的经验,大多数 PHP 脚本生成的 HTML 文件只有几个表格,但是有一些 PHP 脚本可以创建大约 30 个表格的 HTML 文件。之所以选择 HTML 文件作为这些扫描的分发格式,是因为 HTML 可以轻松地在浏览器窗口中一次查看多个表。
我想为客户端添加将 HTML 文件中的表格下载为 CSV 文件的功能。我预计客户在怀疑基于表数据的数据完整性问题时会使用此功能。对于他们来说,能够获取有问题的表格,将数据导出到 CSV 文件,然后进一步研究,这将是理想的选择。
因为是否需要将数据导出为 CSV 格式由客户自行决定,无法预测哪些表将受到审查,并且间歇性使用我不想为每个表创建 CSV 文件。
通常创建 CSV 文件不会太难,使用 JavaScript/jQuery 执行 DOM 遍历并利用服务器调用或 flash 库将 CSV 文件数据生成字符串以方便下载过程;但我有一个限制条件:HTML 文件必须是“可移植的”。
我希望客户能够获取他们的 HTML 文件并对公司内部网之外的数据进行预分析。此外,这些 HTML 文件很可能会被归档,因此出于上述两个原因,将导出功能“自包含”在 HTML 文件中是一个非常理想的功能。
从 HTML 文件生成 CSV 文件的“可移植”约束意味着:
我无法拨打服务器电话。这意味着所有文件生成都必须在客户端完成。
我希望附加到电子邮件的单个 HTML 文件包含生成 CSV 文件的所有资源。这意味着我不能使用 jQuery 或 flash 库来生成文件。
我知道,出于明显的安全原因,任何浏览器都不支持使用 JavaScript 将文件写入磁盘。我不想在用户不知情的情况下创建文件;我想在内存中使用 JavaScript 生成文件,然后提示用户从内存中“下载”文件。
我已经研究过将 CSV 文件生成为 URI,但是根据我的研究和测试,这种方法存在一些问题:
IE 不支持文件的 URI(请参阅此处)
FireFox 中的 URI 使用随机文件名和 .part 文件保存文件
尽管让我很痛苦,但我可以接受 IE<=v9 不会为文件创建 URI 的事实。我想创建一个半跨浏览器解决方案,其中 Chrome、Firefox 和 Safari 在 JavaScript DOM 遍历编译数据后创建一个 URI 来下载 CSV 文件。
我的示例表:
<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's 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>
我的示例 JavaScript:
<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>
我正在寻找可以将上述示例表下载为 CSV 文件的示例解决方案:
- 使用 URI
- 使用 a
<button>
或 a<a>
- 代码按照现代版本的 FireFox、Safari 和 Chrome 中的描述工作
- 与(1.或2.):
- 提示用户保存文件
- 用户不需要“右键单击另存为”
- 自动将文件保存到默认浏览器保存目录
- 默认文件名是带有 .csv 文件扩展名的表的名称
我添加了一个<script>
带有 DOM 遍历功能的标签doSomething()
。我需要的真正帮助是将 URI 格式化为函数中我想要的内容doSomething()
。方法#2(见我的代码)似乎最有希望。
我愿意接受我想要的功能是不可能实现仅使用 HTML 和 JavaScript 如果声明提供证明; 例如浏览器文档、DOM 标准、JavaScript/ECMAscript 文档或证明不可能的逻辑反例。
话虽如此,我认为解决方案可能来自具有更深背景/更多 URI 经验的人,即使解决方案有点 hack。