2017-08-02 16 views
1

こんにちは私のXMLファイルをpandasデータフレームに変換できます。しかし、私が持っている挑戦は、私は適切な行にレコードを取得していない、我々は例えば繰り返しているXMLでタグのセットを持っていると言うことができます。 4回、それは私のデータフレームの列でなければならない複数の子ノードを持っています、今私はxmlを読もうとしています私は私のパンダのデータフレームでわずか4行を取得したいが、別のレベルにある。PythonのXML解析Pandasは1行に完全なタグブロックを取得します

編集:ちょうど今、XMLデータの記述/相違点を見つけました。言及されたものは最終的に編集されたXMLデータです 私のXMLデータでいくつかの問題を見つけてください...正確で最終的なXMLコンテンツを更新しました。私は以下の回答でパフェによって提案された今の機能として使用しています

 <ns1:parenttag> 
      <ns1:indenticaltag>123</ns1:indenticaltag> 
      <ns1:childtag2>N</ns1:childtag2> 
      <ns1:childtag3>0</ns1:childtag3> 
      <ns1:childtag4>N</ns1:childtag4> 
      <ns1:childtag5> 
       <ns2:subchildtag1 attributename0="poi"> 
        <ns2:sub_subchildtag1> 
         <ns2:sub_sub_subchildtag1> 
          <ns2:sub_sub_sub_subchildtag1 attributename1="3" attributename2="17">1234</ns2:sub_sub_sub_subchildtag1> 
         </ns2:sub_sub_subchildtag1> 
        </ns2:sub_subchildtag1> 
       </ns2:subchildtag1> 
      </ns1:childtag5> 
      <ns1:childtag6>12</ns1:childtag6> 
      <ns1:childtag7> qwer</ns1:childtag7> 
      <ns1:childtag8> 
       <ns3:subchildtag2>456</ns3:subchildtag2> 
      </ns1:childtag8> 
      <ns1:childtag9>N</ns1:childtag9> 
      <ns1:childtag10> 
       <ns3:subchildtag3>908</ns3:subchildtag3> 
       <ns3:subchildtag4>abc/123</ns3:subchildtag4> 
      </ns1:childtag10> 
     </ns1:parenttag>   

: が、このエラーを取得:

i am getting ValueError: Length mismatch: Expected axis has 21 elements, new values have 22 elements erros 

    Also it has issue with indenticaltag column as its of same name thrice but hierarchy is different 
    but in dataframe i am getting only one indenticaltag column instead of 3 for example: 
    parent.child.indenticaltag, parent.child.subchild.indenticaltag and parent.child.subchild.sub_subchild.indenticaltag etc. 

Same <ns1:parenttag> is getting repeated over a xml file multiple times 

    <?xml version="1.0" encoding="UTF-8"?> 
    <row:user-agents xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:row="http://www.row.com" 
    xmlns:ns1="http://www.ns1.com" 
    xmlns:ns2="http://www.ns2.com" 
    xmlns:ns3="http://www.ns3.com" 
    xmlns:row1="http://www.row1.com" 
    xmlns:row3="http://www.row3.com" 
    xmlns:row2="http://www.row2.com" 
    xsi:schemaLocation="http://www.schemaLocation-1.4.xsd"> 

<row:agent1> 
<row:test> 
    <row2:test1> 
    <row2:test2> 
     <row2:test3>9999</row2:test3> 
     <row2:test4>aa</row2:test4> 
     <row2:test5>1</row2:test5> 
    </row2:test2> 
    </row2:test1> 
    <row2:test6>2017</row2:test6> 
</row:test> 
<row:agent2> 
<row3:agent3> 

     <ns1:parenttag> 
      <ns1:childtag1> 
       <ns1:subchildtag1> 
        <ns1:indenticaltag>123</ns1:indenticaltag> 
       </ns1:subchildtag1> 
      </ns1:childtag1> 
      <ns1:indenticaltag>456</ns1:indenticaltag> 
      <ns1:childtag2>N</ns1:childtag2> 
      <ns1:childtag3>0</ns1:childtag3> 
      <ns1:childtag4>N</ns1:childtag4> 
      <ns1:childtag5> 
       <ns2:subchildtag2 attributname="abc"> 
        <ns2:sub_subchildtag1>12 45</ns2:sub_subchildtag1> 
       </ns2:subchildtag2> 
      </ns1:childtag5> 
      <ns1:childtag6>tyu</ns1:childtag6> 
      <ns1:childtag7>2</ns1:childtag7> 
      <ns1:childtag8> poiu</ns1:childtag8> 
      <ns1:childtag9> 
       <ns3:subchildtag3>345</ns3:subchildtag3> 
       <ns3:subchildtag6>567</ns3:subchildtag6> 

      </ns1:childtag9> 
      <ns1:childtag10>N</ns1:childtag10> 
      <ns1:childtag11> 
       <ns3:subchildtag4>34</ns3:subchildtag4> 
       <ns3:subchildtag5>abc/123</ns3:subchildtag5> 
      </ns1:childtag11> 
      <ns1:childtag12> 
       <ns1:indenticaltag>234</ns1:indenticaltag> 
      </ns1:childtag12> 
     </ns1:parenttag> 

