このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

拡張JSONにDOM風APIを導入してXML処理

「拡張JSONで表現したXMLの正規形」から引用:

正規形データに対して、DOM APIに相当するアクセス&操作の体系は簡単に定義できます。

「拡張JSONで表現したXMLの正規形」に沿った方法でやってみました。実際に簡単でした。

以下は、DOM APIの一部に相当する関数をPythonで書いたものです。elm.getAttribute(attr_name) のようなメソッドではなくて、getAttribute(elm, attr_name) のような関数形式です。また、ノード参照の代わりに配列インデックスを使っているところがあります。tag, tagged, untagged については後で少し説明します。

from caty.jsontools import tag, tagged, untagged

def createElement(tag_name, obj={"": []}):
    return tagged(tag_name, obj)

def tagName(elm):
    return tag(elm)

def getAttribute(elm, attr_name):
    return untagged(elm)[attr_name]

def hasAttribute(elm, attr_name):
    return attr_name in untagged(elm)

def hasAttributes(elm):
    return len(untagged(elm)) > 1

def setAttribute(elm, attr_name, val):
    untagged(elm)[attr_name] = val

def removeAttribute(elm, attr_name):
    del untagged(elm)[attr_nam]

def childNodes(elm):
    return untagged(elm)[""]

def hasChildNodes(elm):
    return len(untagged(elm)[""]) > 0

def firstChild(elm):
    return untagged(elm)[""][0]

def lastChild(elm):
    return untagged(elm)[""][-1]

def appendChild(elm, x):
    untagged(elm)[""].append(x)
    return x

def insertBefore(elm, new, i):
    untagged(elm)[""].insert(i, new)
    return new

def replaceChild(elm, new, i):
    untagged(elm)[""][i] = new
    return new

def removeChild(elm, i):
    obj = untagged(elm)
    old = obj[""][i]
    del obj[""][i]
    return old

次の例を考えます。

<!-- HTMLインスタンス -->
 <a href="http://www.example.jp/">example <strong>JP domain</strong> site</a>


// XJSON(拡張JSONインスタンス
@a {
"href" : "http://www.example.jp/",
"" : ["exmaple ", @strong {"" : ["JP domain"]}, " site"]
}

XJSON(拡張JSON)はアットマークで識別されたタグを持ちます。念のため、通常のJSONへのマーシャリング結果も示すと:


{
"$tag" : "a",
"href" : "http://www.example.jp/",
"" : ["exmaple ", {"$tag" : "strong", "" : ["JP domain"]}, " site"]
}

このインスタンスを生成するPythonコードは次のとおり:

tagged("a", {
 "href" : "http://www.example.jp/",
  "" : ["exmaple ", tagged("strong", {"" : ["JP domain"]}), " site"]
}

インスタンスリテラル表現とほとんど変わりません。アットマーク表現 @tag data の代わりに tagged(tag, data) という関数呼び出しが使われるだけです。taggedで付加されたタグは tag(tagged_data) で取り出せます。タグ以外の部分は untagged(tagged_data) です。 tagとuntaggedは、タグが付いてないデータに対してもエラーではなくて合理的な動作をするようになっています。

XJSON(拡張JSON)のメモリ内の表現は非常にシンプルで、ノードの相対的関係をノード自体には保持していません。ですから、DOM APIの nextSibling, previousSibling, ownerDocument などは実現できません。しかし、SAX APIで出来る事なら、ツリーをルートからたどっていけば遂行できます。データ形式の変換などは、SAX風の処理でたいていは間に合いますね。

XMLをXJSON(拡張JSON)にエンコードする方法は、AjaxリクエストやWebAPIのレスポンスをJSON処理系に取り込むために考えたものです。しかし、しばらくいじっていると、これは軽量で単純ながらも一般的なXML処理にも使える気がしてきました。たとえば、文書処理とかにも。