ワタシは辞書です

pythonらしいというか。ま、python に限らず、動的な言語はだいたいこんなことが出来ますな。

python で、xpath の simplifyで、こんなのを書いた:

 1 # -*- coding: utf-8 -*-
 2 from xml.etree.ElementPath import xpath_tokenizer
 3 
 4 def xpath_simplify_tokenize(xpath, nsmaps={}):
 5     depth = 0
 6     for tok in xpath_tokenizer(xpath, nsmaps):
 7         if tok[0] == '[':
 8             depth += 1
 9         elif tok[0] == ']':
10             depth -= 1
11         elif depth == 0:
12             yield tok
13 
14 print(list(
15         xpath_simplify_tokenize(
16             '/books/author[last-name [position()=1]= "Bob"]')))
17 
18 # ancestor::は無論「namespace」ではないが、xpath_tokenizer は「馬鹿」なので。
19 # そもそも xpath フルスペックを扱おうとするものではないので…。
20 # 戻りには {ancestor}: のように、python 文字列の format が扱える形("{a}".format(a=1)という
21 # 具合)で返るので、nsmaps の工夫で多分なんとかなる。
22 print(list(
23         xpath_simplify_tokenize(
24             'ancestor::author[last-name [position()=1]= "Bob"]',
25             {'ancestor': 'ancestor'})))

これな、こんなんしとけばいいのな:

 1 # -*- coding: utf-8 -*-
 2 from xml.etree.ElementPath import xpath_tokenizer
 3 
 4 class _M(object):
 5     def __getitem__(self, name):
 6         return name
 7 
 8 def xpath_simplify_tokenize(xpath, nsmaps=_M()):
 9     depth = 0
10     for tok in xpath_tokenizer(xpath, nsmaps):
11         if tok[0] == '[':
12             depth += 1
13         elif tok[0] == ']':
14             depth -= 1
15         elif depth == 0:
16             yield tok
17 
18 print(list(
19         xpath_simplify_tokenize(
20             '/books/author[last-name [position()=1]= "Bob"]')))
21 
22 print(list(
23         xpath_simplify_tokenize(
24             'ancestor::author[last-name [position()=1]= "Bob"]')))

class _Mのインスタンスは「obj['xyz']」に対して単に「'xyz'」をそのまま返す。ので、今の場合、ancestorをそのまま返すので、結果、実行結果は前回と全く同じ:

1 me@host: ~$ python aaa2.py
2 [('/', ''), ('', 'books'), ('/', ''), ('', 'author')]
3 [('', '{ancestor}:author')]
4 me@host: ~$

となって、めでたし。