Python操作并保存XML,更改一个属性
我有以下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">
<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的解析器不是很聪明
- 底线是,您不会得到完全相同的输出(除非您想编写自己的解析器,如下所述:)
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的解析器不是很聪明
- 底线是,您不会得到完全相同的输出(除非您想编写自己的解析器,如下所述:)
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")