xpathで要素数が可変のデータを抽出する方法
先月、質問をさせていただいた者です。質問は「xpathでデータが未定義の箇所がある場合、どのように例外処理をすれば良いか」で、これに続く内容です。
使っている元データは科研費のDBで https://kaken.nii.ac.jp/ からアクセスしてXMLデータとしてダウンロードできます。ダウンロードしたXMLから必要なデータだけを抽出して、CSVファイルを作っています。
当初の目的は達成し、うまく動くようになったのですが、機能を拡張していく中で、別のことも必要になってきました。
例えば https://kaken.nii.ac.jp/search/?kw=KAKENHI-PROJECT-18K09063 から、画面上の方にある[XMLで出力]の隣の実行ボタンを押してXMLデータをダウンロードすると、
<grantAward>
<summary xml:lang="ja">
<member sequence="1" eradCode="60196904" role="principal_investigator">~
<member sequence="2" eradCode="10508526" role="co_investigator_buntan">~
<member sequence="3" eradCode="20378285" role="co_investigator_buntan">~
のように、sequenceが1, 2, 3~順に並ぶ、メンバーリストがある構造になっています。ここで、前回の処理と並行して各summaryに、
・sequenceが何番まであるのか探索して数値を出力する
・sequence=1~n内の情報(ここではeradCode)を連続出力(TAB区切り)する
ことが出来ないか考えています。sequenceの数は定められておらず、可変です。(大半のデータは1ですが、大きいものだと50超のものもあります)
今試しているコードは下記のような状態です(本当はもっと長いですが、短縮してあります)。
from lxml import etree # lxmlライブラリを使用
tree = etree.parse('ファイル名')
root = tree.getroot()
awards = tree.xpath('/grantAwards/grantAward')
LstGrantid = list()
LstErad = list()
LstMembers = list()
if len(awards):
for m in awards:
# 科研費ID
grantid = m.xpath('@id')
eradname = m.xpath('summary[@xml:lang="ja"]/member[@sequence="1"]/@eradCode')
# 取得した要素をリスト変数へ代入
if len(grantid): # 科研費ID
LstGrantid.append(grantid[0])
else:
LstGrantid.append("")
if len(eradname): # 1st名前(Erad)
LstErad.append(eradname[0])
else:
LstErad.append("")
# 共同研究者リストを作る ★うまくいっていない
memberlst = tree.xpath('/grantAwards/grantAward/summary[@xml:lang="ja"]/member')
if len(memberlst):
for n in memberlst:
membersu = n.xpath('member[@sequence=n]/@eradCode') # メンバー(Erad)
if len(membersu):
LstMembers.append(membersu[0])
else:
LstMembers.append("")
print(len(LstMembers), end='\t') # 共同人数
# 結果をTAB区切りで標準出力
for j in range(len(LstGrantid)):
print(str(LstGrantid[j]), end='\t') # 科研費ID
print(str(LstErad[j]), end='\t') # 1st名前(Erad)
# print(len(LstMembers), end='\t') # ★うまくいっていない
print()
結果はTAB区切りあるいはカンマ区切りで、人数(11)の後、Eradを羅列するもの:
KAKENHI-PROJECT-18K09063 60196904 11 10508526 20378285 20422826 20727664 40308664 40444442 50362687 50467362 60647121 80763739
人数(11)の後、Eradと名前を羅列するもの:
KAKENHI-PROJECT-18K09063 60196904 11 10508526 西村 明展 20378285 淺沼 邦洋 20422826 明田 浩司 20727664 竹上 徳彦 40308664 長谷川 正裕 40444442 辻井 雅也 50362687 若林 弘樹 50467362 中村 知樹 60647121 内藤 陽平 80763739 刀根 慎恵
を考えています。よろしくお願いいたします。
(質問の追記1)
データが1件ならば動くのですが、複数件あるとエラーが出てしまう
kaken.nii.ac.jp/search/?o1=1&s1=2018&s2=2018&s3=1 から、画面にある[XMLで出力]隣の実行ボタンを押してXMLデータをダウンロードしたものは
File "test.py", line 33, in membersu = n.xpath('@eradCode')[0] IndexError: list index out of range
になってしまう。
※eradCodeを持っていない研究者の方がいるため
(質問の追記2)
新し目のデータにも未登録になるケースがある。
(1)名前だけ羅列するモード(Eradの有無は考慮しない)
(2)Eradだけ羅列するモード(Erad未登録のものはスキップする)
(3)Eradと名前を合わせて羅列し、Erad未登録者についてはEradの部分をnullにして、名前だけ出す
といったアプローチが考えられる。また、の方にしか personalName/fullName がないケースがあるようだ。
※名前がなけれは出力なし、として対応した