2008-09-04

IEでjQueryを利用してxmlをパース

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
サーバからxmlを受け取るajaxアプリを最近firefoxで確認しながら作っていたのですが、ふとIEで見てみたらxmlのパースがうまく出来ていないことが判明しました。

どうもIEでは、明示的にヘッダーに
Content-Typeにtext/xml; charset=utf-8としてあげないとだめみたいです。

なので、google app engineでxmlを返す際には
きちんと以下のような感じでヘッダーを指定しないといけないようです。
self.response.headers["Content-Type"] = "text/xml; charset=utf-8"
self.response.out.write(template.render(path, template_values))

ちなみにクライアント側のコードは以下のような感じです。

function hogehoge(val) {
if (!confirm('よろしいですか?')) {
return;
}
$.ajax({
url: '/hogehoge/hoge?key=' + val,
type: 'GET',
error: cant_connect,
success: get_xml_message
});
}

function cant_connect() {
alert('サーバーと接続できませんでした');
}

function get_xml_message(xml) {
var message;
$(xml).find('message').each(function(){
message = $(this).text();
});
alert(message);
}



ちなみにIEでは、きちんとheaderでContent-Typeを指定してないと
$(xml).find('message').each(function(){
の部分がうまく動いてくれないのでした。

2008-08-24

pythonで文字列の中に携帯の絵文字が含まれているかどうかを確認する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
pythonで文字列の中に絵文字が含まれるかどうかを確認しようとして以下のような関数を作ってみました。
とりあえず、受け取るフォームはutf-8で作られているとしています。

def include_emoji(str):
'''指定文字列内に絵文字が含まれるかどうかを確認する

  引数
str String チェック対象文字列(utf-8)
  戻り値
Boolean'''
if str is None:
return False
try:
dummy = unicode(str,'utf-8').encode('euc_jp')
except UnicodeEncodeError,UnicodeDecodeError:
return True
return False

本当にこんなんでいいのかどうかよくわからないけど、簡易的に試した限りはうまくいく気配。
でも、本当は携帯の絵文字をキャリア毎に変換することをやりたいと思ったのですが、pythonでのやり方がわからず挫折。
perlやPHPでは変換モジュールみたいのがあるのですが、pythonでは見つからず。。。
作り直すには技術が足らず。。。

cssでドロップダウンメニュー

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
とりあえず、

http://www.dynamicdrive.com/style/csslibrary/item/inverted-shift-down-menu/
http://blog.faro.main.jp/?eid=369489
にお世話になりドロップダウンメニューを作ってみました。

こんな感じ

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<!--ここからCSS-->
<style type="text/css">
body {
margin: 0; /*ブラウザデフォルトの空白を除去*/
}

.menu {
position: absolute;
top: 100px;
width: 100%;
padding: 0;
border-top: 5px solid #D00;
font: bold 12px Arial;
}

.menu_list {
margin:0;
margin-left: 40px; /*メニューの横の隙間*/
}

.menu dl {
margin:0;
padding: 0;
float: left;
}

.menu dt {
margin: 0 2px 0 0; /*メニュー間の隙間*/
}

.menu dd {
display: none;
margin: 0;
padding: 5px 10px 5px 10px;
border-left: 1px solid #000;
border-right: 1px solid #000;
border-bottom: 1px solid #000;
background-color: #DDD;
}

.menu dl:hover dt {
background-color: #DAA;
padding-top: 9px;
padding-bottom: 5px;
color: #FFF;
}

.menu dl:hover dd {
display: block;
}

.menu a {
display: block;
color: #000;
text-decoration: none;
}

.menu a:hover {
color: #FFF;
}

.menu dd a:hover {
color: #D00;
}

.menu .current {
background-color: #D00;
padding: 9px 10px 5px 10px;
color: #FFF;
}

.menu dl:hover dt.current {
background-color: #D00;
}

.menu .menu_item {
padding: 5px 10px 9px 10px;
}
</style>
<!--ここまでCSS-->
</head>

<body>
<div class="menu">
<div class="menu_list">
<dl><dt class="current">Menu1</dt></dl>
<dl><dt class="menu_item"><a href="">Menu2</a></dt></dl>
<dl><dt class="menu_item"><a href="">Menu3</a></dt></dl>
<dl><dt class="menu_item">Menu4</dt>
<dd><a href="">Menu4-1</a></dd>
<dd><a href="">Menu4-2</a></dd>
<dd><a href="">Menu4-3</a></dd>
</dl>
<dl><dt class="menu_item"><a href="">Menu5</a></dt></dl>
</div>
</div>
</body>
</html>


FireFox3とIE7では動くみたいですが、IE6はひょっとしたら
http://blog.faro.main.jp/?eid=369489
に書いてあるjavaスクリプトも入れないといけないのかもしれないです。

そして関係ないですが、
色指定で
#D00
と書いたら
#DD0000
の意味になるらしいですね。

2008-08-02

Google App Engineで日本時間を表示する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Google App Engineでdateime型を利用すると日本時間が表示されないでちょっと困ります。
そこでいろいろ調べた結果
http://webdba.blogspot.com/2008/04/google-app-engine4python.html
を参考に以下のような感じで解決することにしました。

モデルを以下のように作成します。
モデル内にget_create_tという関数を作成してここで時間の表示したい形式でフォーマッティングします。

from datetime import *
from google.appengine.ext import db

class Samples(db.Model):
name = db.StringProperty(required=True)
create_t = db.DateTimeProperty(required=True,auto_now_add=True)

def print_create_t(self):
jd = self.create_t + timedelta(hours=9)
return jd.strftime("%Y-%m-%d %H:%M:%S")


その後、実際に出力するさいには
sample.print_create_t()
とすることで利用できます。

2008-07-27

GQLでReference型の列でIN条件を利用する

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
GQLでReference型の列に対してINを利用するのにちょっと悩んでしまったので、メモです。
以下のようなモデルがある時の場合です。

class AAA(db.Model):
name = db.StringProperty(required=True)

class BBB(db.Model):
memo = db.StringProperty(required=True)
ref = db.ReferenceProperty(AAA)

AAAからデータを一回引っこ抜いて、そこでBBB用検索用のIN条件を作成する場合ですが、以下のようにする必要があります。

aaa = db.GqlQuery("SELECT * FROM AAA")
search_list = []
for aa in aaa:
search_list.append(aa.key())
bbb = db.GqlQuery("SELECT * FROM BBB WHERE ref IN :list",list = search_list)

search_list.append(aaa.key())
の部分を
search_list.append(aaa)
としていたら、以下のようなエラーが出てしまったのです。

Traceback (most recent call last):
....
File "C:\...\google\appengine\ext\db\__init__.py", line 1257, in __iter__
return self.run()
File "C:\...\google\appengine\ext\db\__init__.py", line 1589, in run
query_run = self._proto_query.Run(*self._args, **self._kwds)
File "C:\...\google\appengine\ext\gql\__init__.py", line 563, in Run
bind_results = self.Bind(args, keyword_args)
File "C:\...\google\appengine\ext\gql\__init__.py", line 254, in Bind
query.update(enumerated_query)
File "C:\...\google\appengine\api\datastore.py", line 1035, in update
self.__setitem__(filter, value)
File "C:\...\google\appengine\api\datastore.py", line 978, in __setitem__
datastore_types.ToPropertyPb(' ', value)
File "C:\...\google\appengine\api\datastore_types.py", line 958, in ToPropertyPb
'Unsupported type for property %s: %s' % (name, proptype))
BadValueError: Unsupported type for property :


あと、Google App Engineのバグなのかどうかわかりませんが、GQLでINを使ったクエリーの結果に対して、count()を利用するとエラーが出るようです。
これは、ReferencePropertyと関係なくでるようです。StringPropertyでも出ることを確認しました。
ちなみに以下のようなエラーメッセージが出ます。

Traceback (most recent call last):
File "C:\...\google\appengine\ext\webapp\__init__.py", line 499, in __call__
handler.get(*groups)
File "C:\...\myapp.py", line X, in get
xxx = items.count()
File "C:\...\google\appengine\ext\db\__init__.py", line 1286, in count
return self._get_query().Count(limit=limit)
File "C:\...\google\appengine\api\datastore.py", line 957, in Count
self._ToPb(limit=limit), resp)
File "C:\...\google\appengine\api\datastore.py", line 1110, in _ToPb
pb.set_kind(self.__kind.encode('utf-8'))
AttributeError: 'NoneType' object has no attribute 'encode'

