web-dev-qa-db-ja.com

ElementTreeの例を使用したPythonでのXMLの解析

Element Treeを使用してpythonでXMLを解析する方法の基本的な例を見つけるのに苦労しています。見つけることができるものから、これは解析に使用する最も簡単なライブラリのようですXML:私が使用しているXMLのサンプルは次のとおりです。

<timeSeriesResponse>
    <queryInfo>
        <locationParam>01474500</locationParam>
        <variableParam>99988</variableParam>
        <timeParam>
            <beginDateTime>2009-09-24T15:15:55.271</beginDateTime>
            <endDateTime>2009-11-23T15:15:55.271</endDateTime>
        </timeParam>
     </queryInfo>
     <timeSeries name="NWIS Time Series Instantaneous Values">
         <values count="2876">
            <value dateTime="2009-09-24T15:30:00.000-04:00" qualifiers="P">550</value>
            <value dateTime="2009-09-24T16:00:00.000-04:00" qualifiers="P">419</value>
            <value dateTime="2009-09-24T16:30:00.000-04:00" qualifiers="P">370</value>
            .....
         </values>
     </timeSeries>
</timeSeriesResponse>

ハードコーディングされた方法を使用して、必要なことを実行できます。しかし、コードをもう少し動的にする必要があります。これがうまくいったものです:

tree = ET.parse(sample.xml)
doc = tree.getroot()

timeseries =  doc[1]
values = timeseries[2]

print child.attrib['dateTime'], child.text
#prints 2009-09-24T15:30:00.000-04:00, 550

ここに私が試したことがいくつかありますが、どれも機能せず、timeSeries(または私が試した他の何か)が見つからなかったと報告しています:

tree = ET.parse(sample.xml)
tree.find('timeSeries')

tree = ET.parse(sample.xml)
doc = tree.getroot()
doc.find('timeSeries')

基本的に、xmlファイルをロードし、timeSeriesタグを検索し、値タグを反復処理して、dateTimeとタグ自体の値を返します。上記の例で行っていることはすべて行いますが、興味のあるxmlのセクションをハードコーディングすることはできません。


すべての助けてくれてありがとう。以下の両方の提案を使用すると、提供したサンプルファイルで機能しましたが、完全なファイルでは機能しませんでした。エド・キャレルの方法を使用すると、実際のファイルから得られるエラーは次のとおりです。

 (<type 'exceptions.AttributeError'>, AttributeError("'NoneType' object has no attribute 'attrib'",), <traceback object at 0x011EFB70>)

実際のファイルには、気に入らないものがあると考えたため、機能するまで徐々に削除しました。変更した行は次のとおりです。

originally: <timeSeriesResponse xsi:schemaLocation="a URL I removed" xmlns="a URL I removed" xmlns:xsi="a URL I removed">
 changed to: <timeSeriesResponse>

 originally:  <sourceInfo xsi:type="SiteInfoType">
 changed to: <sourceInfo>

 originally: <geogLocation xsi:type="LatLonPointType" srs="EPSG:4326">
 changed to: <geogLocation>

「xsi:...」を持つ属性を削除すると、問題が修正されました。 「xsi:...」は有効なXMLではありませんか?これらをプログラムで削除するのは難しいでしょう。推奨される回避策はありますか?

完全なXMLファイルを以下に示します。 http://www.sendspace.com/file/lofcpt


最初にこの質問をしたとき、私はXMLの名前空間を知りませんでした。何が起こっているかがわかったので、名前空間宣言である「xsi」属性を削除する必要はありません。 xpath検索にそれらを含めるだけです。 lxmlの名前空間の詳細については、 このページ を参照してください。

62
Casey

だから私は今私のボックスにElementTree 1.2.6を持っているので、投稿したXMLチャンクに対して次のコードを実行しました。

import elementtree.ElementTree as ET

tree = ET.parse("test.xml")
doc = tree.getroot()
thingy = doc.find('timeSeries')

print thingy.attrib

そして、以下を取り戻しました:

{'name': 'NWIS Time Series Instantaneous Values'}

数値インデックスを使用せずにtimeSeries要素を見つけたようです。

今、役に立つのは、「機能しない」と言うときの意味を知ることです。同じ入力が与えられれば機能するので、ElementTreeが何らかの明らかな方法で壊れることはまずありません。エラーメッセージ、バックトレース、またはサポートに役立つ情報を入力して質問を更新してください。

46
Ed Carrel

あなたの質問を正しく理解できたら:

_for elem in doc.findall('timeSeries/values/value'):
    print elem.get('dateTime'), elem.text
_

または、必要な場合(および_timeSeries/values_が1つしか存在しない場合):

_values = doc.find('timeSeries/values')
for value in values:
    print value.get('dateTime'), elem.text
_

findall()メソッドは一致するすべての要素のリストを返しますが、find()メソッドは最初に一致した要素のみを返します。最初の例は見つかったすべての要素をループし、2番目の例はvalues要素の子要素をループします。この場合、同じ結果になります。

ただし、timeSeriesが見つからないという問題の原因はわかりません。たぶん、あなたはgetroot()呼び出しを忘れただけでしょうか? (たとえば、パス式を_/timeSeriesResponse/timeSeries/values_または_//timeSeries/values_に変更すると、要素ツリー自体からも作業できるため、実際には必要ないことに注意してください)

21
Steven