使用 Python 和正则表达式编辑本地 XML 文件
Editing local XML file using Python and Regular expression
我是 python 的新手,正在尝试修改我本地系统中存在的一些 xml 配置文件。
输入:我有一个包含以下内容的 xml 文件(比如 Test.xml)。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<JavaHost xmlns="SomeInfo/v1.1">
<Domain>
<MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<SocketTimeout>500</SocketTimeout>
</MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<Composer>
<SocketTimeout>5000</SocketTimeout>
<Enabled>true</Enabled>
</Composer>
</Domain>
</JavaHost>
我想要实现的目标:
我想实现以下两件事:
第 1 部分:
我想将 SocketTimeout 标签(仅在 composer 标签下)的值修改为 60,并且还想添加这样的注释(例如更改此值以减少 SocketTimeout)。
因此文件 Test.xml 应该如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<JavaHost xmlns="SomeInfo/v1.1">
<MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<SocketTimeout>500</SocketTimeout>
</MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<Composer>
<!-- Changed this value to reduce SocketTimeout -->
<SocketTimeout>60</SocketTimeout>
<Enabled>true</Enabled>
</Composer>
</Domain>
</JavaHost>
第 2 部分:
在文件 Test.xml 中,我想在域标签下添加一个新标签,如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<JavaHost xmlns="SomeInfo/v1.1">
<MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<SocketTimeout>500</SocketTimeout>
</MessageProcessor>
<!-- comment should not be removed and all formatting should be untouched -->
<Composer>
<!-- Changed this value to reduce SocketTimeout -->
<SocketTimeout>60</SocketTimeout>
<Enabled>true</Enabled>
</Composer>
<New_tag>
<!-- New Tag -->
<Enabled>true</Enabled>
</New_tag>
</Domain>
</JavaHost>
这就是我想要的:)
我尝试过的:
为了完成这个任务,我考虑了以下选项:
Minidom/ElementTree/lxml 删除文件中的注释并更改文件的格式。
正则表达式:不删除评论,也不影响格式。
因此,我选择了正则表达式,下面是我开始的,但没有用:(
import os, re
# set the working directory
os.chdir('C:\Users\Dell\Desktop\')
# open the source file and read it
fh = open('C:\Users\Dell\Desktop\Test.xml', 'r')
subject = fh.read()
fh.close()
pattern = re.compile(r"\[<Composer>\].*?\[/<Composer>\]")
#Replace
result = pattern.sub(lambda match: match.group(0).replace('<SocketTimeout>500</SocketTimeout>','<SocketTimeout>60</SocketTimeout>') ,subject)
# write the file
f_out = open('C:\Users\Dell\Desktop\Test.xml', 'w')
f_out.write(result)
f_out.close()
任何实现我想要的东西或纠正错误的想法都将非常感激。
虽然我是 python 的新手,但我会尽力处理这些建议。
这不完全您想要的,但已经很接近了。一方面,避免 xml、html 和类似处理 的正则表达式,如瘟疫 。同时,如果您在使用 lxml.
等产品时偶尔会发现 'challenges',请不要感到惊讶。
我想,这次我发现了一个错误。
from lxml import etree
tree = etree.parse('shivam.xml')
element_to_change = tree.xpath('.//Composer/SocketTimeout')[0]
print(element_to_change)
element_to_change.text='60'
comment_will_follow_this = tree.xpath('.//Composer')[0]
print(comment_will_follow_this)
comment = etree.Comment('This did not work')
comment_will_follow_this.append(comment)
comment = etree.Comment('Changed this value to reduce SocketTimeout')
element_to_change.addprevious(comment)
tree.write('see_it.xml', pretty_print=True)
- 我使用
xpath
找到要更改的元素,以及文件中接收评论的位置。
append
方法应该将注释或其他元素作为子元素添加到给定元素。但是,我发现在这种情况下 'This did not work' 注释被添加为前面的元素注释。
- 然而,我确实发现
addprevious
能够在所需位置添加评论,美中不足的是它无法在评论和下一个评论之间放置 end-line xml 元素。
这是生成的文件。顺便说一句,你会注意到原来的评论是完整的。
<JavaHost>
<Domain>
<MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<SocketTimeout>500</SocketTimeout>
</MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<Composer>
<!--Changed this value to reduce SocketTimeout--><SocketTimeout>60</SocketTimeout>
<Enabled>true</Enabled>
<!--This did not work--></Composer>
</Domain>
</JavaHost>
由于您在同一句话中使用了 modify 和 XML,请考虑 XSLT, the special-purpose language designed to modify XML files. Python's lxml
can run XSLT 1.0 scripts as well as external processors 或其他语言 Python 可以在命令行调用。所以,XSLT 是可移植的!更重要的是,Python 可以将参数传递给 XSLT,以防 50 需要动态调整 - 非常类似于其他 special-purpose 语言中的参数,SQL,其中 Python 具有许多 API。
具体来说,XSLT 维护了 <xsl:comment>
命令并且可以将节点追加或重写到树中。此外,正如评论、链接和希望网络搜索推荐的那样,在 non-natural 语言的 X|HTML 文档上使用正则表达式是高度 ill-adivsed。因此,DOM 像 Python 的 etree、lxml、minidom 这样的库是首选,当然 XSLT 也符合 W3C 标准。
XSLT (另存为.xsl文件,一个特殊的.xml文件)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*|comment()">
<xsl:copy>
<xsl:apply-templates select="node()|@*|comment()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Domain">
<xsl:copy>
<xsl:apply-templates select="*|@*|comment()"/>
<New_tag>
<xsl:comment>New Tag</xsl:comment>
<Enabled>true</Enabled>
</New_tag>
</xsl:copy>
</xsl:template>
<xsl:template match="Composer">
<xsl:copy>
<xsl:comment>Changed this value to reduce SocketTimeout</xsl:comment>
<SocketTimeout>50</SocketTimeout>
<xsl:apply-templates select="Enabled"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Python
import lxml.etree as et
# LOAD XML AND XSLT
dom = et.parse('Input.xml')
xslt = et.parse('XSLT_Script.xsl')
# TRANSFORM SOURCE
transform = et.XSLT(xslt)
newdom = transform(dom)
# OUTPUT TO CONSOLE
print(newdom)
# OUTPUT TO FILE
with open('Output.xml', 'wb') as f:
f.write(newdom)
输出
<JavaHost>
<Domain>
<MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<SocketTimeout>500</SocketTimeout>
</MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<Composer>
<!--Changed this value to reduce SocketTimeout-->
<SocketTimeout>50</SocketTimeout>
<Enabled>true</Enabled>
</Composer>
<New_tag>
<!--New Tag-->
<Enabled>true</Enabled>
</New_tag>
</Domain>
</JavaHost>
我是 python 的新手,正在尝试修改我本地系统中存在的一些 xml 配置文件。
输入:我有一个包含以下内容的 xml 文件(比如 Test.xml)。
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<JavaHost xmlns="SomeInfo/v1.1">
<Domain>
<MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<SocketTimeout>500</SocketTimeout>
</MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<Composer>
<SocketTimeout>5000</SocketTimeout>
<Enabled>true</Enabled>
</Composer>
</Domain>
</JavaHost>
我想要实现的目标: 我想实现以下两件事:
第 1 部分: 我想将 SocketTimeout 标签(仅在 composer 标签下)的值修改为 60,并且还想添加这样的注释(例如更改此值以减少 SocketTimeout)。 因此文件 Test.xml 应该如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<JavaHost xmlns="SomeInfo/v1.1">
<MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<SocketTimeout>500</SocketTimeout>
</MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<Composer>
<!-- Changed this value to reduce SocketTimeout -->
<SocketTimeout>60</SocketTimeout>
<Enabled>true</Enabled>
</Composer>
</Domain>
</JavaHost>
第 2 部分: 在文件 Test.xml 中,我想在域标签下添加一个新标签,如下所示:
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<JavaHost xmlns="SomeInfo/v1.1">
<MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<SocketTimeout>500</SocketTimeout>
</MessageProcessor>
<!-- comment should not be removed and all formatting should be untouched -->
<Composer>
<!-- Changed this value to reduce SocketTimeout -->
<SocketTimeout>60</SocketTimeout>
<Enabled>true</Enabled>
</Composer>
<New_tag>
<!-- New Tag -->
<Enabled>true</Enabled>
</New_tag>
</Domain>
</JavaHost>
这就是我想要的:)
我尝试过的:
为了完成这个任务,我考虑了以下选项:
Minidom/ElementTree/lxml 删除文件中的注释并更改文件的格式。
正则表达式:不删除评论,也不影响格式。 因此,我选择了正则表达式,下面是我开始的,但没有用:(
import os, re
# set the working directory
os.chdir('C:\Users\Dell\Desktop\')
# open the source file and read it
fh = open('C:\Users\Dell\Desktop\Test.xml', 'r')
subject = fh.read()
fh.close()
pattern = re.compile(r"\[<Composer>\].*?\[/<Composer>\]")
#Replace
result = pattern.sub(lambda match: match.group(0).replace('<SocketTimeout>500</SocketTimeout>','<SocketTimeout>60</SocketTimeout>') ,subject)
# write the file
f_out = open('C:\Users\Dell\Desktop\Test.xml', 'w')
f_out.write(result)
f_out.close()
任何实现我想要的东西或纠正错误的想法都将非常感激。 虽然我是 python 的新手,但我会尽力处理这些建议。
这不完全您想要的,但已经很接近了。一方面,避免 xml、html 和类似处理 的正则表达式,如瘟疫 。同时,如果您在使用 lxml.
等产品时偶尔会发现 'challenges',请不要感到惊讶。我想,这次我发现了一个错误。
from lxml import etree
tree = etree.parse('shivam.xml')
element_to_change = tree.xpath('.//Composer/SocketTimeout')[0]
print(element_to_change)
element_to_change.text='60'
comment_will_follow_this = tree.xpath('.//Composer')[0]
print(comment_will_follow_this)
comment = etree.Comment('This did not work')
comment_will_follow_this.append(comment)
comment = etree.Comment('Changed this value to reduce SocketTimeout')
element_to_change.addprevious(comment)
tree.write('see_it.xml', pretty_print=True)
- 我使用
xpath
找到要更改的元素,以及文件中接收评论的位置。 append
方法应该将注释或其他元素作为子元素添加到给定元素。但是,我发现在这种情况下 'This did not work' 注释被添加为前面的元素注释。- 然而,我确实发现
addprevious
能够在所需位置添加评论,美中不足的是它无法在评论和下一个评论之间放置 end-line xml 元素。
这是生成的文件。顺便说一句,你会注意到原来的评论是完整的。
<JavaHost>
<Domain>
<MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<SocketTimeout>500</SocketTimeout>
</MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<Composer>
<!--Changed this value to reduce SocketTimeout--><SocketTimeout>60</SocketTimeout>
<Enabled>true</Enabled>
<!--This did not work--></Composer>
</Domain>
</JavaHost>
由于您在同一句话中使用了 modify 和 XML,请考虑 XSLT, the special-purpose language designed to modify XML files. Python's lxml
can run XSLT 1.0 scripts as well as external processors 或其他语言 Python 可以在命令行调用。所以,XSLT 是可移植的!更重要的是,Python 可以将参数传递给 XSLT,以防 50 需要动态调整 - 非常类似于其他 special-purpose 语言中的参数,SQL,其中 Python 具有许多 API。
具体来说,XSLT 维护了 <xsl:comment>
命令并且可以将节点追加或重写到树中。此外,正如评论、链接和希望网络搜索推荐的那样,在 non-natural 语言的 X|HTML 文档上使用正则表达式是高度 ill-adivsed。因此,DOM 像 Python 的 etree、lxml、minidom 这样的库是首选,当然 XSLT 也符合 W3C 标准。
XSLT (另存为.xsl文件,一个特殊的.xml文件)
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*|comment()">
<xsl:copy>
<xsl:apply-templates select="node()|@*|comment()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="Domain">
<xsl:copy>
<xsl:apply-templates select="*|@*|comment()"/>
<New_tag>
<xsl:comment>New Tag</xsl:comment>
<Enabled>true</Enabled>
</New_tag>
</xsl:copy>
</xsl:template>
<xsl:template match="Composer">
<xsl:copy>
<xsl:comment>Changed this value to reduce SocketTimeout</xsl:comment>
<SocketTimeout>50</SocketTimeout>
<xsl:apply-templates select="Enabled"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
Python
import lxml.etree as et
# LOAD XML AND XSLT
dom = et.parse('Input.xml')
xslt = et.parse('XSLT_Script.xsl')
# TRANSFORM SOURCE
transform = et.XSLT(xslt)
newdom = transform(dom)
# OUTPUT TO CONSOLE
print(newdom)
# OUTPUT TO FILE
with open('Output.xml', 'wb') as f:
f.write(newdom)
输出
<JavaHost>
<Domain>
<MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<SocketTimeout>500</SocketTimeout>
</MessageProcessor>
<!-- This comment should not be removed and all formating should be untouched -->
<Composer>
<!--Changed this value to reduce SocketTimeout-->
<SocketTimeout>50</SocketTimeout>
<Enabled>true</Enabled>
</Composer>
<New_tag>
<!--New Tag-->
<Enabled>true</Enabled>
</New_tag>
</Domain>
</JavaHost>