【问题标题】:Python Manipulate and save XML, change one propertyPython 操作并保存 XML,更改一个属性
【发布时间】:2015-10-27 03:13:29
【问题描述】:

我有这个 xml:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <SOAP-ENV:Body>
        <m:request xmlns:m="http://www.datapower.com/schemas/management" domain="XXXXX">
            <m:do-action>
                <FlushDocumentCache>
                    <XMLManager class="XMLManager">default</XMLManager>
                </FlushDocumentCache>
                <FlushStylesheetCache>
                    <XMLManager class="XMLManager">default</XMLManager>
                </FlushStylesheetCache>
            </m:do-action>
        </m:request>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

我只想更改域属性的值 XXXXX。

我做了这样的事情:

import xml.etree.ElementTree as etree
tree = etree.parse('input.xml')
# HOW TO FIND THE VALUE XXXXX AND CHANGE IT WITH A NEW VALUE ???
tree.write('output.xml')

谢谢。

【问题讨论】:

    标签: python xml


    【解决方案1】:

    几句话:

    • 您将看到解析 xml 字符串(来自文件)然后将其写入另一个文件,不会产生相同的结果,因为解析器会更改它。您可以通过简单地运行您发布的代码来测试它(显然是第 3 行):

      import xml.etree.ElementTree as etree
      tree = etree.parse('input.xml')
      tree.write('output.xml')
      
    • 所有 SOAP-ENV:* 节点已转换为 ns0*,m* 节点已转换为 ns1*。为此,我必须将它们从 xml 文件复制到代码中(soap_env_ns_namem_ns_name 变量),如下所述:Saving XML using ETree in Python. It's not retaining namespaces, and adding ns0, ns1 and removing xmlns tags

    • SOAP-ENC 和默认命名空间(xsixsd)已被删除,因为它们在xml。此外,m 已从 request 节点移动到 Envelope(根)节点;我不确定它是否是标准的一部分,但在大多数 XML 中,我看到命名空间是在根节点中声明的。反正这里也无能为力 Python的解析器不是很聪明。

    • 底线是您不会得到完全相同的输出(除非您想编写自己的解析器,如下所述:Python: Update XML-file using ElementTree while conserving layout as much as possible)。

    因此,代码对 XML 结构非常严格(丑陋但不是最丑陋的),如果结构发生变化,代码也需要更新(这里我不是在谈论命名空间的变通方法):

    @EDIT1:添加了for 循环来注册命名空间,之前的版本就像我在第二个项目符号中描述的那样。但是在运行它时,它确实将 X s 替换为 Y s。

    @EDIT2:注释掉了domain属性值测试,所以现在值无论如何都会改变。

    import xml.etree.ElementTree as ET
    
    env_node_name = "Envelope"
    body_node_name = "Body"
    request_node_name = "request"
    domain_attr_name = "domain"
    domain_attr_val = "XXXXX"
    domain_attr_new_val = "YYYYY"
    
    #Gainarie: those are the namespaces from the xml file
    soap_env_ns_name = "SOAP-ENV"
    m_ns_name = "m"
    #soap_enc_ns_name = "SOAP-ENC"
    #xsi_ns_name = "xsi"
    #xsd_ns_name = "xsd"
    
    namespaces_dict = {
        soap_env_ns_name: "http://schemas.xmlsoap.org/soap/envelope/",
        m_ns_name: "http://www.datapower.com/schemas/management",
    
        # Those are simply ignored by the parser as they're not referenced in our xml.
        #"SOAP-ENC": "http://schemas.xmlsoap.org/soap/encoding/",
        #"xsi": "http://www.w3.org/2001/XMLSchema-instance",
        #"xsd": "http://www.w3.org/2001/XMLSchema",
    }
    
    
    def tag(ns, name):
        return "{" + ns + "}" + name
    
    
    for key in namespaces_dict.keys():
        ET.register_namespace(key, namespaces_dict[key])
    
    tree = ET.parse("input.xml")
    root = tree.getroot()
    env_gen = root.iter(tag(namespaces_dict[soap_env_ns_name], env_node_name))
    try:
        for env in env_gen:
            body_gen = env.iter(tag(namespaces_dict[soap_env_ns_name], body_node_name))
            try:
                for body in body_gen:
                    request_gen = body.iter(tag(namespaces_dict[m_ns_name], request_node_name))
                    try:
                        for request in request_gen:
                            if domain_attr_name in request.keys():
                                # Now, I didn't fully understand the question:
                                # you want to change the value of the 'domain' attribute (in your xml example: "XXXXX") to - let's say - "YYYYY"  (as my code does) on one of the 2 below cases:
                                # 1: change it only if current value is "XXXXX"
                                # 2: change it regardless of the current value
                                # if it's 1, then that's OK, but if it's 2, you'll have to comment the very below 'if domain_attr_val ...' line (prepend it by a # - just like the current one)
                                #if domain_attr_val == request.get(domain_attr_name):
                                request.set(domain_attr_name, domain_attr_new_val)
                    except StopIteration:
                        print "Done iterating on '%s' node" % request_node_name
            except StopIteration:
                print "Done iterating on '%s' node" % body_node_name
    except StopIteration:
        print "Done iterating on '%s' node" % env_node_name
    
    tree.write("output.xml")
    

    【讨论】:

    • 感谢 CristiFati 的解释,Traceback(最后一次调用):文件“/Users/majid/PycharmProjects/changeXmlAttribute/changeSOAPattr.py”,第 32 行,在 tree = ET. parse("soap.xml") 文件 "/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/xml/etree/ElementTree.py",第 1242 行,在 parse tree.parse(source, parser ) 文件“/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/xml/etree/ElementTree.py”,第 1730 行,解析 self._root = parser._parse(source) xml.etree。 ElementTree.ParseError:未找到元素:第 13 行,第 16 列
    • 嗯,错误是当引擎尝试解析 xml 时,这意味着 xml 不正确。检查(可能使用网络浏览器)input.xml 文件是否有错误。
    • xml 丢失了:,但是您的代码没有将“XXXXX”更改为“YYYYY”,xml 文件仍然相同。
    • 您有机会测试这个新版本吗?它对我有用。如果不适合您,您可以粘贴 output.xml 的内容吗?
    • 感谢 ChristFati,它现在可以工作了,但我不希望它依赖于值 XXXXX,只需将任何 bin 域更改为新值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多