2017-02-23 90 views
0

私はPython lxml(Python 2)でXPathを使用しています。データの2つのパスを実行します.1つは関心のあるレコードを選択し、もう1つはデータから値を抽出します。ここにコードの種類のサンプルがあります。Python/lxmlとXPathで属性名と値を取得する

['1', '160', '80'] 
['2', '70'] 
['3', '140'] 

あなたは、属性が欠落している結果から、他の属性の変更の位置を見ることができますので、私は言うことができないとして:私はこのスクリプトを実行すると出力され

from lxml import etree 

xml = """ 
    <records> 
    <row id="1" height="160" weight="80" /> 
    <row id="2" weight="70" /> 
    <row id="3" height="140" /> 
    </records> 
""" 

parsed = etree.fromstring(xml) 
nodes = parsed.xpath('/records/row') 
for node in nodes: 
    print node.xpath("@id|@height|@weight") 

これが身長か体重かどうか2列目と3行目。

etree/lxmlから返される属性の名前を取得する方法はありますか?理想的には、私は形式で結果を見てする必要があります。

[('@id', '1'), ('@height', '160'), ('@weight', '80')] 

私はElementTreeのとPythonを使用して、この特定のケースを解決できると認識しています。しかし、私はPythonを使用してデータを処理するのではなく、XPath(および比較的単純なXPath)を使用してこれを解決したいと考えています。

答えて

0

私はPythonを使用しないという私の主張が間違っていました。私は、lxml/etreeの実装が容易に拡張され、XPath DSLを変更で使用できることがわかりました。

私は関数 "dictify"を登録しました。

dictify('@id|@height|@weight|weight|height') 

新しいコードは次のとおりです:

from lxml import etree 

xml = """ 
<records> 
    <row id="1" height="160" weight="80" /> 
    <row id="2" weight="70" ><height>150</height></row> 
    <row id="3" height="140" /> 
</records> 
""" 

def dictify(context, names): 
    node = context.context_node 
    rv = [] 
    rv.append('__dictify_start_marker__') 
    names = names.split('|') 
    for n in names: 
     if n.startswith('@'): 
      val = node.attrib.get(n[1:]) 
      if val != None: 
       rv.append(n) 
       rv.append(val) 
     else: 
      children = node.findall(n) 
      for child_node in children: 
       rv.append(n) 
       rv.append(child_node.text) 
    rv.append('__dictify_end_marker__') 
    return rv 

etree_functions = etree.FunctionNamespace(None) 
etree_functions['dictify'] = dictify 


parsed = etree.fromstring(xml) 
nodes = parsed.xpath('/records/row') 
for node in nodes: 
    print node.xpath("dictify('@id|@height|@weight|weight|height')") 

これは次の出力を生成します。私はにXPath式を変更し

['__dictify_start_marker__', '@id', '1', '@height', '160', '@weight', '80', '__dictify_end_marker__'] 
['__dictify_start_marker__', '@id', '2', '@weight', '70', 'height', '150', '__dictify_end_marker__'] 
['__dictify_start_marker__', '@id', '3', '@height', '140', '__dictify_end_marker__'] 
1

次の試してみてください:

list_of_attributes = [] 
for node in nodes: 
    attrs = [] 
    for att in node.attrib: 
     attrs.append(("@" + att, node.attrib[att])) 
    list_of_attributes.append(attrs) 

出力:

あなたが [('@id', '1'), ('@height', '160'), ('@weight', '80')]のようなものを取得したい場合はこれが {'id': '1', 'weight': '80', 'height': '160'}

ように、ノードのすべての属性の辞書を返します

for node in nodes: 
    print node.attrib 

[[('@id', '1'), ('@height', '160'), ('@weight', '80')], [('@id', '2'), ('@weight', '70')], [('@id', '3'), ('@height', '140')]] 
+0

はい、動作しますが、それはPythonのです。 XPathを使用してデータを抽出したい。 XPathを使用すると、ユーザーがアクセスパスを定義できるようになります。 Pythonで実装するには、ある形式のXPath DSLを書く必要があります。これは、XPathがこの領域のDSLであることを考えると意味がありません。 –

+0

これは '/ records/row/@ */concat(name()、"、 "、。)のトリックですか? – Andersson

+0

残念ながら。これによりエラーが発生します。 prints parsed.xpath( '/ records/row/@ */concat(name()、 "、")) lxml.etree.XPathEvalError:無効な式 –

関連する問題