例如 OpenOffice.org (現為 Apache OpenOffice), LibreOffice, KOffice 等辦公室軟件
閉源的 Microsoft Office 由 2007 開始 及 線上辦公室應用的 Google Docs (現為 Google Drive 的一部分)
亦支援 OpenDocument Format
OpenDocument Format 由於使用 XML ,檔案於資料交換上非常簡單及方便
OpenDocument Format 將文件內容,文件風格,圖像等分開保存,再利用 Zip 壓縮技術將所有檔案包裝成一個獨立檔案
所以以任何文字編輯器觀察文件,會發現文件頭 2 個位元組是 PK (即 Phil Katz Zip 的作者)
在 Windows 環境下強行將副案名改為 zip 便可以將檔案壓縮
這篇文章主要介紹只使用 XML 製作 OpenDocument Spreadsheet (ods) 格式
為甚麼要使用 ods ? 而不使用更簡單的 Comma Separated Values (csv) 或 Plain Text (txt)
預設的 Spreadsheet ,csv 以逗號分隔,而 txt 以 tab 分隔
其他開源辦公室軟件,還可以自訂欄位分隔號及文字分隔符
兩者雖然非常簡單方便,但兩者都不能加入風格,例如文字顏色、欄位顏色、邊界顏色等
雖然 ods 不及 csv 及 txt 簡單,但 ods 仍然是一種不錯的 Spreadsheet 格式
若果只製作純資料的 OpenDocument Spreadsheet 文件
文件配置上只需要有 META-INF/manifest.xml, content.xml 這兩個文件
META-INF/manifest.xml 為指示以哪一種 OpenDocument Format 開啟及處理方式,因此這個檔案非常重要
(注意,META-INF 為全大寫字母)
content.xml 包含文件版面設定、字型、風格,及最主要的內容
META-INF/manifest.xml 內容大致如下,使用最基本的 OpenDocument Format 資訊
<?xml version="1.0" encoding="UTF-8"?><!-- --><manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0"><!-- --><manifest:file-entry manifest:media-type="application/vnd.oasis.opendocument.spreadsheet" manifest:full-path="/"/><!-- --><manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml"/><!-- --></manifest:manifest>
content.xml 內容大致如下
<?xml version="1.0" encoding="UTF-8"?><!-- --><office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" office:version="1.0"><!-- --><office:body><!-- --><office:spreadsheet><!-- --><table:table table:name="Sheet1"><!-- --><table:table-row><!-- --><table:table-cell office:value-type="string"><!-- --><text:p><![CDATA[hello, world]]></text:p><!-- --></table:table-cell><!-- --></table:table-row><!-- --></table:table><!-- --></office:spreadsheet><!-- --></office:body><!-- --></office:document-content>
當中的
<table:table table:name="Sheet1"><!-- --><table:table-row><!-- --><table:table-cell office:value-type="string"><!-- --><text:p><![CDATA[hello, world]]></text:p><!-- --></table:table-cell><!-- --></table:table-row><!-- --></table:table>就是顯示的資訊部分
大致上與 HTML 的 table tr td 差不多
<![CDATA[hello, world]]> 這種寫法是避免文字包含「&」、「>」、「<」這類 XML 特殊字元而發生問題
另外常用的跨列跨欄屬性 table:number-rows-spanned, table:number-columns-spanned 及 文字屬性 office:value-type
有 string (字串), float (浮點數), boolean (真假值) 等常用文字屬性
*註
由於由開源辦公室軟件所編製的 ods 不會包含 newline 及 tab 而是用單行編寫
使用者閱讀上相當困難,尤其資料非常龐大時,文字編輯器對單行編寫的閱讀能力亦會下降
而在下使用了大量 <!----> 是為了避免 XML 解析 newline 及 tab 卻保留閱讀性
但這種寫法會令文件體積增加 (單是一組 <!----> 已經 7 個位元組,還未計算 newline 及 tab 數量)
然後編製 ZipFile.php
<?php class ZipFile{ private $datasec = array(); private $ctrl_dir = array(); private $eof_ctrl_dir = "\x50\x4b\x05\x06\x00\x00\x00\x00"; private $old_offset = 0; private function unix2DosTime($unixtime = 0){ $timearray = (($unixtime == 0) ? getdate() : getdate($unixtime)); if ($timearray['year'] < 1980){ $timearray['year'] = 1980; $timearray['mon'] = 1; $timearray['mday'] = 1; $timearray['hours'] = 0; $timearray['minutes'] = 0; $timearray['seconds'] = 0; } return (($timearray['year'] - 1980) << 25) | ($timearray['mon'] << 21) | ($timearray['mday'] << 16) | ($timearray['hours'] << 11) | ($timearray['minutes'] << 5) | ($timearray['seconds'] >> 1); } public function addFile($data, $name, $time = 0){ $name = str_replace('\\', '/', $name); $dtime = substr('00000000' . dechex($this->unix2DosTime($time)), -8); $hexdtime = '\x' . $dtime[6] . $dtime[7] . '\x' . $dtime[4] . $dtime[5] . '\x' . $dtime[2] . $dtime[3] . '\x' . $dtime[0] . $dtime[1]; eval('$hexdtime = "' . $hexdtime . '";'); $fr = "\x50\x4b\x03\x04"; $fr .= "\x14\x00"; $fr .= "\x00\x00"; $fr .= "\x08\x00"; $fr .= $hexdtime; $unc_len = strlen($data); $crc = crc32($data); $zdata = gzcompress($data); $zdata = substr(substr($zdata, 0, strlen($zdata) - 4), 2); $c_len = strlen($zdata); $fr .= pack('V', $crc); $fr .= pack('V', $c_len); $fr .= pack('V', $unc_len); $fr .= pack('v', strlen($name)); $fr .= pack('v', 0); $fr .= $name; $fr .= $zdata; $this->datasec[] = $fr; $cdrec = "\x50\x4b\x01\x02"; $cdrec .= "\x00\x00"; $cdrec .= "\x14\x00"; $cdrec .= "\x00\x00"; $cdrec .= "\x08\x00"; $cdrec .= $hexdtime; $cdrec .= pack('V', $crc); $cdrec .= pack('V', $c_len); $cdrec .= pack('V', $unc_len); $cdrec .= pack('v', strlen($name)); $cdrec .= pack('v', 0); $cdrec .= pack('v', 0); $cdrec .= pack('v', 0); $cdrec .= pack('v', 0); $cdrec .= pack('V', 32); $cdrec .= pack('V', $this->old_offset); $this->old_offset += strlen($fr); $cdrec .= $name; $this->ctrl_dir[] = $cdrec; } public function file(){ $data = implode('', $this->datasec); $ctrldir = implode('', $this->ctrl_dir); return $data . $ctrldir . $this->eof_ctrl_dir . pack('v', sizeof($this->ctrl_dir)) . pack('v', sizeof($this->ctrl_dir)) . pack('V', strlen($ctrldir)) . pack('V', strlen($data)) . "\x00\x00"; } } ?>
這個類別可能閣下已經見過,這個類別其實來自 phpMyAdmin
由於減少多餘的資料,在下將原來的 comment 全部刪除,若果想查看原文件,請到 phpmyadmin/libraries/zip.lib.php
(注意:不同的 phpmyadmin 設定有機會不同,如 NAS, Windows, Linux 等,本文使用 LinuxMint)
這個類別的好處是不需要創建額外檔案便可以直接輸出 zip 檔
<?php // require('ZipFile.php'); header('Content-Type: application/zip; charset=UTF-8'); header('Content-Disposition: attachment; filename="myzip.zip"'); $zip = new ZipFile(); $zip->addFile('my content', 'content.txt'); echo $zip->file(); ?>
這樣便可以輸出 zip 檔
同樣道理,由於 ods 只是 zip
只要將輸出 MIME 改寫為 application/vnd.oasis.opendocument.spreadsheet
及加載檔案名為 META-INF/manifest.xml 及 content.xml 即可
<?php // require('ZipFile.php'); header('Content-Type: application/vnd.oasis.opendocument.spreadsheet; charset=UTF-8'); header('Content-Disposition: attachment; filename="myods.ods"'); $zip = new ZipFile(); $zip->addFile($manifest_string, 'META-INF/manifest.xml'); $zip->addFile($content_string, 'content.xml'); echo $zip->file(); ?>
另外還可以透過各類壓縮軟件,直接將檔案壓縮為 zip
以 7-Zip 為例子,由於 7-Zip 為跨平台軟件,利用 7-Zip 以 zip 壓縮文件可以無視不同平台的問題
7z a -tzip -mx9 myods.ods content.xml META-INF/利用 7-Zip 指令將 content.xml 及 META-INF/ 壓縮為 zip 同時直接將檔案輸出為 ods
關於 7-Zip指令 請查看在下另一篇文章
在 GUI 的操作下,使用 Windows 內建的 zip 或 Linux / Unix / Mac 的 Archive Manager 選擇 zip
亦可以達至相同效果
透過具 OpenDocument Spreadsheet 分析功能既辦公室軟件開啟
沒有留言 :
張貼留言