我正在使用以下示例XML树:
<group>
<group_info>
<Text>
Text_1
</Text>
</group_info>
<group_info>
<Text>
Text_2
</Text>
</group_info>
<group_info>
<Text>
Text_3
</Text>
</group_info>
</group>
我想合并<group>
中所有重复的子元素并将它们分组为一个子元素。我想要的输出:
<group>
<group_info>
<Text>
Text_1 Text_2 Text_3
</Text>
</group_info>
</group>
我不导入任何正在使用的新模块:
import xml.etree.ElementTree
group_list = MY_XML.findall(".//group") # I do this because the actual xml is bigger with several groups
for elem in group_list:
string_text = ""
for child in elem :
for super_child in child:
if(super_child.text is not None): #Just in case None value because I cannot use string addition
string_text = string_text + super_child.text + " "
elem.remove(child)
new_child = xml.etree.ElementTree.Element("group_info")
text_elem = xml.etree.ElementTree.Element("Text")
text_elem.text = string_text
new_child.append(text_elem)
elem.append(new_child)
这个想法是我遍历所有组,将<group_info>
中的所有文本信息收集到一个字符串中,然后删除树中的所有这些元素,并在信息中附加一个新元素。这可能不是最好的方法,但是我是一个相对较新的人。但是我的输出看起来像:
<group>
<group_info>
<Text>
Text_1
</Text>
</group_info>
<group_info>
<Text>
Text_2
</Text>
</group_info>
<group_info>
<Text>
Text_3
</Text>
</group_info>
<group_info><Text>Text1 Text2 Text3</Text></group_info></group>
从技术上讲,最后一行是我需要的(尽管看起来并不漂亮),但是我不知道为什么即使我打<group_info>
答案 0 :(得分:1)
由于没有人回答,所以花了我一些时间,但是如果其他人遇到相同的问题,我就会得到答案和指示。
我从您在问题中看到的初始代码开始,该代码不会删除旧元素,并且在最后一行留下了非常丑陋的内容。
请注意:MY_XML = xml.etree.ElementTree.parse({PATH_OF_XML})
如果使用的是xml.etree.ElementTree,则应使用remove()
删除节点的方法,但这需要您拥有父节点
节点参考。我称之为elem.remove(child)
[第9行]
那么,为什么不删除它们?我发现修改 您要迭代的对象会影响迭代。这不是 完全出乎意料,如果您在更改列表的同时 遍历它。我无法存储信息的方式 一次删除元素。
我必须拆分任务:
group_list = MY_XML.findall(".//group") # I do this because the actual xml is bigger with several groups
text_list = []
for group in group_list:
string_text = ""
for child in group :
for super_child in child:
if(super_child.text is not None): #Just in case None value because I cannot use string addition
string_text = string_text + super_child.text + " "
text_list.append(string_text) #I stored all the info in 1 group as a value in this list because like I stated my overall xml might be bigger with more than 1 group
for group in group_list:
for elem in group.findall(".//group_info"):
#loop over all possible <group> and removes all <group_info> inside
group.remove(elem)
#And finally to append the information gathered:
for group in group_list:
Text_elem = ET.Element("Text")
Text_elem.text = text_list[group_list.index(group)]
group_info_elem = ET.Element("Kundenhinweis_redigiert")
group_info_elem.append(Text_elem)
group.append(Kund_elem)
这给我留下了非常丑陋的输出:
<group>
<group_info><Text>Text1 Text2 Text3</Text></group_info></group>
,可使用xml.dom.minidom
模块轻松解决。我首先定义:
def prettify(elem):
rough_string = xml.etree.ElementTree.tostring(elem, 'utf-8')
reparsed = xml.dom.minidom.parseString(rough_string)
return reparsed.toprettyxml(indent=" ")
调用该函数:
root = MY_XML.getroot()
pretty_xml = prettify(root)
#Next line is optional, but sometimes your string contains empty lines or lines with white spaces and/or breaklines
pretty_xml = "\n".join([s for s in pretty_xml.split("\n") if not s.isspace()])
print(pretty_xml)
输出将是:
<group>
<group_info>
<Text>Text1 Text2 Text3</Text>
</group_info>
</group>
希望这对其他新手有帮助。
答案 1 :(得分:1)
考虑XSLT,这是一种专用于转换XML文件的语言,您可以在其中通过索引相同的节点名称并将其文本值分组来运行Muenchian Method。尽管Python的内置xml.ElementTree
不支持XSLT,但其第三方模块lxml
却支持XSLT 1.0脚本。而且您可以这样做,而无需单个for
循环,也无需手动修饰输出。
XSLT (另存为.xsl文件,一个特殊的.xml文件)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" method="xml"/>
<xsl:strip-space elements="*"/>
<xsl:key name="group_key" match="group/*" use="name()" />
<xsl:template match="/group">
<xsl:copy>
<xsl:apply-templates select="*[generate-id() =
generate-id(key('group_key', name())[1])]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group/*">
<xsl:copy>
<xsl:element name="{name(*)}">
<xsl:for-each select="key('group_key', name())">
<xsl:value-of select="normalize-space(*)"/>
<xsl:if test="position() != last()">
<xsl:text> </xsl:text>
</xsl:if>
</xsl:for-each>
</xsl:element>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
XSLT Demo (分为两组)
Python
import lxml.etree as et
# LOAD XML AND XSL
doc = et.parse('/path/to/Input.xml')
xsl = et.parse('/path/to/XSLT_Script.xsl')
# CONFIGURE TRANSFORMER
transform = et.XSLT(xsl)
# RUN TRANSFORMATION
result = transform(doc)
# PRINT RESULT
print(result)
# SAVE TO FILE
with open('/path/to/Output.xml', 'wb') as f:
f.write(result)