</row3:agent3> 
</row:agent2> 
</row:agent1> 
</row:user-agents> 

親タグの項で少し異なっている別のXMLに

出力データフレーム:

I will parse both xmls differently using one function only. 
    Would like to parse all the tags and their attribute as column name in 
    pandas. Also the column name should be 
    parent.child.subchild.sub_sub_subchildtag and for attributes it should 
    be parent.child.subchild.sub_sub_childtag.attribute 

xmlを解析して適切な形式でレコードを取得するより良い方法はありますか?または私は何かが不足していますか?

編集:解決策はいくつかのより多くの複雑さを働いていたが、追加

I need your help for three points if you guys can suggest some pointers: 

    1) I need columns name for pandas dataframe as root.child.subchild.grandchild i am not sure how i can get it here ? as in my solution i was able to get. 
    2) the descendant function is very slow is any way we can speed it up ? 
    3) i have to multiple xml of same type present in one directory and i would like to generate one dataframe out of it by appending all xml results any best way to do ? 

答えて

1

を考えてみましょうlxmlのxpath()<xs:topcol>ノードに、lxmlのparse()を使用してファイルから直接読み取ります。 XPathループは、データフレームにキャストするためのリストコンテナと辞書コンテナに繰り返し追加されます。また、ご希望の出力は、実際にノード値に整列されていません。

import pandas as pd 
from lxml import etree 
import re 

pd.set_option('display.width', 1000) 

NSMAP = {'row': 'http://www.row.com', 
     'row3': 'http://www.row3.com', 
     'row1': 'http://www.row1.com', 
     'xs': 'http://www.xs.com', 
     'row2': 'http://www.row2.com'} 

xmldata = etree.parse('RowAgent.xml')  

data = [] 
inner = {} 
for el in xmldata.xpath('//xs:top_col', namespaces=NSMAP): 
    for i in el:         # PARSE CHILDREN 
     inner[i.tag] = i.text 
     if len(i.xpath('/*')) > 0:    # PARSE GRANDCHILDREN 
      for subi in i: 
       inner[subi.tag] = subi.text 

    data.append(inner) 
    inner = {} 

df = pd.DataFrame(data) 

# REGEX TO REMOVE NAMESPACE URIs IN COL NAMES 
df.columns = [re.sub(r'{.*}', '', col) for col in df.columns] 

解析するには、無制限の子要素が使用するXPathのdescendant::*

num_top_cols = len(xmldata.xpath('//xs:top_col', namespaces=NSMAP)) 

for i in range(1,num_top_cols+1): 
    for el in xmldata.xpath('//xs:top_col[{}]/descendant::*'.format(i), namespaces=NSMAP): 
     if el.text.strip()!='':     # REMOVE EMPTY TEXT TAGS 
      inner[el.tag] = el.text.strip() 

    data.append(inner) 
    inner = {} 

df = pd.DataFrame(data) 

出力

print(df) 
# col11_1  col11_2 col8_1 col8_2  col1  col10 col12 col13_1 col2 col3 col4 col5 col6 col7 col9 
# 0  2010 AB 20/SEC001  2010 2016 00032000 test_name pqr 000330 N 0 3 N I AA N 
# 1 2016026 rty-qwe-01  2000 26000  03985  temp2 perrl 0117203 N 0 3 N a 9AA N 
# 2  8965 147A-254-044  7896 NaN  00985  mjkl rtyyu 45612 N 0 3 N NaN yuio N 
# 3 52369 ui 247/mh45 145ghg7 NaN  78965  ghyuio trwer  9874 N 0 5 N NaN 23rt N 

のためにdescendants::*のパフォーマンスの課題、再帰的な呼び出しが最初にすべてのdesceをトラバースすると考えてください次に、データフレーム列の親子/子孫/孫の名前を取得する別の呼び出し。今OrderedDict使用してください:

