content.opfファイルを解析する
サンプル2はEPUB内の特定のXHTMLしか表示できませんが、実際のEPUB形式ではXHTMLのファイル名やディレクトリ階層を自由に指定できます。
EPUBファイル内で使用されるXHTMLファイルやページの順番は「content.opf」というXMLファイルに記述されており、たとえば今回のサンプルデータの場合は以下のようになっています。
■content.opfの内容
<?xml version="1.0" encoding="UTF-8"?> <package xmlns="http://www.idpf.org/2007/opf" unique-identifier="BookID" version="2.0"> <metadata xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:opf="http://www.idpf.org/2007/opf"> <dc:identifier id="BookID" opf:scheme="UUID">fcdbe9e3-a185-40ee-8a61-920d69c69db7</dc:identifier> <meta name="Sigil version" content="0.2.3"/> </metadata> <manifest> <item id="ncx" href="toc.ncx" media-type="application/x-dtbncx+xml"/> <item id="Section0001.xhtml" href="Text/Section0001.xhtml" media-type="application/xhtml+xml"/> </manifest> <spine toc="ncx"> <itemref idref="Section0001.xhtml"/> </spine> </package>
使用するファイルはmanifest要素内にあるitem要素に、ページの表示順序はspine要素内のitemref要素に記述されています。spine要素内のitemref要素に記述されているidref属性のIDを読み出し、同じIDを持つitem要素をmanifest要素内から探し出すと、表示するXHTMLファイルを特定できます。実際に表示するXHTMLファイルはitem要素のhref属性に書かれています。
content.opfのXMLデータを解析するプログラム(analysisXML関数)を作成します。XMLデータ処理を簡素化するため、以下のようにして文字列として格納されているXMLをページ上に流し込みます。これによってDOMとして取り扱えるようになり、getElementsByTagName()などを使ってアクセスできます。
document.getElementById("epubxml").innerHTML = xmldata; var epubXML = document.getElementById("epubxml");
ファイル情報が記述されているmanifest要素内のitem要素には、以下のようにしてアクセスできます。変数itemTagにはitem要素が配列として入ります。
var itemTag = epubXML.getElementsByTagName("manifest")[0].getElementsByTagName("item");
ページの表示順序が記述されているspine要素内のitemref要素は以下のようにして取得します。変数indexItemにはitemref要素が配列として入ります。
var indexItem = epubXML.getElementsByTagName("spine")[0].getElementsByTagName("itemref");
次に、itemref要素のidref属性に記述されているIDを読み出します。以下のようにgetAttribute()を使います。
var ID = indexItem[i].getAttribute("idref");
あとはfor()を使って同じIDが見つかるまで繰り返します。以下の例ではエラー処理はしていませんが、EPUBデータが間違っていない限り必ず対応するIDがあります。
for(var i=0; i<indexItem.length; i++){ var ID = indexItem[i].getAttribute("idref"); // IDを読み出す for(var j=0; j<itemTag.length; j++){ var cID = itemTag[j].getAttribute("id"); // IDを読み出す if (ID == cID){ fileList.push(itemTag[j].getAttribute("href")); // href属性を読み出す break; // ループから抜ける } } }
content.opfファイルの解析が終わってファイルリストを取得できたら、最初のXHTMLファイルだけ表示してみましょう。以下のようになります。
xhtmlList = analysisXML(zip.files["OEBPS/content.opf"].data); // XMLデータ解析 var text = zip.files["OEBPS/"+xhtmlList[0]].data; // 最初のページを表示 document.getElementById("result").innerHTML = Utf8.decode(text);
ここまでの処理をまとめたのがサンプル3です。
■サンプル3
<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>EPUBデータの最初のページだけを表示</title> <script type="text/javascript" src="js/sjis.js" charset="shift_jis"></script> <script type="text/javascript" src="js/zip.js" charset="shift_jis"></script> <script type="text/javascript" src="js/utf8.js" charset="utf-8"></script> <script> window.addEventListener("load", function(){ document.getElementById("viewEPUB").addEventListener("click", function(){ document.getElementById("result").innerHTML = ""; var fileData = document.getElementById("myFile").files[0]; var reader = new FileReader(); reader.onload = function(evt){ var bytes = []; var byteData = evt.target.result; for (var i = 0; i <byteData.length; i++)bytes[i] = byteData.charCodeAt(i); var zip = Zip.inflate(bytes); // console.dir(zip.files["OEBPS/content.opf"]); xhtmlList = analysisXML(zip.files["OEBPS/content.opf"].data); // XMLデータ解析 var text = zip.files["OEBPS/"+xhtmlList[0]].data; // 最初のページを表示 document.getElementById("result").innerHTML = Utf8.decode(text); } reader.readAsBinaryString(fileData); }, true); }, true); // XMLデータを解析してXHTMLファイル一覧を返す function analysisXML(xmldata){ document.getElementById("epubxml").innerHTML = xmldata; var epubXML = document.getElementById("epubxml"); var fileList = []; // EPUB表示に必要なファイル項目を取得 var itemTag = epubXML.getElementsByTagName("manifest")[0].getElementsByTagName("item"); // 表示順を示すitemrefタグを取得 var indexItem = epubXML.getElementsByTagName("spine")[0].getElementsByTagName("itemref"); // ページの表示順番を取得(IDからファイル名を取得) for(var i=0; i<indexItem.length; i++){ var ID = indexItem[i].getAttribute("idref"); // IDを読み出す for(var j=0; j<itemTag.length; j++){ var cID = itemTag[j].getAttribute("id"); // IDを読み出す // console.log(ID+" = "+cID); // 確認したい人はコメント削除してください if (ID == cID){ fileList.push(itemTag[j].getAttribute("href")); // href属性を読み出す break; // ループから抜ける } } } return fileList; } </script> </head> <body> <h1>EPUBデータの最初のページだけを表示</h1> <form action="./test.cgi" method="get"> <input type="file" id="myFile" /> <input type="button" id="viewEPUB" value="EPUB表示" /> </form> <div id="result"></div> <div id="epubxml" style="display:none"></div> </body> </html>