MS Word2011,2013の「ドキュメントのプロパティ」>「ユーザー設定」についてのメモ
Wordでは「ドキュメントのプロパティ」を本文中で参照することが可能であり(多くの場合「クイックパーツ」から貼り付けられる),また,独自のプロパティをユーザーが設定することも可能である。
これを上手く使えば Don't Repeat Again な文書作成も可能となるはずだ。
よく知られているように.docxファイルはXML等をZIPで固めたものなので,unzipすれば中身を確認できる。
そして,パッと見た感じ,ユーザー設定のプロパティは THE_DOC.docx/docProps/custom.xml に記録されている。
例えばこんな風に。
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <Properties xmlns="http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" xmlns:vt="http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes"> <property fmtid="{00000000-0000-0000-0000-000000000000}" pid="2" name="ひづけ(Mac)"> <vt:lpwstr>00002010/05/21</vt:lpwstr> </property> <property fmtid="{00000000-0000-0000-0000-000000000000}" pid="2" name="ひづけ(Win)"> <vt:filetime>2010-05-20T15:00:00Z</vt:filetime> </property> <property fmtid="{00000000-0000-0000-0000-000000000000}" pid="4" name="てきすと"> <vt:lpwstr>てきすとの値</vt:lpwstr> </property> <property fmtid="{00000000-0000-0000-0000-000000000000}" pid="5" name="すうち"> <vt:i4>11922960</vt:i4> </property> <property fmtid="{00000000-0000-0000-0000-000000000000}" pid="6" name="うむ"> <vt:bool>true</vt:bool> </property> </Properties>
プロパティは「日付」「テキスト」「数値」「有無」の4種類から選ぶことができる。
プロパティには共通のFMTIDなるものが振られていて(上の例では念のため全て0に置き換えた),これはプロパティセットフォーマット…を識別するための、GUID
(型/構造体リファレンス - GUID,CLSID,IID,FMTID,CATID)らしいけどよく分からない。
さて,上のプロパティリストの「ひづけ(Mac)」と「ひづけ(Win)」は,同じファイルをそれぞれ Word2011 (Mac) と Word2013 (Win) で保存した場合に記録されたプロパティの値である。
Macでは lpwstr タグ内で,0000yyyy/mm/ddという書式の値が振られ,Winでは filetime タグ内で ISO 8061形式の日付が振られている(2010-05-20T15:00:00Z(世界標準時)は2010-05-21T00:00:00+09:00(日本標準時)と等しいので,両者は要するに同じ日を指している。)。
(テキスト,数値,有無については面倒なので,タグの違いは確認しなかった。)
実は,Word2011で日付形式のプロパティを追加しようとしたところ,ISO8061形式であると0000yyyy/mm/dd書式であるとに関わらず,入力した値は指定された種類ではありません。値はテキストとして保存されます。
というエラーメッセージが出てしまい,日付のプロパティを設定できなかった。
ちょっとよく分からない。
特定の日までの日数を表示する Web サービス
こんなのサーバー使わなくても JavaScript でクライアントサイドで完結させられるんですが、ガラケー向けということで。ガラケーなら input が数字。
http://okelawebsite.appspot.com/calcudate
URL の末尾に ?d=20110913 のような形式で日付を指定すれば、当該日付までの日数を表示します。変な引数だと自動的にクリスマスイヴまでの日数になります。
まぁ、サーバーサイド環境を得たおかげでこういう小物も簡単に作れるのは良いんですけど。
困ったところ。日付を整形して出力する datetime.date.strftime
で日本語や unicode が上手く通らなかった。 codec 使って色々試したけどどうにも…。
なので結局 str(todate.year)+u"年"+str(todate.month)+u"月"+str(todate.day)+u"日"
という力押しに。きちゃない。
困ったところその2。
ガラケーの数値入力だけで行けるようにすることを考えると、 input 要素の type は date じゃなくて number の方が楽。というのは、 date を指定してモダンなブラウザでアクセスすると、 yyyy-mm-dd という、( ISO 標準の? ) 形式になるので、サーバーサイドで切り分ける手間がかかるからです。
大した手間じゃないですが、身内向けなのでその手間も惜しみました。
JavaScript : 1行で、より0から遠い整数値に丸める
要するに、 0 よりも大きければ Math.ceil() を、 0よりも小さければ Math.floor() を使うわけです。
function foo(num){ return (num>0 ? Math.ceil : Math.floor)(num); } //下記コードと同等 function foo2(num){ var func; //丸めに使う関数 if(num>0){ func = Math.ceil; } else { func = Math.floor; } return func(num); } //普通はこう書くのかも。 function foo3(num){ return num>0 ? Math.ceil(num) : Math.floor(num); } //普通の長いバージョン function foo4(num){ if(num>0){ return Math.ceil(num); }else{ return Math.floor(num); } }
ポイントは、「関数を使い分け」るのではなく「関数を選び分け」ている事。
メリットを強いて言えば、同じ引数を2度書かずに済むことでしょうか。 floor, ceil では引数が1つなのでメリットは活きないですが、多くのあるいは複雑な引数を取る関数を使い分ける場合には、引数の修正が必要になっても修正が1箇所で済むから楽かもしれません。
可読性の低下のほうが問題かもしれませんけど。
東北電力の使用状況 CSV 形式が変更されました。
前から東京電力では5分間隔の使用状況とかが分かるようになってたんですが、東北電力の発表データもそれと同じものになったと思われます。
データのフォーマットが違うので、正しく動作しない予感。
携帯電話用のサイト (http://okelawebsite.appspot.com/ecoco) では Yahoo!電力使用情況API を使っていたので改修の必要はありませんが、左にある OpenSocial 版は改修が必要ですね。
前日以前のデータは別ファイルとして提供されるようになったので、これもまた検討が必要。単純な前日比ではなく、「今日によく似た日」を選ぶようにしても面白いかもしれません(データ解析は大変ですが)。さしあたりは先週同曜日データで代用でしょうか。
夜明け頃追記
さしあたりスクショだけ。お休みなさい。
json から辞書でなくオブジェクトっぽく。
Yahoo!電力使用情況API を使うにあたって JSON をロードしたりしてたんですが、タイミングよくこんな話が。
【辞書にオブジェクトっぽくアクセスする - Keep on moving】
Python 2.6 以降に搭載されている json ライブラリでは、 JSON のロード時にフックを指定することが出来て、上手く使えばロードした JSON をオブジェクトっぽくアクセスできるようになるそうです。
で、 Google App Engine の Python はバージョンが古くて json ライブラリが搭載されていませんが、 Django は標準搭載されているので、そこに含まれる simplejson ライブラリが使える。つまり
from django.utils import simplejson as json
とすれば大抵のコードは流用が可能です。
そして、 simplejson の load にも同様の object_hook 引数がある。つまり、上掲記事と同じことが GAE でも出来る!
さて、 object_hook にはフック用のクラスを渡します。
上掲の id:Ehren さんの記事では別途クラスを定義していましたが、いわゆる無名クラス*1を渡してしまえば、別途の定義も必要なくなります。
test = json.loads('{"foo":[{"a":1},2]}', object_hook=type("D", (dict,), {"__getattr__": dict.__getitem__}))
(とか言いつつ __getattr__ とか __getitem__ とか type() とか初めて触りましたが…。)
しかしまぁ、こうしてみると、 type() を使うと可読性が落ちて見えますね…。
さて、朮の嵌ったところ。
type 関数で dict を継承しようとしたら、下記エラーが。
>>> type("D", (dict), {} ) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: type() argument 2 must be tuple, not type
原因は第2引数。 () で囲っても、中身が1つだとタプルにならないんですね。
>>> (1) 1 >>> (1,) (1,) >>> #というわけで ... type("D", (dict,), {} ) <class '__main__.D'>
dict の後の「,」がポイントです。
余談。
Yahoo!電力使用情況API の JSON は、数値だけのデータに対して "$" という名前をつけています。(たぶん XML から JSON に変換しているんだけど、 Attribute 付きの Element を JSON にするときにノードに名前をつける必要があるから。)
が、どうやら $ は Python 的に特殊なので、上述のように読み込んでも
data.ElectricPowerUsage.Usage.$
とかだと上手くアクセス出来ない。
なので、次のようにアクセスすることになります。
data.ElectricPowerUsage.Usage["$"]
"$" じゃなくてもうちょっとマシな文字を選んでくれたら良かったのに><
*1:でも名前付いてるような…。
東北電力使用状況のモバイル版を作りました。
http://okelawebsite.appspot.com/ecoco
使用率等を表示するだけですけど。
mixiアプリモバイルに出来なかった件
mixiアプリモバイル化を念頭において作ったんですが(どうやら mixi 外部の HTML を埋め込んで表示しているみたい?)、作ったは良いもののモバイル版アプリを公開できるのは認定法人パートナーだけらしいので、アプリ化は断念です。まぁ、でも HTML を表示しているだけである以上、その元の HTML を直接開いてしまえば良いだけなんですけどね。
GAE での JSON
上記 URL から明らかなように、 GAE を使って実装しています。
また、データは東北電力からではなく、Yahoo! 電力使用情況APIを使って取得しています。
データの取り回しが楽な JSON で取得することにしたのですが、 GAE の Python はバージョンが古いため、標準ライブラリの JSON は存在しない。
ですが、 Django が標準で使え、 Django に simplejson が含まれているので、これをインポートして何とかしました。
from django.utils import simplejson as json
東北電力使用状況のグラフ表示とガジェットにおけるタブ UI
まず、 mixi アプリとしても提供を始めました。 OpenSocial なので全く同じコードを使うことが出来るので、 Google にホストしている XML を参照しているだけなんですけどね。
朮は mixi のアカウント持っていないので、類聚揮洒の副管理人である casm 氏に代行してもらっています。
で、実物を見てもらったほうが早いですが、グラフを表示するようにして、ついでにタブで切り替えられるようにしました。タブ周りのドキュメントが解りにくいのでちょっくらメモ。
<Module> <ModulePrefs title="ガジェット名"> <Require feature="tabs"/> <Require feature="setprefs"/> </ModulePrefs> <UserPref name="selectedTab" datatype="hidden"/> <Content type="html"><![CDATA[ 略 <script type="text/javascript"> var tabs = new gadgets.TabSet(__MODULE_ID__); gadgets.util.registerOnLoadHandler(function(){ tabs.addTab("現在値", {contentContainer: document.getElementById("tab_main")}); tabs.addTab("グラフ", {contentContainer: document.getElementById("tab_graph")}); }); </script> <div id="tab_main" stle="display:none"> <!-- 「現在値」タブ内のコンテンツ --> </div> <div id="tab_graph" stle="display:none"> <!-- 「グラフ」タブ内のコンテンツ --> </div> ]]></Content> </Module>
ドキュメントに言うところのテクニック 2
を使っています。
まず ModulePrefs 内で tabs を読み込むように。また、ユーザーが現在のタブを記憶できるように、 setprefs の読み込みと selectedTab の UserPref も用意します(これだけで自動的にタブを記憶するみたいです)。
gadgets.TabSet を初期化。ただし、具体的なタブへの要素の追加はロード後(gadgets.util.registerOnLoadHandler( handler );
の handler 内) に行います。
tabs.addTab() は、第1引数にタブ名、第2引数はタブの内容に関するパラメーターを渡すんですが、内容になる Element だけで良いみたいです。
あとグラフの描画には HTML5.jp さんの 折れ線グラフライブラリを使わせていただきました。
なるべく1ファイルで済ませたかったので、埋め込める程度の大きさのグラフライブラリということで。ちなみに JavaScript の圧縮ツールも試してみたんですけど、何故か動作しなくなるので諦めました。
大きなライブラリも Google Libraries API を使えば自前でホストせずに使えるので良いかなと思ったんですが、 API key を取るのが面倒な気がしたのでパス。