javascript - 无法使用 Blob 对象在客户端打开 `docx` 文件 - vanilla JavaScript

标签 javascript xml file blob docx

这是客户端的代码,它是一个最小的、完整的和可验证的代码段,允许其他开发人员自己测试。

// requires: a string that contains html tags
// returns: a word document that can be downloaded with extension .doc or docx
// @ param cvAsHTML is a string that contains html tags

const preHtml = "<html xmlns:v='urn:schemas-microsoft-com:vml' xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/html4/loose.dtd\'><head><meta charset='utf-8'></head><body>";
const postHtml = "</body></html>";
const html = preHtml + cvAsHTML + postHtml;

let filename = "filename";
const blob = new Blob(["\ufeff", html], { type: "application/msword"});

上面的代码片段就像一个魅力。请注意,XML 模式是多余的,实际上是不必要的。 doc 文件可以在没有它们的情况下工作,但必须存在 head 和 body 标签。

对于 docx文件 我无法下载该文件。该文件似乎已损坏,经过几次试验,我真的不知道该怎么办。这是 docx 文件的代码:
const preHtml = "<?xml version='1.0' encoding='UTF-8?><html xmlns:v='urn:schemas-microsoft-com:vml' xmlns:o='urn:schemas-microsoft-com:office:office' xmlns:w='urn:schemas-microsoft-com:office:word' xmlns='http://www.w3.org/TR/html4/loose.dtd\'><head><meta charset='utf-8'></head><body>";
const postHtml = "</body></html>";
const html = preHtml + cvAsHTML + postHtml;

let filename = "filename.docx";
const blob = new Blob(["\ufeff", html], { type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document.main"});

注:我已更改 Blob 对象内的 MIME 类型并尝试了不同的其他选项,例如 application/zip , application/octet-stream等无济于事。我还更改了 prehtml变量包括:
<?xml version='1.0' encoding='UTF-8?>

鉴于我了解 docx 文件本质上是包含 xml 段的压缩文件...

非常感谢您提供的任何帮助。

编辑:2019 年 12 月 16 日

这是我在@dw_建议的实现后截取的截图:

使用 JSZip 的实现不能按预期工作,因为:
  • 浏览器本身不允许用户在 microsoft word 中打开文件,就像使用 doc 一样。文件;
  • 用户必须先保存文件,但即使那样,文件也不会打开,因为它已损坏。

  • enter image description here

    最佳答案

    .docx是压缩文件的集合,使用 simplified, minimal DOCX document as a guideline , 我创建了一个 ".zip"包含主要 word/document.xml 的文件文件和 3 个额外的必需文件。
    更多信息 .docx文件可以在这里找到:An Informal Introduction to DOCX

    // Other needed files
    const REQUIRED_FILES = {
      content_types_xml: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Types xmlns="http://schemas.openxmlformats.org/package/2006/content-types">
    <Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml"/>
    <Default Extension="xml" ContentType="application/xml"/>
    <Override PartName="/word/document.xml"
              ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml"/>
    </Types>`,
      rels: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
    <Relationship Id="rId1" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
                  Target="word/document.xml"/>
    </Relationships>`,
      document_xml_rels: `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Relationships xmlns="http://schemas.openxmlformats.org/package/2006/relationships">
    
    </Relationships>`
    };
    /// --
    const preHtml = `<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <w:document xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas"
                xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                xmlns:o="urn:schemas-microsoft-com:office:office"
                xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
                xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml"
                xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing"
                xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
                xmlns:w10="urn:schemas-microsoft-com:office:word"
                xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
                xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml"
                xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup"
                xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk"
                xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml"
                xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 wp14">
        <w:body><w:p w:rsidR="005F670F" w:rsidRDefault="005F79F5">`;
    const postHtml = `<w:bookmarkStart w:id="0" w:name="_GoBack"/>
                <w:bookmarkEnd w:id="0"/>
            </w:p>
            <w:sectPr w:rsidR="005F670F">
                <w:pgSz w:w="12240" w:h="15840"/>
                <w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" w:footer="720"
                         w:gutter="0"/>
                <w:cols w:space="720"/>
                <w:docGrid w:linePitch="360"/>
            </w:sectPr>
        </w:body>
    </w:document>`;
    const cvAsHTML = `<w:r><w:t>Sample content inside .docx</w:t></w:r>`;
    const html = preHtml + cvAsHTML + postHtml;
    
    function generateDocx(fname) {
      let zip = new JSZip();
      // prerequisites: 
        zip.file("_rels/.rels", REQUIRED_FILES.rels);
        zip.file("[Content_Types].xml", REQUIRED_FILES.content_types_xml);
        zip.file("word/_rels/document.xml.rels", REQUIRED_FILES.document_xml_rels);
      //
      zip.file("word/document.xml", html);
      zip.generateAsync({type:"blob"}).then(function(content) {
          saveAs(content, fname + ".docx");
      });
    }
    <script src="https://cdn.jsdelivr.net/npm/file-saver@2.0.2/dist/FileSaver.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.2/jszip.min.js"></script>
    <button onclick="generateDocx('test_1')">Download .docx</button>

    使用的库
  • JSZip
  • FileSaver.js

  • External Demo (因为内联可能不起作用)

    关于javascript - 无法使用 Blob 对象在客户端打开 `docx` 文件 - vanilla JavaScript,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59201272/

    相关文章:

    javascript - 使用日期作为哈希表键

    javascript - 从 jQuery .ajax() 问题调用 Web 服务

    html - 和 之间有什么区别?

    C++代码查找文件中的所有IP地址

    javascript - 禁用整个页面的 UpdateProgress

    javascript - jQuery UI slider 自定义步骤增量和加载时的逗号

    php - 将 SimpleXML 转换为 DOMDocument,而不是 DOMElement

    ruby-on-rails - 将 XML 文档导入 Rails 数据库?

    java - 用于下载文件的rest api返回文件内容作为响应而不下载它

    java - 在一个路径中一起解析符号链接(symbolic link)和 ".."