【问题标题】:Editing local XML file using Python and Regular expression使用 Python 和正则表达式编辑本地 XML 文件
【发布时间】:2018-08-05 05:06:23
【问题描述】:

我是 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 中,我想在 Domain 标签下添加一个新标签,如下所示:

<?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 删除文件中的 cmets 并更改文件的格式。

正则表达式:不删除 cmets,也不干扰格式化。 因此,我选择了正则表达式,下面是我开始使用的,但不起作用:(

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 新手,但会尽我所能提出建议。

【问题讨论】:

  • 显示您尝试的 lxml 代码,您声称不保留 cmets 和格式。
  • 感谢 ekhumoro 的快速回复,我没有尝试过 lxml,但我从 stakoverflow 上的各种问题和答案中了解到,它删除了 cmets。如果不是这种情况,您是否可以共享代码 sn-p 来实现这一点?我是新手,正在学习,但如果我得到一些像算法这样的短代码,我可以尝试编辑和编写代码。
  • 没有问题 ekhumoro

标签: python regex xml lxml elementtree


【解决方案1】:

这不是完全你想要的,但它很接近。一方面,避免 xml、html 和类似处理的正则表达式像瘟疫一样。同时,如果您在使用 lxml 等产品时偶尔发现“挑战”,请不要感到惊讶。

我想,这一次,我发现了一个错误。

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 查找要更改的元素,以及文件中接收 cmets 的位置。
  • append 方法应该将注释或其他元素添加到给定元素作为子元素。但是,我发现在这种情况下,“这不起作用”注释被添加为前面的元素注释。
  • 但是,我确实发现 addprevious 能够在所需位置添加评论,美中不足的是它未能在评论和下一个 xml 元素之间放置结束行。

这是生成的文件。顺便说一句,您会注意到原来的 cmets 是完整的。

<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>

【讨论】:

  • 太棒了,谢谢比尔,即使不能满足我的所有需求,这也应该对我有所帮助。我现在正在尝试这个,它应该是好的开始。我会发布更新。
  • 您好 Bill,此代码运行良好,但我面临以下问题: 为未提供更早的准确输入文件而道歉。我现在已对其进行了编辑。 1.输入文件实际上包含一些声明,即 (xml_declaration = True, encoding='UTF-8', Standalone="no") 这没有被保存,因此我像下面这样修改它并且它工作。 tree.write('see_it.xml', pretty_print=True, xml_declaration = True, encoding='UTF-8', Standalone="no")
  • 2.Input 文件还包含如下命名空间信息: 如果我删除它并使其仅 代码工作正常,但我不想删除这个。还有其他方法吗?
  • 3. 评论在没有 NewLine 的情况下被添加。 60 为此我修改了代码如下: parser = etree.XMLParser(remove_blank_text=True) tree = etree.parse('C:\ \Users\\Dell\\Desktop\\Test.xml',parser) 但这将删除我不想删除的所有空白行。
  • 并希望在 cmets 中添加 NewLine : New_Line_Here 60
【解决方案2】:

由于您在同一个句子中使用了 modifyXML,请考虑 XSLT,这是一种专门用于修改 XML 文件的语言。 Python 的lxml 可以运行XSLT 1.0 脚本以及external processors 或Python 可以在命令行调用的其他语言。所以,XSLT 是可移植的!更重要的是,Python 可以将参数传递给 XSLT,以防 50 需要动态调整——这与其他专用语言 SQL 中的参数非常相似,其中 Python 有许多 API。

具体来说,XSLT 维护&lt;xsl:comment&gt; 命令并且可以将节点附加或重写到树。此外,正如评论、链接和希望网络搜索所推荐的那样,在非自然语言的 X|HTML 文档上使用正则表达式是非常不明智的。因此,首选 Python 的 etree、lxml、minidom 等 DOM 库,当然还有符合 W3C 标准的 XSLT。

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>

【讨论】:

  • 感谢 Parfait 的回复,我正在检查您的解决方案,并会尽快发布更新。
  • 进展如何?这应该与您发布的确切输入一致。
猜你喜欢
  • 2020-05-24
  • 1970-01-01
  • 1970-01-01
  • 2019-09-18
  • 2020-09-29
  • 1970-01-01
  • 1970-01-01
  • 2022-11-24
  • 1970-01-01
相关资源
最近更新 更多