SimplePrograms - Python Wiki
https://wiki.python.org/moin/SimplePrograms
の 19番目のプログラムは、 21行の XML,HTML パーサです。
(このブログではうまく表示できないので、XML/HTMLデータは大文字のカギ括弧を使っています。)
dinner_recipe = '''<html><body><table>
<tr><th>amt</th><th>unit</th><th>item</th></tr>
<tr><td>24</td><td>slices</td><td>baguette</td></tr>
<tr><td>2+</td><td>tbsp</td><td>olive oil</td></tr>
<tr><td>1</td><td>cup</td><td>tomatoes</td></tr>
<tr><td>1</td><td>jar</td><td>pesto</td></tr>
</table></body></html>'''
# From http://effbot.org/zone/element-index.htm
import xml.etree.ElementTree as etree
tree = etree.fromstring(dinner_recipe)
# For invalid HTML use http://effbot.org/zone/element-soup.htm
# import ElementSoup, StringIO
# tree = ElementSoup.parse(StringIO.StringIO(dinner_recipe))
pantry = set(['olive oil', 'pesto'])
for ingredient in tree.getiterator('tr'):
amt, unit, item = ingredient
if item.tag == "td" and item.text not in pantry:
print ("%s: %s %s" % (item.text, amt.text, unit.text))
これを、prog-21.py というファイルにして実行してみます。
$ python3 prog-21.py
e "/home/espiya/test/python/samples/prog-21.py", line 18, in <module>
for ingredient in tree.getiterator('tr'):
^^^^^^^^^^^^^^^^
AttributeError: 'xml.etree.ElementTree.Element' object has no attribute 'getiterator'
$ (空白がずれていると思うので ^^ は tree.getiterator を表しています。)
SimpoePrograms 初めての実行できない事例ですね。ちなみに、コメントのURLももはや存在しません。
原因は、getiterator() ですね。
https://docs.python.org/ja/3.6/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.getiterator
バージョン 3.2 で非推奨: 代わりに Element.iter() メソッドを使用してください。
なので、
iter(tag=None)
現在の要素を根とする木の イテレータを作成します。
イテレータは現在の要素とそれ以下のすべての要素を、文書内での出現順 (深さ優先順) でイテレートします。 tag が None または '*' でない場合、与えられたタグに等しいものについてのみイテレータから返されます。イテレート中に木構造が変更された場合の結果は未定義です。
ということで、 tree.iter('tr') で tree の中で、タグが tr のものを抽出できます。指示に従って、
for ingredient in tree.iter('tr'):
と変更して prog-21-01.py を作成して、2つのファイルの違いを表示した後に、実行してみます。
$ diff prog-21.py prog-21-01.py
18c18
< for ingredient in tree.getiterator('tr'):
---
> for ingredient in tree.iter('tr'):
$
$ python3 prog-21-01.py
baguette: 24 slices
tomatoes: 1 cup
$
これは、HTML 形式のデータ dinner_recipe を取り扱うプログラムですね。
つまり、開始タグ + コンテンツ + 終了タグ からなる要素(element)の集まりで、コンテンツに別の要素を含んでいること(入れ子)を許すようなデータの扱いです。
プログラムを見ていきましょう。
import 文から、使用するモジュールは xml.etree.ElementTree で、それを etree としています。
tree = etree.fromstring(dinner_recipe) は、
文字列定数で与えられた XML 断片を解析します。 XML() と同じです。 text には XML データを含む文字列を指定します。 parser はオプションで、パーザのインスタンスを指定します。指定されなかった場合、標準の XMLParser パーザを使用します。 Element インスタンスを返します。
なので、試して見ます。
>>> d = '''<html><body><table>
... <tr><td>aaa</td><td>001</td></tr>
... <tr><td>bbb</td><td>002</td></tr>
... </table></body></html>
... '''
>>>
>>> d
'<html><body><table>\n<tr><td>aaa</td><td>001</td></tr>\n<tr><td>bbb</td><td>002</td></tr>\n</table></body></html>\n'
>>> t = etree.fromstring(d)
>>> t
<Element 'html' at 0xf6d83690>
>>>
作成された Element インスタンスですが、
>>> print(tree[0].tag)
body
>>> print(tree[0][0].tag)
table
>>> for trTag in tree[0][0]:
... print(trTag.tag, trTag.text)
... for child in trTag:
... print(' ',child.tag, child.text)
...
tr None
td aaa
td 001
tr None
td bbb
td 002
>>>
のように、ツリー構造になっているそうです。
ちなみに、HTMLが間違っていると、mismatched tag というエラーが出るようです。
この例の Element インスタンス t は、for 文でこのプログラムのように iter('tr')を使えば、
tr タグで囲まれた2つの td タグの部分を2つの要素として取り出せるので、
>>> for i in t.iter('tr'):
... a, b = i
... print(a.tag, a.text, b.tag, b.text)
...
td aaa td 001
td bbb td 002
>>>
それぞれ、タグ名は .tag 、値は .text として参照できるようになるのですね。
次に set が出てきました。集合型ですね。
https://docs.python.org/ja/3/tutorial/datastructures.html#sets
Python には、 集合 (set) を扱うためのデータ型もあります。集合とは、重複する要素をもたない、順序づけられていない要素の集まりです。 Set オブジェクトは、和 (union)、積 (intersection)、差 (difference)、対称差 (symmetric difference)といった数学的な演算もサポートしています。
中括弧、または set() 関数は set を生成するために使用することができます。注: 空集合を作成するためには set() を使用しなければなりません ({} ではなく)。後者は空の辞書を作成します。辞書は次のセクションで議論するデータ構造です。
ということで、set()以外に中括弧も使えるのですね。リストと似てますが、「順序づけられない要素の集まり」が集合の要点?だと思います。しかも「重複する要素をもたない」のですね。
チュートリアルにあるデモを修正して 3.12.5 で試してみました。
>>> number = set(['one', 'two', 'three', 'four', 'five'])
>>> print(number)
{'five', 'three', 'four', 'two', 'one'}
>>> 'four' in number
True
>>> 'seven' in number
False
>>> number = {'one', 'two', 'one', 'three', 'seven', 'three'}
>>> print(number)
{'two', 'one', 'three', 'seven'}
>>> 'four' in number
False
>>> 'seven' in number
True
>>>
ちゃんと、重複要素は除去されていますね。この例から 集合 number に対して、
a in number が、
True なら a は集合number の要素であり、
False なら a は集合number の要素ではない
となるようですね。更に、
a not in number も可能で、上の最後の例から、
>>> 'seven' not in number
False
>>>
となりました。
プログラムは、
tree = etree.fromstring()で、Elementインスタンス tree を得て、
集合 pantry を定義して、
for文で、tree.iter('tr') から1つずつ tr の中身を ingredient に代入して、
ingredientから3つの要素(タグがth または td)を、amt, unit, item に代入して、
if文で 要素item のタグ item.tag が td でかつ、 そのタグで囲まれたコンテンツ item.text が 集合 pantry に属さなければ、
要素 item: amt unit として出力する
ですね。
今回は、XML/HTML データを扱うプログラムでしたが、
これらのタイプデータを取り扱うときは Python を使おう!ということも、入門者に伝わってくる?ものでした。
特に、fromstring()で生成される、木構造のElementインスタンスが有益そうに思いました。
使うためには、様々なこのタイプのデータがどのような構造になるのかを自分で調べることになるので、
プログラミングで意外と重要な、実際にプログラミングする前に使おうとする機能を色々「試して」確認しておく、
ということが実感できるかもしれませんね。
また、Python も色々なモジュールが公開されているので、これらを活用してプログラムするというのが SimpleProgram の考え方かもしれませんね。
https://wiki.python.org/moin/SimplePrograms
の 19番目のプログラムは、 21行の XML,HTML パーサです。
(このブログではうまく表示できないので、XML/HTMLデータは大文字のカギ括弧を使っています。)
dinner_recipe = '''<html><body><table>
<tr><th>amt</th><th>unit</th><th>item</th></tr>
<tr><td>24</td><td>slices</td><td>baguette</td></tr>
<tr><td>2+</td><td>tbsp</td><td>olive oil</td></tr>
<tr><td>1</td><td>cup</td><td>tomatoes</td></tr>
<tr><td>1</td><td>jar</td><td>pesto</td></tr>
</table></body></html>'''
# From http://effbot.org/zone/element-index.htm
import xml.etree.ElementTree as etree
tree = etree.fromstring(dinner_recipe)
# For invalid HTML use http://effbot.org/zone/element-soup.htm
# import ElementSoup, StringIO
# tree = ElementSoup.parse(StringIO.StringIO(dinner_recipe))
pantry = set(['olive oil', 'pesto'])
for ingredient in tree.getiterator('tr'):
amt, unit, item = ingredient
if item.tag == "td" and item.text not in pantry:
print ("%s: %s %s" % (item.text, amt.text, unit.text))
これを、prog-21.py というファイルにして実行してみます。
$ python3 prog-21.py
e "/home/espiya/test/python/samples/prog-21.py", line 18, in <module>
for ingredient in tree.getiterator('tr'):
^^^^^^^^^^^^^^^^
AttributeError: 'xml.etree.ElementTree.Element' object has no attribute 'getiterator'
$ (空白がずれていると思うので ^^ は tree.getiterator を表しています。)
SimpoePrograms 初めての実行できない事例ですね。ちなみに、コメントのURLももはや存在しません。
原因は、getiterator() ですね。
https://docs.python.org/ja/3.6/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.getiterator
バージョン 3.2 で非推奨: 代わりに Element.iter() メソッドを使用してください。
なので、
iter(tag=None)
現在の要素を根とする木の イテレータを作成します。
イテレータは現在の要素とそれ以下のすべての要素を、文書内での出現順 (深さ優先順) でイテレートします。 tag が None または '*' でない場合、与えられたタグに等しいものについてのみイテレータから返されます。イテレート中に木構造が変更された場合の結果は未定義です。
ということで、 tree.iter('tr') で tree の中で、タグが tr のものを抽出できます。指示に従って、
for ingredient in tree.iter('tr'):
と変更して prog-21-01.py を作成して、2つのファイルの違いを表示した後に、実行してみます。
$ diff prog-21.py prog-21-01.py
18c18
< for ingredient in tree.getiterator('tr'):
---
> for ingredient in tree.iter('tr'):
$
$ python3 prog-21-01.py
baguette: 24 slices
tomatoes: 1 cup
$
これは、HTML 形式のデータ dinner_recipe を取り扱うプログラムですね。
つまり、開始タグ + コンテンツ + 終了タグ からなる要素(element)の集まりで、コンテンツに別の要素を含んでいること(入れ子)を許すようなデータの扱いです。
プログラムを見ていきましょう。
import 文から、使用するモジュールは xml.etree.ElementTree で、それを etree としています。
tree = etree.fromstring(dinner_recipe) は、
文字列定数で与えられた XML 断片を解析します。 XML() と同じです。 text には XML データを含む文字列を指定します。 parser はオプションで、パーザのインスタンスを指定します。指定されなかった場合、標準の XMLParser パーザを使用します。 Element インスタンスを返します。
なので、試して見ます。
>>> d = '''<html><body><table>
... <tr><td>aaa</td><td>001</td></tr>
... <tr><td>bbb</td><td>002</td></tr>
... </table></body></html>
... '''
>>>
>>> d
'<html><body><table>\n<tr><td>aaa</td><td>001</td></tr>\n<tr><td>bbb</td><td>002</td></tr>\n</table></body></html>\n'
>>> t = etree.fromstring(d)
>>> t
<Element 'html' at 0xf6d83690>
>>>
作成された Element インスタンスですが、
>>> print(tree[0].tag)
body
>>> print(tree[0][0].tag)
table
>>> for trTag in tree[0][0]:
... print(trTag.tag, trTag.text)
... for child in trTag:
... print(' ',child.tag, child.text)
...
tr None
td aaa
td 001
tr None
td bbb
td 002
>>>
のように、ツリー構造になっているそうです。
ちなみに、HTMLが間違っていると、mismatched tag というエラーが出るようです。
この例の Element インスタンス t は、for 文でこのプログラムのように iter('tr')を使えば、
tr タグで囲まれた2つの td タグの部分を2つの要素として取り出せるので、
>>> for i in t.iter('tr'):
... a, b = i
... print(a.tag, a.text, b.tag, b.text)
...
td aaa td 001
td bbb td 002
>>>
それぞれ、タグ名は .tag 、値は .text として参照できるようになるのですね。
次に set が出てきました。集合型ですね。
https://docs.python.org/ja/3/tutorial/datastructures.html#sets
Python には、 集合 (set) を扱うためのデータ型もあります。集合とは、重複する要素をもたない、順序づけられていない要素の集まりです。 Set オブジェクトは、和 (union)、積 (intersection)、差 (difference)、対称差 (symmetric difference)といった数学的な演算もサポートしています。
中括弧、または set() 関数は set を生成するために使用することができます。注: 空集合を作成するためには set() を使用しなければなりません ({} ではなく)。後者は空の辞書を作成します。辞書は次のセクションで議論するデータ構造です。
ということで、set()以外に中括弧も使えるのですね。リストと似てますが、「順序づけられない要素の集まり」が集合の要点?だと思います。しかも「重複する要素をもたない」のですね。
チュートリアルにあるデモを修正して 3.12.5 で試してみました。
>>> number = set(['one', 'two', 'three', 'four', 'five'])
>>> print(number)
{'five', 'three', 'four', 'two', 'one'}
>>> 'four' in number
True
>>> 'seven' in number
False
>>> number = {'one', 'two', 'one', 'three', 'seven', 'three'}
>>> print(number)
{'two', 'one', 'three', 'seven'}
>>> 'four' in number
False
>>> 'seven' in number
True
>>>
ちゃんと、重複要素は除去されていますね。この例から 集合 number に対して、
a in number が、
True なら a は集合number の要素であり、
False なら a は集合number の要素ではない
となるようですね。更に、
a not in number も可能で、上の最後の例から、
>>> 'seven' not in number
False
>>>
となりました。
プログラムは、
tree = etree.fromstring()で、Elementインスタンス tree を得て、
集合 pantry を定義して、
for文で、tree.iter('tr') から1つずつ tr の中身を ingredient に代入して、
ingredientから3つの要素(タグがth または td)を、amt, unit, item に代入して、
if文で 要素item のタグ item.tag が td でかつ、 そのタグで囲まれたコンテンツ item.text が 集合 pantry に属さなければ、
要素 item: amt unit として出力する
ですね。
今回は、XML/HTML データを扱うプログラムでしたが、
これらのタイプデータを取り扱うときは Python を使おう!ということも、入門者に伝わってくる?ものでした。
特に、fromstring()で生成される、木構造のElementインスタンスが有益そうに思いました。
使うためには、様々なこのタイプのデータがどのような構造になるのかを自分で調べることになるので、
プログラミングで意外と重要な、実際にプログラミングする前に使おうとする機能を色々「試して」確認しておく、
ということが実感できるかもしれませんね。
また、Python も色々なモジュールが公開されているので、これらを活用してプログラムするというのが SimpleProgram の考え方かもしれませんね。