【问题标题】:Python / XML: lxml insert not functioning in a loop with deepcopyPython / XML:lxml 插入在 deepcopy 的循环中不起作用
【发布时间】:2021-10-09 05:03:05
【问题描述】:

我正在尝试使用 lxml + itertools 插入先前元素的深层副本。无论我做什么,我都只能插入一次新元素。

在示例中,您可以看到我尝试插入 5 次(实际上这是一个变量,但您知道 - 保持简单)。

我拥有的实际 XML 并不太复杂,但确实有很多元素,所以我将提供一个较小的示例版本。

我在这里缺少什么?在继续循环之前,我是否需要在执行 root.insert(insertPosition newWx) 之后以某种方式将更新写入根或树?

from lxml import etree
import copy
import itertools

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

# Find element to copy 
originalWx = tree.find("Weather")

insertPosition = int(tree.xpath('count(//Weather[last()]/preceding-sibling::*)')+1)
print("Next position for <Weather> is: " + str(insertPosition))

# Create a copy
newWx = copy.deepcopy(originalWx)

for _ in itertools.repeat(None, 5):
    root.insert(insertPosition, newWx)
    insertPosition = insertPosition + 1

开始 XML:

<ProjectDataSet>
  <Project>
    <Id>0.1.2</Id>
    <Project_Name>Weather Stream Sample</Project_Name>
    <End_Time>2021-06-30T13:00:00+10:00</End_Time>
    <Comments>Project Comments</Comments>
  </Project>
  <Thing>
    <Id>2</Id>
    <Project_Id>492</Project_Id>
    <Weather_Id>2</Weather_Id>
    <Merged_By>0</Merged_By>
    <Merged>0001-01-01T00:00:00+10:00</Merged>
    <Comments/>
  </Thing>
  <Detail>
    <Order_Id>1</Order_Id>
    <X>1095935</X>
    <Y>6999365</Y>
  </Detail>
  <Weather>
    <Id>2</Id>
    <Weather_Name>Original Weather</Weather_Name>
    <Comments>Original Weather</Comments>
    <Latitude>-27</Latitude>
    <Longitude>153</Longitude>
  </Weather>
  <Weather_Entry>
    <Weather_Id>2</Weather_Id>
    <Weather_Time>2021-06-29T10:00:00+10:00</Weather_Time>
    <Temperature>28</Temperature>
    <Rel_Humidity>20</Rel_Humidity>
    <Wind_Speed>15.4</Wind_Speed>
  </Weather_Entry>
  <Weather_Entry>
    <Weather_Id>2</Weather_Id>
    <Weather_Time>2021-06-29T11:00:00+10:00</Weather_Time>
    <Temperature>29</Temperature>
    <Rel_Humidity>24</Rel_Humidity>
    <Wind_Speed>12.4</Wind_Speed>
  </Weather_Entry>
  <Setting>
    <stuff>True</stuff>
  </Setting>
  <Setting>
    <stuff2>False</stuff2>
  </Setting>
<ProjectDataSet>

我得到了什么:

<ProjectDataSet>
  <Project>
    <Id>0.1.2</Id>
    <Project_Name>Weather Stream Sample</Project_Name>
    <End_Time>2021-06-30T13:00:00+10:00</End_Time>
    <Comments>Project Comments</Comments>
  </Project>
  <Thing>
    <Id>2</Id>
    <Project_Id>492</Project_Id>
    <Weather_Id>2</Weather_Id>
    <Merged_By>0</Merged_By>
    <Merged>0001-01-01T00:00:00+10:00</Merged>
    <Comments/>
  </Thing>
  <Detail>
    <Order_Id>1</Order_Id>
    <X>1095935</X>
    <Y>6999365</Y>
  </Detail>

*** Added break for clarity ***

  <Weather>
    <Id>2</Id>
    <Weather_Name>Original Weather</Weather_Name>
    <Comments>Original Weather</Comments>
    <Latitude>-27</Latitude>
    <Longitude>153</Longitude>
  </Weather>
  <Weather>
    <Id>2</Id>
    <Weather_Name>Original Weather</Weather_Name>
    <Comments>Original Weather</Comments>
    <Latitude>-27</Latitude>
    <Longitude>153</Longitude>
  </Weather>



  <Weather_Entry>
    <Weather_Id>2</Weather_Id>
    <Weather_Time>2021-06-29T10:00:00+10:00</Weather_Time>
    <Temperature>28</Temperature>
    <Rel_Humidity>20</Rel_Humidity>
    <Wind_Speed>15.4</Wind_Speed>
  </Weather_Entry>
  <Weather_Entry>
    <Weather_Id>2</Weather_Id>
    <Weather_Time>2021-06-29T11:00:00+10:00</Weather_Time>
    <Temperature>29</Temperature>
    <Rel_Humidity>24</Rel_Humidity>
    <Wind_Speed>12.4</Wind_Speed>
  </Weather_Entry>
  <Setting>
    <stuff>True</stuff>
  </Setting>
  <Setting>
    <stuff2>False</stuff2>
  </Setting>
