助けていただければ幸いです。私は 2 日以上忙しく、この xml ファイルにアクセスしてその内容を df に入れることができない理由を理解するためにサーフィンをしています。私の目標は、ワークシートを pandas データフレームの xml ファイルに入れることです。このトピックに対処する投稿がいくつかあることは知っていますが、複雑にするいくつかのエラーに直面しているようです。
データは、有名な ETF プロバイダーからダウンロードしたものです。「.xls」としてダウンロードされますが、実際には「xml」形式です。明らかにExcel xlmです。したがって、簡単な pd.read_excel は機能しません。そこで、LXML や xml.etree.ElementTree などの xml 形式やライブラリーに取り掛かることを余儀なくされました。私はBS4でしばらく働いてきました。
xml ダウンロードではエンコーディングが指定されておらず、解析しようとするとエラーが返されます。だから私はchardetとet.XMLParserをいじって、それがエンコーディングであることを発見し、パーサーに「ハードセット」させました。しかし、役に立たない。解析すると次のように返されます。
「lxml.etree.XMLSyntaxError: ドキュメントが空です、行 1、列 1」
それを直接解析する代わりに (以下の xml_tree1 を参照)、fromstring を使用して xml を読み取ろうとしたところ、意味不明なことに気付きました。だから私はそれを何も置き換えませんでした:
xml_str = xml_file.read().replace('', '')
今、私はきれいな xml コードを持っていますが、まだルートに子を見つけることができません。実際、それは空で、まったく解析されていないようです。私の知識は私を失望させています。誰かが私を正しい方向に押してくれませんか? 私の問題は初期段階にあります。ファイルとその基になる形式を解析できないようです。2 つ目の問題は、ドキュメント内のそれぞれのワークシートで ss:table を解析する必要があることです。コードのもう少し先に、作業用にいくつかの例を書き留めました。どんなコメントでも大歓迎です。
これらは私を最も助けた投稿です。
ElementTree で XML を解析するときに子ノードのテキスト値を取得するにはどうすればよいですか
ElementTree で .xml のようなスプレッドシートを読み取る
xml のソースはここにあります (オランダ語版)。右上隅からダウンロードできます。
XML のスニペット:
<?xml version="1.0"?>
<ss:Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
<ss:Styles>
<ss:Style ss:ID="Default">
<ss:Alignment ss:Horizontal="Left"/>
</ss:Style>
<ss:Style ss:ID="wraptext">
<ss:Alignment ss:Horizontal="Left" ss:WrapText="1"/>
<ss:Font ss:Italic="1"/>
</ss:Style>
<ss:Style ss:ID="disclaimer">
<ss:Alignment ss:Vertical="Top" ss:WrapText="1"/>
</ss:Style>
<ss:Style ss:ID="DefaultHyperlink">
<ss:Alignment ss:Vertical="Center" ss:WrapText="1"/>
<ss:Font ss:Color="#0000FF" ss:Underline="Single" />
</ss:Style>
<ss:Style ss:ID="headerstyle">
<ss:Font ss:Bold="1" />
</ss:Style>
<ss:Style ss:ID="Date">
<ss:NumberFormat ss:Format="dd\-mmm\-yyyy"/>
</ss:Style>
<ss:Style ss:ID="Left">
<ss:Alignment ss:Horizontal="Left"/>
<ss:NumberFormat ss:Format="Standard"/>
</ss:Style>
<ss:Style ss:ID="Right">
<ss:Alignment ss:Horizontal="Right"/>
<ss:NumberFormat ss:Format="Standard"/>
</ss:Style>
</ss:Styles>
<ss:Worksheet ss:Name="Overzicht">
<ss:Table>
<ss:Row >
<ss:Cell ss:StyleID="headerstyle">
<ss:Data ss:Type="String">iShares Core MSCI World UCITS ETF</ss:Data>
</ss:Cell>
</ss:Row>''
これまでの私のコード:
import lxml.etree as et
from lxml import objectify
import io
import chardet
with open('C:\\MSCI.xml') as xml_file:
parser = et.XMLParser(encoding="iso-8859-5", recover=True)
xml_str = xml_file.read().replace('', '') # !!! IShares xml has error in first row !!!
xml_tree = et.ElementTree(et.fromstring(xml_str, parser=parser))
root = xml_tree.getroot()
xml_tree0 = et.iterparse(xml_file, encoding='iso-8859-1') # Nothing
xml_tree1 = et.parse(xml_file, parser=parser) # File seems empty, but is not
xml_tree2 = objectify.parse(io.StringIO(xml_str)) # This is the same as fromstring
#################################################
### Trying to capture encoding and replace it ###
#################################################
detector = chardet.UniversalDetector()
for line in xml_file.readlines():
detector.feed(line) # This doesn't seem to work
if detector.done: break
detector.close()
print(detector.result)
xml_enc = detector.result['encoding'] # The result seems always to be None
if xml_enc != 'utf-8':
# content = xml_str(xml_enc, 'replace').encode('utf-8') # Don't know how to replace encoding
pass
xml_clean = et.fromstring(xml_str, parser=parser)
# The detector function above and Encryption replacer does not work :(
#############################################################################
### Some code below is how I'd guess to proceed, after I have a good tree ###
#############################################################################
# ns = {"ss": "urn:schemas-microsoft-com:office:spreadsheet"}
# https://stackoverflow.com/questions/59945728/how-do-i-pick-up-text-values-of-child-nodes-when-parsing-xml-with-elementtree
# https://stackoverflow.com/questions/54107550/reading-a-spreadsheet-like-xml-with-elementtree
### Something like this to iterate through the children
# for appt in xml_tree.getchildren():
# for elem in appt.getchildren():
# if not elem.text:
# text = "None"
# else:
# text = elem.text
# print(elem.tag + " => " + text)
### Or something like this to iterate to take into account namespaces
# for ws in xml.findall('ss:Worksheet', namespaces):
# for table in ws.findall('ss:Row', namespaces):
# for c in table.findall('ss:Cell', namespaces):
# data = c.find('ss:Data', namespaces)
# if data.text is None:
# text = []
# data = data.findall('html:Font', namespaces)
# for element in data:
# text.append(element.text)
#
# data_text = ''.join(text)
# print(data_text)
# else:
# print(data.text)
### Or something like this to iterate to take into account xpaths and namespaces
# L = []
# ws = xml.xpath('/ss:Workbook/ss:Worksheet', namespaces=namespaces)
# if len(ws) > 0:
# tables = ws[0].xpath('./ss:Table', namespaces=namespaces)
# if len(tables) > 0:
# rows = tables[0].xpath('./ss:Row', namespaces=namespaces)
# for row in rows:
# tmp = []
# cells = row.xpath('./ss:Cell/ss:Data', namespaces=namespaces)
# for cell in cells:
# # print(cell.text);
# tmp.append(cell.text)
# L.append(tmp)
# print(L)