あれ?抜けてる・・・。

よしよし今月も毎日埋まったなと思ってカレンダーを見てみると、なぜか6日のところだけリンクがない。なぜ抜けていることに気づかなかったのか…3日ためたのに2日だけ書いて終わったとかでしょうか。とりあえず5日と7日の日記から6日の自分を思い出して書いてきます。


明日で日記を書いた日数が400日になると思ってたのに、これのせいで400日目は4月6日の日記になってしまった。どうでもいいけどなんかむなしい。

ID3タグ@Python

上の日記忘れに関連して3月末の日記もちょろっと見たのだが、そこで解決していなかった問題を発見。id:tomoemon:20060328の日記でPythonでmp3のタグを取得するための方法を書いたが、実際fix_str関数は別のサイトのコピペなのでよく理解していなかった。最近XMLをいじることが多くUnicodeに関する知識が多少深まったおかげか今なら理解できることに気づいた。

def fix_str(s):
  try:
    #utf-8のunicode文字列を通常文字列に変換
    buf = "".join([chr(ord(x)) for x in s])
  except ValueError:
    #utf-16のunicode文字列が来たときはencodeで変換
    buf = s.encode("mbcs")
  return buf

PythonでいうUnicode文字列というのはutf-16UCS-2の文字列のことなので、上にある「utf-8unicode文字列」という表現は間違いで、正しくは「utf-8エンコードされた文字列」である。


@指摘を受けて追記
PythonにおけるUnicode文字列とはUCS-2またはUCS-4で、これはコンパイル時のオプションで決定される。UCS-2とは2バイトの文字集合であり、文字の表現方式であるutf-16とは違う。utf-16も基本的には1文字をUCS-2と同じコード体系の2バイトで表現するため今回は「たまたま」うまくいった。しかし、utf-16は1文字を4バイトで表現する可能性もあるため実は問題がある。そして、UCS-4でコンパイルされたPython(最近のLinuxに載っているのはこれらしい)では上手く動かないだろう。

参考リンク
http://www.python.org/doc/api/unicodeObjects.html
http://www.mylab.jp/diary/20060123.html

また、「unicode文字列が来たときはencodeで変換」以下の部分はとりあえずencode関数を使ったらうまくいったというだけで理解できていなかったが、encodeはUnicode文字列を指定した文字コードに変換して返すという関数なのでうまくいくというわけである。


しかし、chr(ord(x))の部分はいまだによくわからない。utf-8の文字列だけでなくShift-JISの文字もうまく処理できているようだけどなんなんだろうなぁ。まだ完全な理解には遠いらしい。

PHP5のインストールに苦戦

PC講座で使う予定のサーバをゴールデンウィーク明けまでに完成させなければならないが、ゴールデンウィークはこっちにいないので実質月曜日までに完成させなければならない。FedoraCore5をインストールして、SSHサーバとWebサーバを稼動させる。


そしていつものようにPHP5のインストールに手間取る。そのものはすでに入っているのだがmbstringなどの必要なモジュールが入っていないのでインストールのし直し。しかし、前に家でやったときと同じようにやってみてもさっぱり上手くいかない。



makeを繰り返すがさっぱり。


14時から18時までずーっとやっていたのだが上手くいかなかった。


Linuxなんてもういや。・゚・(ノД`)・゚・。


ってかSSH動かしたんだから電源つけておけば家からできたじゃん!?
はふぅorz

DOMでXML@Python,PHP5

PHPPythonもDOMでXMLを扱うためのモジュールはあるのだが、整形する際にできる空白のせいでこちらの思ったとおりのXMLファイルを出力しない。また、空白が入っているXMLファイルを読み込む際の扱いも違うのでメモしておく。

PHP5における空白の扱い

PHP5ではDOM XMLで読み込むときに、preserveWhiteSpaceの値を設定することで余計な空白を取り除いてくれる。しかし、これは混合ノードにおける空白に対してのみでテキストノードだけの場合は消してくれない。以下のようなコードでXMLファイルに対して処理した結果について考えてみよう。

<?php
$dom = new DOMDocument;
$dom->preserveWhiteSpace = false;
$dom->load('sample.xml')
$dom->save('sample.xml')
?>

このとき、以下のsample.xmlから[A]の部分の空白は取り除いてくれるが、[B]の部分の空白は取り除いてくれない。

<?xml version='1.0' encoding='utf-8'?>
<Root>
                    ・・・[A]
    <Record>
        <item>
                    ・・・[B]
            なのは
        </item>
    </Record>
                    ・・・[A]
</Root>

出力結果は以下のようになる。

<?xml version='1.0' encoding='utf-8'?>
<Root>
    <Record>
        <item>
            
            なのは
        </item>
    </Record>
</Root>

また、書き出すときはformatOutputの値によってノードの階層によって空白を入れてくれるのだが、すでに一部に空白が入っている状態だと整形されているものと受け取るのか、なにもせずにそのまま出力される。そのため、書き出す前に自分で必要のない空白はすべて削除する必要がある。実は他のパラメータでうまくいくのかもしれないが。

Pythonにおける空白の扱い

Pythonではxml.dom.minidomで読み込むときに自動的に空白を削除する方法が備わっていないので、値を取り出すときにstrip()を使う必要がある。書き込む際にはwritexml()で書き出すためのフォーマットを指定できるのだが、これがまたこちらの思い通りには動いてくれない。以下のようなコードでXMLファイルに対して処理した結果について考えてみる。

# -*- coding: sjis -*-
from xml.dom.minidom import parse

dom = parse('sample.xml')
file = open('sample.xml','w')
dom.writexml(file,'','\t','\n')
file.close()

以下のようなsample.xmlを処理すると

<?xml version='1.0' encoding='utf-8'?>
<Root><Record>フェイト</Record></Root>

1回実行した結果は以下の通りできれいに整形されてファイルが出力される。

<?xml version='1.0' encoding='utf-8'?>
<Root>
    <Record>
        フェイト
    </Record>
</Root>

同じコードでさらに実行すると空白が無駄に増えている。

<?xml version='1.0' encoding='utf-8'?>
<Root>
    
    
    <Record>
        
        フェイト
    
    </Record>
    

</Root>

空白が入ると余計にファイル容量が大きくなってしまうのでこれは避けたい。そのため、ファイルを読み込んでparseするときに空白のテキストノードは削除してしまうほうがよいだろう。整形をwritexmlに頼らないで自分で書くのもありだが、結局読み込む際には空白が邪魔になってしまうので毎回はじめに取り除いてしまったほうが楽だろう。


こちらももっと楽に扱える方法があるのかもしれない。