print(df) 
#  col1 col2 col3 col4 col5 col6 col7     col8 col8.col8_1 col8.col8_1.sName col8.col8_2 col9  col10     col11 col11.col11_1 col11.col11_2 col12     col13 col13.col13_1 
# 0 00032000 N 0 3 N I AA \n       2010    pqrst  2016 N test_name \n       2010 AB 20/SEC001 pqr \n       000330 
# 1  03985 N 0 3 N a 9AA \n       2000    NaN  26000 N  temp2 \n       2016026 rty-qwe-01 perrl \n       0117203 
# 2  00985 N 0 3 N NaN yuio \n       7896    NaN   NaN N  mjkl \n       8965 147A-254-044 rtyyu \n       45612 
# 3  78965 N 0 5 N NaN 23rt \n      145ghg7    NaN   NaN N  ghyuio \n       52369 ui 247/mh45 trwer \n       9874 

最後に

from collections import OrderedDict 

#... same as above XML setup ... # 

def recursiveParse(curr_elem, curr_inner):  
    if len(curr_elem.xpath('/*')) > 0:   
     for child_elem in curr_elem:    
      curr_inner[child_elem.tag] = child_elem.text 
      inner[i.tag] = i.text 
      if child_elem.attrib is not None:     
       for attrib in child_elem.attrib: 
        inner[attrib] = child_elem.attrib[attrib] 
      recursiveParse(child_elem, curr_inner) 

    return(curr_inner) 

for el in xmldata.xpath('//xs:top_col', namespaces=NSMAP): 
    for i in el:   
     inner[i.tag] = i.text 
     if i.attrib is not None: 
      for attrib in i.attrib: 
       inner[attrib] = i.attrib[attrib]     
     recursiveParse(i, inner) 

    data.append(inner) 
    inner = {} 

df = pd.DataFrame(data) 

colnames = [] 
def recursiveNames(curr_elem, curr_inner, num):  
    if len(curr_elem.xpath('/*')) > 0:   
     for child_elem in curr_elem:  
      tmp = re.sub(r'{.*}', '', child_elem.tag)    
      curr_inner.append(colnames[num-1] +'.'+ tmp) 
      if child_elem.attrib is not None:     
       for attrib in child_elem.attrib: 
        curr_inner.append(curr_inner[len(curr_inner)-1] +'.'+ attrib) 
      recursiveNames(child_elem, curr_inner, len(colnames)) 

    return(curr_inner)   

for el in xmldata.xpath('//xs:top_col[1]', namespaces=NSMAP): 
    for i in el:     
     tmp = re.sub(r'{.*}', '', i.tag) 
     colnames.append(tmp) 
     recursiveNames(i, colnames, len(colnames)) 

df.columns = colnames 

出力は、ループ内のすべてを解析し、この処理し、元のXMLを統合し、そのディレクトリ内のすべてのXMLファイルを反復処理します。ただし、すべてのデータフレームをデータフレームのリストに保存し、次にpd.concat() `を使用して/スタックを追加してください。

import # modules 

dfList = [] 
for f in os.list.dir('/path/to/XML/files'): 
    #...xml parse... (passing in f for file name in parse()) 
    #...dataframe build with recursive calls... 

    dfList.append(df) 

finaldf = pd.concat(dfList) 
+0

私よりもずっと優れています。私たちが壮大なグランド子供を階層内に持っているかどうかという疑問が1つあります。すべてのサブチャイルドをトラバースする標準的な方法はありますか? – user07

+0

良い質問は、ノードインデックスで各 ' 'をループし、すべての子孫を解析するXPathの' descendant :: * 'を使って更新された拡張を見てください。 – Parfait

+0

あなたのXMLはどれくらいの大きさですか? 1 GB以上?あなたはどれくらい遅いですか?また、属性とテキストは非常に異なっています。あなたのXMLの例には属性や解析の試みが含まれていません。 **実際の**データの真の例を常に投稿してください。 – Parfait

0

こんにちは、私はそれが他の人のために役立つことができるので、それを投稿、上記の問題に対する答えを見つけた:

xml_data = open('test.xml').read().encode('utf8') 

    def xml2df(xml_data): 
     tree = et.parse(xml_data) 
     all_records= [] 
     result= {} 
     for el in tree.iterfind("./row:agent1/row:agent2/row3:agent3/xs:top_col/",namespaces): 

      for r in el: 

       if '}' in r.tag: 
        r.tag = r.tag.split('}', 1)[1] 
      for i in el.iterfind('*'): 

       for s in i: 

        s.tag = s.tag.split('}',1)[1] 
        s.tag = i.tag +"."+s.tag    

       result[i.tag] = i.text 

       for j in i.iterfind('*'): 
        result[j.tag] = j.text 

      all_records.append(result) 

      result= {} 

     df = pd.DataFrame(data) 
     return df 
    df1 = xml2df(xml_data) 
    df1 
関連する問題