【问题标题】:Replace words in XML file替换 XML 文件中的单词
【发布时间】:2015-03-08 07:20:20
【问题描述】:

我需要编写 python 脚本来替换 xml 文件中某些单词的所有出现。我只需要替换标签中的禁用词即可。

这应该被替换:

<some_xml_tag>some text REPLACE_ME some text</some_xml_tag>

这不应该:

<some_xml_tag attr="REPLACE_ME">some text</some_xml_tag>

<REPLACE_ME>some text</REPLACE_ME>

我不是正则表达式专家,但应该可以吗?

【问题讨论】:

  • 这个REPLACE_ME 是否可以出现在 XML 中的任何位置——在标签名称、文本或属性中?谢谢。
  • 是的,这就是问题所在。但只有包含在标签中才会被替换

标签: python regex xml replace xml-parsing


【解决方案1】:

请改用 XML 解析器。

使用lxml 库的示例。这里我们使用xpath() 搜索具有所需文本的节点,然后使用replace() 替换它:

import lxml.etree as ET

ban_word = 'REPLACE_ME'
replacement = 'HELLO'

data = """<root>
    <some_xml_tag>REPLACE_ME</some_xml_tag>
    <some_xml_tag attr="REPLACE_ME">some text</some_xml_tag>
    <REPLACE_ME>some text</REPLACE_ME>
</root>
"""

root = ET.fromstring(data)

for item in root.xpath('//*[. = "%s"]' % ban_word):
    item.text = item.text.replace(ban_word, replacement)

print ET.tostring(root)

打印:

<root>
    <some_xml_tag>HELLO</some_xml_tag>
    <some_xml_tag attr="REPLACE_ME">some text</some_xml_tag>
    <REPLACE_ME>some text</REPLACE_ME>
</root>

注意事项:

  • 比较不区分大小写
  • xml.etree.ElementTree 不会处理这种特殊方法,因为它仅提供有限的 xpath 支持
  • 正如@tdelaney 在 cmets 中指出的那样,如果您有要替换的单词列表,最好简单地遍历所有节点并在必要时替换文本

【讨论】:

  • 非常感谢,我会尽快尝试的
  • 非常好的方法 +1
  • @tdelaney 这是一个有效的观点。这里有很多 ifs/caveats,让我们等待 OP 的回应。谢谢。
  • 替换应该区分大小写
【解决方案2】:

作为@alexce 答案的扩展/替代方案,底线是:您仍然可以迭代所有子元素并替换循环中的所有单词:

import lxml.etree as ET

ban_words = ['REPLACE_ME', 'Some']
replacement = 'HELLO'

data = """<root>
    <some_xml_tag>REPLACE_me</some_xml_tag>
    <some_xml_tag attr="REPLACE_ME">Some text</some_xml_tag>
    <REPLACE_ME>some text</REPLACE_ME>
</root>
"""
root = ET.fromstring(data)
# different approach using iter()
for node in root.iter():
    for word in ban_words:
        node.text = node.text.replace(word, replacement)

print ET.tostring(root)

结果也会像您的列表一样区分大小写:

<root>
    <some_xml_tag>REPLACE_me</some_xml_tag>
    <some_xml_tag attr="REPLACE_ME">HELLO text</some_xml_tag>
    <REPLACE_ME>some text</REPLACE_ME>
</root>

更新

如果你不想替换连接词,你可以使用字典来匹配禁用词和替换,如下所示:

import lxml.etree as ET
ban = {'REPLACE_ME': 'HELLO', 'Some': 'HELLO'}

data = """<root>
    <some_xml_tag>REPLACE_me</some_xml_tag>
    <some_xml_tag attr="REPLACE_ME">REPLACE_ME Some text</some_xml_tag>
    <REPLACE_ME>someSome Some SomeSOME text</REPLACE_ME>
</root>
"""
root = ET.fromstring(data)
# different approach using iter()
for node in root.iter():
    txt = node.text.split(" ")
    for i, t in enumerate(txt):
        if ban.get(t):
            txt[i] = ban.get(t)
    node.text = ' '.join(txt)

print ET.tostring(root)

连接词不会被替换,只有完全匹配的结果是:

<root>
    <some_xml_tag>REPLACE_me</some_xml_tag>
    <some_xml_tag attr="REPLACE_ME">HELLO HELLO text</some_xml_tag>
    <REPLACE_ME>someSome HELLO SomeSOME text</REPLACE_ME>
</root>

【讨论】:

  • 这就是我所拥有的。我只是添加了一些更多的逻辑,所以它只会替换完全匹配而不是包含禁用词的单词的一部分。
  • 如果你没问题,我会将来自@alecxe 的帖子设置为接受的答案,因为我真的很喜欢这个想法,其他想要同样东西的人希望能阅读整个帖子
  • @zdarsky.peter,我也认为alecxe的应该是公认的答案,前提是关键方法是在for循环下进行模式匹配,并且有一些未明确的要求
  • 谢谢你们!一旦新的 SO 日开始,我肯定会投票。
【解决方案3】:

这是可能的...但不要使用正则表达式,而是尝试 ElementTree:https://docs.python.org/2/library/xml.etree.elementtree.html

这将使查找/替换元素文本值比元素属性等更容易。

【讨论】:

    猜你喜欢
    • 2016-09-02
    • 2015-03-02
    • 1970-01-01
    • 2011-02-23
    • 1970-01-01
    • 2020-01-06
    • 1970-01-01
    • 2019-04-10
    相关资源
    最近更新 更多