gpt4 book ai didi

Python:使用 ElementTree 更新 XML 文件,同时尽可能保留布局

转载 作者:太空狗 更新时间:2023-10-29 17:50:02 27 4
gpt4 key购买 nike

我有一个使用 XML 命名空间的文档,我想为其增加 /group/house/dogs一个:(文件名为 houses.xml )

<?xml version="1.0"?>
<group xmlns="http://dogs.house.local">
<house>
<id>2821</id>
<dogs>2</dogs>
</house>
</group>

我当前使用以下代码的结果是:(创建的文件名为 houses2.xml)

<ns0:group xmlns:ns0="http://dogs.house.local">
<ns0:house>
<ns0:id>2821</ns0:id>
<ns0:dogs>3</ns0:dogs>
</ns0:house>
</ns0:group>

我想解决两件事(如果可以使用 ElementTree。如果不能,我将非常感谢您就我应该使用什么提出建议):

  1. 我想保留 <?xml version="1.0"?>行。
  2. 我不想为所有标签添加前缀,我想保持原样。

总而言之,我不想把文件弄得乱七八糟。

生成上述结果的当前代码(除上述缺陷外有效)如下。

我创建了一个实用函数,它使用 ElementTree 加载 XML 文件并返回 elementTree 和命名空间(因为我不想对命名空间进行硬编码,并且愿意承担它所暗示的风险):

def elementTreeRootAndNamespace(xml_file):
from xml.etree import ElementTree
import re
element_tree = ElementTree.parse(xml_file)

# Search for a namespace on the root tag
namespace_search = re.search('^({\S+})', element_tree.getroot().tag)
# Keep the namespace empty if none exists, if a namespace exists set
# namespace to {namespacename}
namespace = ''
if namespace_search:
namespace = namespace_search.group(1)

return element_tree, namespace

这是我的代码,用于更新狗的数量并将其保存到新文件 houses2.xml :

elementTree, namespace = elementTreeRootAndNamespace('houses.xml')

# Insert the namespace before each tag when when finding current number of dogs,
# as ElementTree requires the namespace to be prefixed within {...} when a
# namespace is used in the document.
dogs = elementTree.find('{ns}house/{ns}dogs'.format(ns = namespace))

# Increase the number of dogs by one
dogs.text = str(int(dogs.text) + 1)

# Write the result to the new file houses2.xml.
elementTree.write('houses2.xml')

最佳答案

针对此问题的基于 XML 的解决方案是为 ElementTree 编写一个辅助类:

  • 编写时在解析为 ElementTree 之前获取 XML 声明行,如果不同时编写编码属性(我检查了源代码),则无法编写 XML 声明行。
  • 解析一次输入文件,获取根元素的 namespace 。使用 ElementTree 将该命名空间注册为具有空字符串作为前缀。完成后,使用 ElementTree 再次使用新设置解析源文件。

它有一个主要缺点:

  • XML 注释丢失。据我所知,这种情况是 Not Acceptable (我最初不认为输入数据有任何注释,但事实证明它有)。<

我的帮助类示例:

from xml.etree import ElementTree as ET
import re


class ElementTreeHelper():
def __init__(self, xml_file_name):
xml_file = open(xml_file_name, "rb")

self.__parse_xml_declaration(xml_file)

self.element_tree = ET.parse(xml_file)
xml_file.seek(0)

root_tag_namespace = self.__root_tag_namespace(self.element_tree)
self.namespace = None
if root_tag_namespace is not None:
self.namespace = '{' + root_tag_namespace + '}'
# Register the root tag namespace as having an empty prefix, as
# this has to be done before parsing xml_file we re-parse.
ET.register_namespace('', root_tag_namespace)
self.element_tree = ET.parse(xml_file)

def find(self, xpath_query):
return self.element_tree.find(xpath_query)

def write(self, xml_file_name):
xml_file = open(xml_file_name, "wb")
if self.xml_declaration_line is not None:
xml_file.write(self.xml_declaration_line + '\n')

return self.element_tree.write(xml_file)

def __parse_xml_declaration(self, xml_file):
first_line = xml_file.readline().strip()
if first_line.startswith('<?xml') and first_line.endswith('?>'):
self.xml_declaration_line = first_line
else:
self.xml_declaration_line = None
xml_file.seek(0)

def __root_tag_namespace(self, element_tree):
namespace_search = re.search('^{(\S+)}', element_tree.getroot().tag)
if namespace_search is not None:
return namespace_search.group(1)
else:
return None


def __main():
el_tree_hlp = ElementTreeHelper('houses.xml')

dogs_tag = el_tree_hlp.element_tree.getroot().find(
'{ns}house/{ns}dogs'.format(
ns=el_tree_hlp.namespace))
one_dog_added = int(dogs_tag.text.strip()) + 1
dogs_tag.text = str(one_dog_added)

el_tree_hlp.write('hejsan.xml')

if __name__ == '__main__':
__main()

输出:

<?xml version="1.0"?>
<group xmlns="http://dogs.house.local">
<house>
<id>2821</id>
<dogs>3</dogs>
</house>
</group>

如果有人对此解决方案有改进,请不要犹豫,获取代码并加以改进。

关于Python:使用 ElementTree 更新 XML 文件,同时尽可能保留布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9579700/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com