最初、ずっとcountしていて何をしてもエラーが出るから原因がなかなかつかめませんでした。

Google App EngineのModelの制限

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Google App EngineでModelを定義するときに、同じモデルに対するReferenceProperty
を二つ設定できない模様(同じモデルに限らないのかもしれないのですが・・・)。

具体的には、

class Users(db.Model):
name = db.StringProperty(required=True)

class Friends(db.Model):
owner = db.ReferenceProperty(Users)
friend = db.ReferenceProperty(Users)

っていうのは、エラーになってしまいました。
しょうがないので、以下のように片方をStringPropertyにしてkey値を文字列に変換して入れて対処してみました。

class Friends(db.Model):
owner = db.StringProperty()
friend = db.ReferenceProperty(Users)

2008-07-08

GQLの制限メモ

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
なにかと便利なGoogle App Engineですが、GQLはなれないといけない感じです。
ちょっと試してGQLの制限をメモ
・ORは使えない
・INの使いっぷりはSQLのつもりで書いてはいけない
 以下のような感じで使う

list = ['a1','a2','a3']
ret = db.GqlQuery("SELECT * FROM aaa WHERE col1 IN :1",list)

2008-07-06

pythonで携帯IP制限

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
携帯専用ページにするには、各携帯キャリアのIPアドレスを利用して制限をかけるみたいです。
通常は、htaccessとかでwebブラウザにこのお仕事を任せるのが通常のやり方のようなのですが、pythonのプログラム側で実装してみたいなぁと思ったので試してみました。

