LoginSignup
11
10

More than 5 years have passed since last update.

javascriptでDOCX,ODTをプレーンテキストに

Last updated at Posted at 2016-02-18

javascriptでDOCX,ODTをプレーンテキストに

MSWordの.docx及びLibreOfficeの.odtはXMLをzipで固めたものなのでjavascriptでも解読は可能(なはず)。機会があったので試してみた。

動作環境

DOCXの構造調査

Wordで作られたdocxを展開したところ、テキスト情報は word/document.xml にあり、以下のような構造だった。

word/document.xml
<w:document>
  <w:body>
    <w:p>
      <w:r>
        <w:t>plain text</w:t>
      </w:r>
      <w:r>
        <w:tab/>
      </w:r>
    </w:p>
    <w:p>....</w:p>
  </w:body>
</w:document>
  • <w:p>はHTMLのP要素のように改行されて表示される
  • たくさんの<w:r>で細かくテキストが分割されている
  • タブ(U+0009)は<w:t>内には存在せず、別の<w:r>内の<w:tab>に変換されるようだ

docx2txtの実装

"use strict";
/**
 * .docxファイルを読み取りプレーンテキストにする
 * @param file {File|Blob} docxのファイル
 * @param callback {function} プレーンテキストを引数にする関数
 */
var docx2txt = function(file, callback) {
  var fr = new FileReader();
  fr.onload = function() {
    var xml,dom,txt,p,i,r,j,t,k;
    xml = new JSZip(fr.result).file('word/document.xml').asText();
    dom = (new DOMParser()).parseFromString(xml, 'application/xml');
    txt = "";
    p = dom.firstChild.firstChild.childNodes; //w:document>w:body>w:p
    for(i=0; i<p.length; i++) {
      if (p[i].nodeName !== 'w:p') {continue;}
      r = p[i].childNodes;
      for(j=0; j<r.length; j++) {
        if (r[j].nodeName !== 'w:r') {continue;}
        t = r[j].childNodes;
        for(k=0; k<t.length; k++) {
          if (t[k].nodeName === 'w:t') {txt += t[k].textContent;}
          else if (t[k].nodeName === 'w:tab') {txt += "\t";}
        }
      }
      txt += "\n";
    }
    callback(txt);
  };
  fr.readAsArrayBuffer(file);
};

//FileオブジェクトはDrag and Dropやinput[type='file']などで作成。以下の例はinputタグ
document.getElementById('inputFile').onchange = function(e) {
  var file = e.target.files[0];
  if (file && file.name.match(/\.docx$/i)) {
    docx2txt(file, function(txt) {
      console.info(txt);
    });
  }
};

ODTの構造調査

テキスト情報は .odt を展開した直下の content.xml にあり以下のような構造をしている

content.xml
<office:document-content>
  <office:body>
    <office:text>
      <text:h>
        <text:span>plain text</text:span>
      </text:h>
      <text:p>
        <text:span>
          <text:s/>はスペース
          <text:tab/>はタブ
        </text:span>
      </text:p>
      ...
    </office:text>
  </office:body>
</office:document-content>
  • DOCXに似ているが多少違う
  • <office:text>以下には<text:h><text:p>がある
  • <text:p>(またはh)直下の<text:span>内にplainTextがある
  • <text:span>の中にはplainText以外に、スペースを表す<text:s/>やタブを表す<text:tab/>が存在することもある

odt2txtの実装

ほぼ同じなので略:P

考察

javascriptでDOCXやODTからプレーンテキストを抜き出すのはそう難しくはなかった。
1MB程度のファイルで試したが処理は数秒だった。
詳細に検証したわけではないので変換できていない文字があるかもしれない。

11
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
10