如何匹配字符串元素并更新plist中相应的响应字符串?

Posted

技术标签:

【中文标题】如何匹配字符串元素并更新plist中相应的响应字符串?【英文标题】:How to match a string element and updater the corresponding response string in a plist? 【发布时间】:2018-07-16 05:41:08 【问题描述】:

我正在尝试如下更新 plist

匹配字符串字段“此提交中修复了哪些更改错误?”并更新<key>response</key>对应的字符串字段

现在的问题代码更新字符串字段What change bugs are fixed in this submission?,我如何更新相应的响应字符串字段?我也添加了预期的plist输出?有没有更简单的方法来做这个python?我哪里出错了?

代码:-

import re,os,fileinput
text1_to_search = re.compile(r'<string>What change bugs are fixed in this submission?.*</string>')
replacement1_text = """change://problem/219620> milestone: WCM-739#202 has failed to build in install: expected a type 
change://problem/215275> Fix logic for PSK-->Open update
change://problem/1265279> Hotspot keeps changing from the device I selected
"""

for line in fileinput.input(filename, inplace=True, backup='.bak'):
    print(text1_to_search.sub(replacement1_text, line)),

列表

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//company//DTD PLIST 1.0//EN" "http://www.company.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>28</key>
    <dict>
        <key>description</key>
        <string>Which update of macOS, Xcode, and the SDKs was this submission built on with 'abc buildit'?</string>
        <key>id</key>
        <string>28</string>
        <key>multiline</key>
        <string>0</string>
        <key>releases</key>
        <array>
            <string>milestone</string>
        </array>
        <key>response</key>
        <string></string>
    </dict>
    <key>7</key>
    <dict>
        <key>description</key>
        <string>What change bugs are fixed in this submission? (Please include the change number or URL followed by the title)</string>
        <key>id</key>
        <string>7</string>
        <key>multiline</key>
        <string>1</string>
        <key>releases</key>
        <array>
            <string>milestone</string>
        </array>
        <key>response</key>
        <string></string>
    </dict>
</dict>
</plist>

更新后的预期输出

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//company//DTD PLIST 1.0//EN" "http://www.company.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>28</key>
    <dict>
        <key>description</key>
        <string>Which update of macOS, Xcode, and the SDKs was this submission built on with 'abc buildit'?</string>
        <key>id</key>
        <string>28</string>
        <key>multiline</key>
        <string>0</string>
        <key>releases</key>
        <array>
            <string>milestone</string>
        </array>
        <key>response</key>
        <string></string>
    </dict>
    <key>7</key>
    <dict>
        <key>description</key>
        <string>What change bugs are fixed in this submission? (Please include the change number or URL followed by the title)</string>
        <key>id</key>
        <string>7</string>
        <key>multiline</key>
        <string>1</string>
        <key>releases</key>
        <array>
            <string>milestone</string>
        </array>
        <key>change://problem/219620> milestone: WCM-739#202 has failed to build in install: expected a type 
change://problem/215275> Fix logic for PSK-->Open update
change://problem/1265279> Hotspot keeps changing from the device I selected</key>
        <string></string>
    </dict>
</dict>
</plist>

【问题讨论】:

【参考方案1】:

Don't use regular expression to parse XML。使用 XML 解析器。在 Python 中,推荐使用lxml。

使用 XPath,这是一种可能的实现方式。

from lxml import etree as et

with open("input.xml") as raw:
    # Parse the XML input file into a tree.
    tree = et.parse(raw)

    # Find the interesting <string> element by first finding the <string> to
    # use as key, then the parent <dict>, then the <key> that preceeds the
    # <string> to change. Since the xpath method returns a list, we take the
    # first element of each list.
    stringUsedAsKey = tree.xpath("/plist/dict/dict/string"
            + "[./text()=\"What change bugs are fixed in this submission? (Please include the change number or URL followed by the title)\"]")[0]
    interestingDict = stringUsedAsKey.getparent()
    stringToChange = interestingDict.xpath("key[text()=\"response\"]/following-sibling::string")[0]

    # Change the text of the <string>.
    stringToChange.text = "updated text"

    # Write the changed tree back to an XML file.
    tree.write("output.xml", pretty_print=True, xml_declaration=True, encoding="UTF-8")

【讨论】:

以上代码将 xml 中的任何地方的 &lt;string&gt;&lt;/string&gt; 替换为 &lt;string/&gt;,这是为什么以及如何修复它? &lt;string&gt;&lt;/string&gt;&lt;string/&gt; 是相同的,它们都是一个名为 string 的空元素。任何理智的 XML 解析都必须理解这两者。不过,可能有一种方法可以强制 lxml 不缩短空元素。 ***.com/questions/34111154/… 似乎有帮助,使用了write_c14n 但顶部的xml声明不见了,你知道如何得到这个吗? 在我的回答中使用xml_declaration=True

以上是关于如何匹配字符串元素并更新plist中相应的响应字符串?的主要内容,如果未能解决你的问题,请参考以下文章

如何匹配最长的字符串并更新值?

如何在 MySQL 中运行更新查询并替换匹配的字符串

如何从 plist 更新和删除字符串项和整个字典项

MongoDB计数按数组元素分组的数组中的匹配字符串

将字符串与元组列表匹配

如何本地化iOS info.plist文件中的字符串?