如何使用python修改xml文件中嵌套元素的文本?
Posted
技术标签:
【中文标题】如何使用python修改xml文件中嵌套元素的文本?【英文标题】:How to modify the text of nested elements in xml file using python? 【发布时间】:2020-02-15 17:33:44 【问题描述】:目前我正在处理语料库/数据集。它是 xml 格式,如下图所示。我面临一个问题。 我想一一访问所有 ‘ne’ 元素,如下图所示。然后我想访问“ne”元素内的“W”元素的文本。然后我想连接你的符号'SDi'和'EDi'与这些'W'元素的文本。 ‘i’ 可以取任何从 1 开始的正整数。在 ‘SDi’ 的情况下,我只需要 ‘ne’ 元素内的第一个 ‘W’ 元素的文本。在“EDi”的情况下,我只需要“ne”元素内的最后一个“W”元素的文本。 目前我在运行代码后没有得到任何输出。我认为这是因为元素“W”从未被访问过。此外,我认为元素 'W' 未被访问,因为它是元素 'ne' 的孙子,因此不能直接访问它,而是可能在其父节点的帮助下。
注意1:‘ne’元素中子元素的个数和名称不一样。
注2:这里只说明需要的东西。您可能会在编码/图片中找到一些其他细节,但请忽略它们。
我正在使用 Spyder (python 3.6) 任何帮助,将不胜感激。
我正在处理的 XML 文件中的图片如下所示:
XML 文件的文本版本: Click here
示例/预期输出图像(下):
到目前为止我所做的编码:
for i in range(len(List_of_root_nodes)):
true_false = True
current = List_of_root_nodes[i]
start_ID = current.PDante_ID
#print('start:', start_ID) # For Testing
end_ID = None
number = str(i+1) # This number will serve as i used with SD and ED that is (SDi and EDi)
discourse_starting_symbol = "SD" + number
discourse_ending_symbol = "ED" + number
while true_false:
if current.right_child is None:
end_ID = current.PDante_ID
#print('end:', end_ID) # For Testing
true_false = False
else:
current = current.right_child
# Finding 'ne' element with id='start_ID'
ne_text = None
ne_id = None
for ne in myroot.iter('ne'):
ne_id = ne.get('id')
# If ne_id matches with start_ID means the place where SDi is to be placed is found
if ne_id == start_ID:
for w in ne.iter('W'):
ne_text = str(w.text)
boundary_and_text = " " + str(discourse_starting_symbol) + " " + ne_text
w.text = boundary_and_text
break
# If ne_id matches with end_ID means the place where EDi is to be placed is found
# Some changes Required here: Here the 'EDi' will need to be placed after the last 'W' element.
# So last 'W' element needs to be accessed
if ne_id == end_ID:
for w in ne.iter('W'):
ne_text = str(w.text)
boundary_and_text = ne_text + " " + str(discourse_ending_symbol) + " "
w.text = boundary_and_text
break
【问题讨论】:
您能否发布您的 xml sn-p 的文本版本或指向它的链接以进行测试?您的预期输出示例也会有所帮助。 我已根据要求编辑了帖子,以便您可以帮助我。 @ColeTierney You should not post code as an image because:... 避免我们下载您的数据。嵌入一个小样本(如您的屏幕截图)作为帖子正文中的文本,以便在链接失效时为未来的读者提供服务。 欣赏你所说的,但请尊重,@Parfait 我不认为我已经发布了我的代码(标题为“到目前为止我已经完成的编码”)作为图像。跨度> 【参考方案1】:类似这样的东西(a.xml 是你上传的 XML):
注意代码没有使用任何外部库。
import xml.etree.ElementTree as ET
SD = 'SD'
ED = 'ED'
root = ET.parse('a.xml')
counter = 1
for ne in root.findall('.//ne'):
w_lst = ne.findall('.//W')
if w_lst:
w_lst[0].text = ' '.format(SD, counter, w_lst[0].text)
if len(w_lst) > 1:
w_lst[-1].text = ' '.format(w_lst[-1].text, ED, counter)
counter += 1
ET.dump(root)
【讨论】:
你能解释一下你发布的代码吗@balderman 当然。代码循环遍历所有元素。对于每个 ne,它会找到 w 个元素。如果有一个 w 元素(在 ne 下),它会设置 SD 值。如果有多个,则转到最后一个 w 并设置 ED 值。它对你有用吗? 我 100% 理解你所说的,但由于我的编码几乎为零,因此我不了解每一行的确切工作方式。你能告诉我更多关于' '的三个大括号的信息吗?他们在这里做什么?他们是否提供了一些空闲空间?另外,如果您可以告诉我有关“格式()”的功能。它对传递的三个参数做了什么?将它们结合在一起。是的?最后为什么会有 ET.dump(root)?是因为我们对 xml 文件进行了一些更改,现在需要重新构建/写入/或类似的东西吗? 上次当我检查您发布的解决方案时,我无法理解它,因此我没有检查它是否适合我。但是在考虑了一段时间之后,现在我认为这是我想要的东西,需要更少或更多的更改。我会告诉您它是否对我有用,并将您的解决方案标记为“有效”。谢谢【参考方案2】:当您需要修改具有各种细微差别的 XML 时,请考虑 XSLT,这是一种专门用于转换 XML 文件的语言。您可以使用 Python 的第三方模块 lxml
(不是内置的 etree
)运行 XSLT 1.0 脚本。
具体来说,调用identity transform 按原样复制XML,然后运行两个模板将SDI
添加到第一个<W>
的文本中,并将最后一个EDI 添加到最后一个<W>
的文本中。如果有 10 或 10,000 个 <W>
节点,无论是否深度嵌套,解决方案都会起作用。
为了演示 *** 的*** Python 和 XSLT 用户的示例数据,请参阅 online demo,其中 SDI
和 EDI
被添加到第一个和最后一个 <user>
节点:
XSLT (另存为.xsl文件,Python中要加载的特殊.xml文件)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:strip-space elements="*"/>
<!-- IDENTITY TRANSFORM -->
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<!-- EDIT FIRST W NODE -->
<xsl:template match="W[count(preceding::W)=0]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:value-of select="concat('SDI ', text())"/>
</xsl:copy>
</xsl:template>
<!-- EDIT LAST W NODE -->
<xsl:template match="W[count(preceding::W)+1 = count(//W)]">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:value-of select="concat('EDI ', text())"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Python (无循环或 if/else 逻辑)
import lxml.etree as et
doc = et.parse('/path/to/Input.xml')
xsl = et.parse('/path/to/Script.xsl')
# CONFIGURE TRANSFORMER
transform = et.XSLT(xsl)
# TRANSFORM SOURCE DOC
result = transform(doc)
# OUTPUT TO CONSOLE
print(result)
# SAVE TO FILE
with open('Output.xml', 'wb') as f:
f.write(result)
【讨论】:
以上是关于如何使用python修改xml文件中嵌套元素的文本?的主要内容,如果未能解决你的问题,请参考以下文章
在Python中使用ElementTree API插入xml元素作为嵌套元素。
如何单击元素并从链接的 xml 文件(python)中解析文本?