Время от времени я перевожу некоторые приложения для Android: разработчик присылает мне XML-файл, например
<string name="foo">Foo</string>
<string name="baz">Baz</string>
и я отправляю ему обратно XML-файл, в котором переведено содержимое каждого элемента, например
<string name="foo">Translated foo</string>
<string name="baz">Translated baz</string>
Проблема возникает, когда разработчик добавляет новый текстовый элемент и отправляет мне новый файл для перевода, например:
<string name="foo">Foo</string>
<string name="bar">Bar</string>
<string name="baz">Baz</string>
Вопрос:Как я могу сравнить это с моим предыдущим переведенным файлом, ища только теги с новыми атрибутами или, что еще лучше, есть ли простой (более) способслияниедва файла, возможно, стоит добавить маркер в начале новых строк для перевода?
Учитывая предыдущий пример, это означало бы создание файла вроде
<string name="foo">Translated foo</string>
<!-- new --><string name="bar">Bar</string>
<string name="baz">Translated baz</string>
решение1
Поскольку я не нашел готового решения, я решил написать небольшой скрипт на Python самостоятельно, который, похоже, справляется с этой задачей:
"""Usage: merge_strings.py [-m <mrk>] [-o <file> [-i]] <old_xml> <new_xml>
Substitutes the content of any 'string' tag from <new_xml> with the
content of a 'string' tag from <old_xml> with the same 'name' attribute,
if present, otherwise prepends it with <mrk>.
By default the result is printed to stdout.
Note: This program assumes that no two 'string' tags in the same file
have the same 'name' attribute. Furthermore, 'string' tags with names
unique to <old_xml> are ignored.
Options:
-h --help Show this screen.
-m <mrk> --marker <mrk> Marker for new strings [default: ***new***].
-o <file> Print to <file> instead.
-i --interactive Check before overwriting <file>.
"""
from os.path import isfile
from sys import exit
from docopt import docopt
import lxml.etree as etree
def merge_strings(old, new, marker):
"""
Merge in place synonymous strings from 'old' into 'new'.
Ignores strings unique to 'old' and prepends strings unique to
'new' with 'marker'.
"""
for s in new.iterfind('//string'):
name = s.attrib['name']
t = old.find("//string[@name='" + name + "']")
if t is not None:
s.text = t.text
else:
s.text = marker + s.text
def check_overwrite(path):
"""
Check if we want to overwrite 'path' and exit if not.
Defaults to no.
"""
print("About to overwrite:", path)
choice = input("Continue? [y/N]")
if choice.lower() != 'y':
exit(0)
def print_to_file(tree, path, interactive=False):
if interactive and isfile(path):
check_overwrite(path)
with open(path, mode='wb') as f:
tree.write(f, pretty_print=True,
encoding='utf-8',
xml_declaration=True)
def print_to_stdout(tree):
print(etree.tostring(tree, pretty_print=True,
encoding='utf-8',
xml_declaration=True).decode('utf-8'))
if __name__ == '__main__':
args = docopt(__doc__)
old_tree = etree.parse(args['<old_xml>'])
new_tree = etree.parse(args['<new_xml>'])
merge_strings(old_tree, new_tree, args['--marker'])
if args['-o']:
print_to_file(new_tree, args['-o'], args['--interactive'])
else:
print_to_stdout(new_tree)
Вот обязательный пример вывода:
$cat tests/old.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="foo">Translated foo</string>
<string name="baz">Translated baz</string>
</resources>
$cat tests/new.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="foo">Foo</string>
<string name="bar">Bar</string>
<string name="baz">Baz</string>
</resources>
$python merge_strings.py old.xml new.xml
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="foo">Translated foo</string>
<string name="bar">***new***Bar</string>
<string name="baz">Translated baz</string>
</resources>
Замечание:Я относительно новичок в Python и совсем новичок в XML, поэтому любые комментарии о том, как улучшить приведенный выше код, будут высоко оценены.