Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/320.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python操作并保存XML,更改一个属性_Python_Xml - Fatal编程技术网

Python操作并保存XML,更改一个属性

Python操作并保存XML,更改一个属性,python,xml,Python,Xml,我有以下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">

我有以下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>
谢谢。

几句话:

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

  • 所有SOAP-ENV:*节点已转换为ns0*,m*节点已转换为ns1*。为此,我必须将它们从xml文件复制到代码中(
    soap_env_ns_name
    m_ns_name
    变量),如下所述:

  • SOAP-ENC和默认名称空间(xsi和xsd)已被删除,因为它们在xml中未被引用。而且,m已经从请求节点移动到信封(根)节点;我不确定它是否是标准的一部分,但在我见过的大多数XML上,名称空间是在根节点中声明的。无论如何,这里没有什么可以做的,Python的解析器不是很聪明

  • 底线是,您不会得到完全相同的输出(除非您想编写自己的解析器,如下所述:)
因此,代码与XML结构的关系非常紧密(丑陋但不是最丑陋的),如果结构发生变化,代码也需要更新(这里我不是在讨论名称空间的解决方法):

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

@EDIT2:注释掉了
属性值测试,因此现在该值仍将更改

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")
两个字:

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

  • 所有SOAP-ENV:*节点已转换为ns0*,m*节点已转换为ns1*。为此,我必须将它们从xml文件复制到代码中(
    soap_env_ns_name
    m_ns_name
    变量),如下所述:

  • SOAP-ENC和默认名称空间(xsi和xsd)已被删除,因为它们在xml中未被引用。而且,m已经从请求节点移动到信封(根)节点;我不确定它是否是标准的一部分,但在我见过的大多数XML上,名称空间是在根节点中声明的。无论如何,这里没有什么可以做的,Python的解析器不是很聪明

  • 底线是,您不会得到完全相同的输出(除非您想编写自己的解析器,如下所述:)
因此,代码与XML结构的关系非常紧密(丑陋但不是最丑陋的),如果结构发生变化,代码也需要更新(这里我不是在讨论名称空间的解决方法):

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

@EDIT2:注释掉了
属性值测试,因此现在该值仍将更改

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的解释,回溯(最近一次调用最后一次):文件“/Users/majid/PycharmProjects/changeXmlAttribute/changesoapatr.py”,第32行,在tree=ET.parse(“soap.xml”)文件“/Library/Frameworks/Python.framework/Versions/3.3/xml/etree/ElementTree.py”,第1242行,在parse.parse(源代码,parser)中文件“/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/xml/etree/ElementTree.py”,第1730行,在parse self._root=parser._parse(source)xml.etree.ElementTree.ParseError:找不到元素:第13行第16列,错误是引擎试图解析xml时,这意味着xml不正确。检查(可能使用web浏览器)input.xml文件是否有错误。缺少xml:,但您的代码没有将“XXXXX”更改为“YYYY”,xml文件仍然相同。您有机会测试此新版本吗?它对我有用。如果不是因为您,您可以粘贴output.xml的内容吗?谢谢ChristFati,它现在正在工作,但我不希望它依赖于值XXXXX,只需将任何bin域更改为新值。感谢CristiFati的解释,Traceback(最近一次调用):File“/Users/majid/PycharmProjects/changeXmlAttribute/changesoapatr.py”,第32行,在tree=ET.parse(“soap.xml”)文件/Library/Frameworks/Python.framework/Versions/3.3/xml/etree/ElementTree.py”中,第1242行,在parse tree.parse(源代码,解析器)文件中”/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/xml/etree/ElementTree.py”,第1730行,在parse self.\u root=parser.\u parse(source)xml.etree.ElementTree.ParseError:找不到元素:第13行,第16列,错误是在引擎尝试解析xml时,这意味着xml不正确。检查(可能使用web浏览器)对于input.xml文件的错误。缺少xml:,但您的代码没有将“XXXXX”更改为“YYYY”,xml文件仍然相同。您有机会测试这个新版本吗?它对我有用。如果不是因为您,您可以粘贴output.xml的内容吗?谢谢ChristFati,它现在正在工作,但我不希望它依赖于值XXXXX,只需将任何bin域更改为新值即可。
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")