<ProjectDataSet>

我期望得到什么:

<ProjectDataSet>
  <Project>
    <Id>0.1.2</Id>
    <Project_Name>Weather Stream Sample</Project_Name>
    <End_Time>2021-06-30T13:00:00+10:00</End_Time>
    <Comments>Project Comments</Comments>
  </Project>
  <Thing>
    <Id>2</Id>
    <Project_Id>492</Project_Id>
    <Weather_Id>2</Weather_Id>
    <Merged_By>0</Merged_By>
    <Merged>0001-01-01T00:00:00+10:00</Merged>
    <Comments/>
  </Thing>
  <Detail>
    <Order_Id>1</Order_Id>
    <X>1095935</X>
    <Y>6999365</Y>
  </Detail>

*** Added break for clarity ***

  <Weather>
    <Id>2</Id>
    <Weather_Name>Original Weather</Weather_Name>
    <Comments>Original Weather</Comments>
    <Latitude>-27</Latitude>
    <Longitude>153</Longitude>
  </Weather>
  <Weather>
    <Id>2</Id>
    <Weather_Name>Original Weather</Weather_Name>
    <Comments>Original Weather</Comments>
    <Latitude>-27</Latitude>
    <Longitude>153</Longitude>
  </Weather>
  <Weather>
    <Id>2</Id>
    <Weather_Name>Original Weather</Weather_Name>
    <Comments>Original Weather</Comments>
    <Latitude>-27</Latitude>
    <Longitude>153</Longitude>
  </Weather>
  <Weather>
    <Id>2</Id>
    <Weather_Name>Original Weather</Weather_Name>
    <Comments>Original Weather</Comments>
    <Latitude>-27</Latitude>
    <Longitude>153</Longitude>
  </Weather>
  <Weather>
    <Id>2</Id>
    <Weather_Name>Original Weather</Weather_Name>
    <Comments>Original Weather</Comments>
    <Latitude>-27</Latitude>
    <Longitude>153</Longitude>
  </Weather>
  <Weather>
    <Id>2</Id>
    <Weather_Name>Original Weather</Weather_Name>
    <Comments>Original Weather</Comments>
    <Latitude>-27</Latitude>
    <Longitude>153</Longitude>
  </Weather>



  <Weather_Entry>
    <Weather_Id>2</Weather_Id>
    <Weather_Time>2021-06-29T10:00:00+10:00</Weather_Time>
    <Temperature>28</Temperature>
    <Rel_Humidity>20</Rel_Humidity>
    <Wind_Speed>15.4</Wind_Speed>
  </Weather_Entry>
  <Weather_Entry>
    <Weather_Id>2</Weather_Id>
    <Weather_Time>2021-06-29T11:00:00+10:00</Weather_Time>
    <Temperature>29</Temperature>
    <Rel_Humidity>24</Rel_Humidity>
    <Wind_Speed>12.4</Wind_Speed>
  </Weather_Entry>
  <Setting>
    <stuff>True</stuff>
  </Setting>
  <Setting>
    <stuff2>False</stuff2>
  </Setting>
<ProjectDataSet>

【问题讨论】:

  • 如果要添加五份 originalWx,则需要制作五份。您只制作一份副本,您不能多次添加同一个子树。
  • 这很痛苦。谢谢(你的)信息。如果您将此添加为答案,我会将其标记为正确。如果你碰巧有一段你知道运行良好的代码,那就太好了 - 否则我会在它运行后在这里添加一些东西。

标签: python python-3.x lxml elementtree


【解决方案1】:

如果您想添加五份originalWx,您需要制作五份。您只制作一份副本,您不能多次添加同一个子树。

所以删除

newWx = copy.deepcopy(originalWx)

然后将循环改为

root.insert(insertPosition, copy.deepcopy(originalWx))

这样每个循环都会插入一个新副本。

在这方面,lxml.etree API 与 JavaScript DOM 实现非常相似。 XML 树中的每个元素都有一个父元素(您可以使用parent() 方法发现),这意味着当您将元素作为某个节点的子节点插入树时,它不再是另一个节点的子节点.换句话说,它将被移动。这在compatibility with ElementTree section of the lxml.etree documentation 中有说明。 (这是第四个要点。我找不到更准确的链接。)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多