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

Del*_*ted 13 python xml

我有一个使用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>
Run Code Online (Sandbox Code Playgroud)

我使用下面代码的当前结果是:(调用创建的文件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>
Run Code Online (Sandbox Code Playgroud)

我想修复两件事(如果有可能使用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
Run Code Online (Sandbox Code Playgroud)

这是我更新狗数并将其保存到新文件的代码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')
Run Code Online (Sandbox Code Playgroud)

Aar*_*lla 1

不幸的是,往返并不是一个小问题。对于 XML,通常不可能保留原始文档,除非您使用特殊的解析器(例如DecentXML,但那是针对 Java 的)。

根据您的需求,您有以下选择:

  • 如果您控制源代码并且可以通过单元测试保护代码,则可以编写自己的简单解析器。该解析器不接受 XML,只接受有限的子集。例如,您可以将整个文档作为字符串读取,然后使用 Python 的字符串操作来查找<dogs>和替换下一个<. 黑客?是的。

  • 您可以过滤输出。XML 只允许该字符串<ns0:出现在一处,因此您可以搜索并替换它<,然后使用<group xmlns:ns0="→进行相同的操作<group xmlns="。这是相当安全的,除非您可以在 XML 中包含CDATA 。

  • 您可以编写自己的简单 XML 解析器。将输入读取为字符串,然后为每对及其<>在输入中的位置创建元素。这允许您快速分解输入,但仅适用于小输入。