まずは、各携帯キャリアの利用IPアドレスが必要なわけですが、それは
http://d.hatena.ne.jp/tomisima/20070903/1188836400
を利用することで取得することができます。
これで取得した結果を適当にファイルなどに保存したりして利用します。

あんまりpython詳しくないのでいまいちな書き方の可能性が高いけど、私はこんな感じでやってみました。
各キャリアのサブネットは24より小さいことはありえないだろうという勝手な思い込みが前提です。


from mobilejp import MobileJP

m = MobileJP()
ret = m.get_cidr()

iplist = []
for carrier in ret :
for cidr in ret[carrier] :
parts = cidr.split("/")
quads = parts[0].split(".")
quads.append(parts[1])
iplist.append(quads)

chkip = os.getenv('REMOTE_ADDR')

q = chkip.split(".")
find = False
for cidr in iplist :
if int(cidr[0]) != int(q[0]) :
continue;
if int(cidr[1]) != int(q[1]) :
continue;
if int(cidr[2]) != int(q[2]) :
continue;
chk4 = int(q[3])
chk4 = chk4 >> (32 - int(cidr[4]))
chk4 = chk4 << (32 - int(cidr[4]))
if int(cidr[3]) == chk4 :
print "OK"
find = True
break;
if find == False :
print "NO"


こんな感じでできていそうな気がします。

2008-07-01

Amazonの個別商品ページを携帯で見る

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
AmazonのWEBサービスを利用することでアフィリエイトつきの商品個別のページのURLを取得することができますが、携帯でこのURLを見ようとするとどうも長すぎて見れないようです。
なので携帯で見るには、別のURLを個別に生成する必要があるようです。

以下が参考になります。
http://tech.bayashi.jp/archives/entry/techweb/2006/001376.html
http://aws.typepad.com/aws_jp/2005/07/amazon_.html

携帯用には、以下のようなURLでいけるようです。
http://www.amazon.co.jp/gp/aw/rd.html?uid=NULLGWDOCOMO&at=[ASSOCIATE_TAG]&a=[ASIN]&o=Add&dl=1&url=%2Fgp%2Faw%2Fc.html
この[ASIN]の部分をWEBサービスで取得してうめることで携帯で見ることができるようです。

iアプリでxmlを読む

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
iアプリでxmlを読むにはkXML2というのを使うといいらしいです。
その方法は、
http://www.ntts.co.jp/products/mobile/detail/article.html
の
第6回「ケータイ+RSSでドコデモ最新情報ゲット」
というのを見ればわかります。
iアプリのサイズを小さくするためにkXML2の一部のファイルのみを組み込ませる方法が書いてあって役に立ちます。
他の記事もiアプリ情報としてはとても役に立ちますよ。

そしてXMLを使っていれば当たり前のかもしれませんが、
XMLデータ内に&があるとkXML2が解析に失敗するようです。
なのでXMLデータに&を入れたいときは、データをURLエンコードしておく必要があるようです。