回答編集履歴

2

追記

2023/02/08 05:14

投稿

can110
can110

スコア38233

test CHANGED
@@ -63,4 +63,4 @@
63
63
  (3.0, [(4,), (5,), (6,)])
64
64
  """
65
65
  ```
66
-
66
+ あるいは、そもそもジェネレータにせずとも、たんに`end`時に`clear`するだけでもよいかもしれません。

1

追記

2023/02/08 05:10

投稿

can110
can110

スコア38233

test CHANGED
@@ -1,2 +1,66 @@
1
1
  実際に試していませんので参考程度の回答ですが[Python running out of memory parsing XML using cElementTree.iterparse](https://stackoverflow.com/a/13261805)の回答にあるようにジェネレータにして`end`時に`clear`するとメモリ節約できるようです。
2
2
 
3
+ ## 追記
4
+
5
+ 大量データでは試していませんが、問題なく処理できているようです。
6
+ なお、提示コードにおいて、XMLに開始時間よりも前の時間のデータが含まれている場合、最初の時間のデータにそれらが含まれるような動作になっているようです。
7
+ ちょっと違和感ありますが、以下テストコードでもそのままの動作にしています。
8
+ ```Python
9
+ from xml.etree.ElementTree import iterparse
10
+ from io import StringIO
11
+
12
+ # テストデータ
13
+ s = """<dummy>
14
+ <timestep time="1">
15
+ <vehicle id="1"/>
16
+ </timestep>
17
+ <timestep time="2">
18
+ <vehicle id="2"/>
19
+ <vehicle id="3"/>
20
+ </timestep>
21
+ <timestep time="3">
22
+ <vehicle id="4"/>
23
+ <vehicle id="5"/>
24
+ <vehicle id="6"/>
25
+ </timestep>
26
+ <timestep time="4">
27
+ <vehicle id="9"/>
28
+ </timestep>
29
+ </dummy>"""
30
+
31
+
32
+ time_s=1 # これよりも大きい時間
33
+ time_e=3 # 終了時間
34
+
35
+ def get_element(xml):
36
+ data_list=[]
37
+ doc = iterparse(xml, events=('start', 'end'))
38
+ event, root = next(doc)
39
+
40
+ for event, elem in doc:
41
+ if event == 'start':
42
+ if elem.tag == 'timestep': #時間を抽出
43
+ # 時間tを読み込み
44
+ t = float(elem.attrib['time'])
45
+ elif elem.tag == 'vehicle' : # 車両の情報を抽出
46
+ id = int(str(elem.attrib['id']))
47
+ data_list.append((id,)) # 時間に関係なく蓄積しているけどまあいいか
48
+ elif event == 'end':
49
+ if elem.tag == 'timestep'and t > time_s:
50
+ yield t, data_list
51
+ data_list=[]
52
+ root.clear()
53
+
54
+ if t == time_e+1: # 完全一致だけどまあいいか
55
+ break
56
+
57
+ # ファイル出力などの処理は呼出元でおこなう
58
+ elems = get_element(StringIO(s))
59
+ for e in elems:
60
+ print(e)
61
+ """
62
+ (2.0, [(1,), (2,), (3,)])
63
+ (3.0, [(4,), (5,), (6,)])
64
+ """
65
+ ```
66
+