【问题标题】:Python / Pandas / XML - Write pandas dataframe rows back to LXMLPython / Pandas / XML - 将 pandas 数据帧行写回 LXML
【发布时间】:2021-10-11 19:37:01
【问题描述】:

我目前正在使用 lxml 摄取一个 XML 文件,然后从根元素创建一个 pandas 数据框。我基本上使用this example。我这样做是为了做一些数学运算/对数据进行一些建模。

我想要实现的下一步是能够将数据写回 xml 文档。在我脚本的其他地方,我使用了root.insert,因为我可以强制在特定位置索引处插入,以保持 xml 文档的整洁和连贯。

有没有一种方法可以为数据帧中的每一行使用root.insert(position, data) 之类的东西写出数据帧的每一行,其中数据帧列标题是标签?

示例 XML

<Root_Data>

  <SomeData></SomeData>
  <SomeOtherData></SomeOtherData>   
   
  <Weather>
    <WxId>1</WxId>
    <Temp>20></WxId>
    <WindSpeed>15</WindSpeed>
  </Weather>

  # We will insert more weather here - I can find this position index. Assume it is 3.

  <SomeMoreData></SomeMoreData>
<Root_Data>

熊猫数据框:

ID Temp Windspeed
2  25   30
3  30   15
4  15   25

我会提供一些到目前为止我已经尝试过的代码 - 但实际上我空手而归可能会改变,这就是为什么我想使用列标题作为标签。)。

预期结果

<Root_Data>

  <SomeData></SomeData>
  <SomeOtherData></SomeOtherData>   
   
  <Weather>
    <WxId>1</WxId>
    <Temp>20></WxId>
    <WindSpeed>15</WindSpeed>
  </Weather>
  <Weather>
    <WxId>2</WxId>
    <Temp>25></WxId>
    <WindSpeed>30</WindSpeed>
  </Weather>
  <Weather>
    <WxId>3</WxId>
    <Temp>30></WxId>
    <WindSpeed>15</WindSpeed>
  </Weather>
  <Weather>
    <WxId>4</WxId>
    <Temp>15></WxId>
    <WindSpeed>25</WindSpeed>
  </Weather>

  <SomeMoreData></SomeMoreData>
<Root_Data>

到目前为止的示例代码:

from lxml import etree
import pandas as pd

tree = etree.parse('example.xml')
root = tree.getroot()

#Load into dataframe
for node in root:
            res=[]
            df_cols = ["WxId","Temp", "WindSpeed"]
            res.append(node.attrib.get(df_cols[0]))
            for el in df_cols[1:]:
                if node is not None and node.find(el) is not None:
                    res.append(node.find(el).text)
                else:
                    res.append(None)
            rows.append({df_cols[i]: res[i]
                        for i, _ in enumerate(df_cols)})
        out_df = pd.DataFrame(rows, columns = df_cols)
        out_df = out_df[~out_df['Temp'].isnull()] #Proxy for good / bad data. Remove nulls.

#Now, write from data frame back to root so we can structure the XML before writing to file. 
# ? Unknown method

【问题讨论】:

    标签: python python-3.x pandas dataframe lxml


    【解决方案1】:

    另一种方法,以防您的列未定义或将来可能会增加。

    df = pd.read_csv('./123.csv')
    
    root = etree.Element("root")
    for rows in range(0,df.shape[0]):
        Tag = etree.Element('weather')
        for cols in range(0,df.shape[1]):
            etree.SubElement(Tag,df.iloc[rows:,cols].head().name).text = str(df.iloc[rows][cols])
        # Append Element "Tag" to the Main Root here
        root.append(Tag)
    
    print(etree.tostring(root,encoding='Unicode'))
    

    【讨论】:

    • 请问-您的示例有效,但是导致所有元素都被添加到单行中而没有格式化。是否可以格式化正在写入的元素,以便像示例中那样存在换行符和缩进。我认为它与这部分代码有关:etree.SubElement(Tag,df.iloc[rows:,cols].head().name).text
    • 因此,当您将该文件导出为 XML 时,请使用 pretty_print 进行缩进。对于 STDOUT 打印,例如。 print(etree.tostring(root,encoding='Unicode',pretty_print=True))
    • 是的,不幸的是,似乎无法修复它。 outfile = 'test.xml' tree.write(outfile, xml_declaration=True, standalone='yes', encoding='utf-8', pretty_print=True)
    • 如果您要大量修改现有结构 - 请检查此stackoverflow.com/questions/7903759/… 它需要“remove_blank_text=True”
    • 谢谢。我正在查看另一个类似的帖子,但没有得到任何结果。我已经用杂乱的标签编写了文件,然后再次导入它并使用解析器,所以tree --&gt; file --&gt; import file again --&gt; parser --&gt; tree --&gt; write tree.. 我似乎无法弄清楚如何在不先通过文件的情况下从tree --&gt; parser --&gt; write tree 开始。
    【解决方案2】:

    您可以使用to_xml 将您的数据框转换为xml:

    xdata = df.rename(columns={'ID': 'WxId'})
              .to_xml(index=False, root_name='Root_Data', row_name='Weather')
    
    >>> xdata
    <?xml version='1.0' encoding='utf-8'?>
    <Root_Data>
      <Weather>
        <WxId>2</WxId>
        <Temp>25</Temp>
        <Windspeed>30</Windspeed>
      </Weather>
      <Weather>
        <WxId>3</WxId>
        <Temp>30</Temp>
        <Windspeed>15</Windspeed>
      </Weather>
      <Weather>
        <WxId>4</WxId>
        <Temp>15</Temp>
        <Windspeed>25</Windspeed>
      </Weather>
    </Root_Data>
    

    现在您可以使用 lxml 在第一个子 Weather 和最后一个子 Weather 之前插入数据,或者在原始 xml 文件中的某个位置插入您的 xdata。

    仅供参考,您可以使用 pd.read_xml 将您的 xml 转换为数据框。

    【讨论】:

    • 所以我正在尝试以下两行并收到错误消息。 xdata = out_df.to_xml(index=False, root_name='Root_Data', row_name='Weather') root.insert(insertPosition, xdata) 错误:TypeError: Argument 'element' has incorrect type (expected lxml.etree._Element, got str)。有什么想法吗?
    猜你喜欢
    • 2013-12-10
    • 2016-03-23
    • 2019-08-07
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    • 2015-08-07
    • 1970-01-01
    • 2018-07-06
    相关资源
    最近更新 更多