Von Zeit zu Zeit übersetze ich einige Android-Apps: Der Entwickler schickt mir eine XML-Datei, z. B.
<string name="foo">Foo</string>
<string name="baz">Baz</string>
und ich schicke ihm eine XML-Datei zurück, in der der Inhalt jedes Elements übersetzt wurde, z. B.
<string name="foo">Translated foo</string>
<string name="baz">Translated baz</string>
Das Problem entsteht, wenn der Entwickler ein neues Textelement hinzufügt und mir eine neue Datei zur Übersetzung sendet, z. B.
<string name="foo">Foo</string>
<string name="bar">Bar</string>
<string name="baz">Baz</string>
Frage:Wie kann ich dies mit meiner zuvor übersetzten Datei vergleichen und nur nach den Tags mit neuen Attributen suchen, oder, noch besser, gibt es eine einfache (oder ziemlich einfache) Möglichkeit,verschmelzendie beiden Dateien, evtl. mit einem Marker am Anfang der neuen zu übersetzenden Zeilen?
Im obigen Beispiel würde dies bedeuten, dass eine Datei wie folgt generiert wird:
<string name="foo">Translated foo</string>
<!-- new --><string name="bar">Bar</string>
<string name="baz">Translated baz</string>
Antwort1
Da ich keine vorgefertigte Lösung gefunden habe, habe ich beschlossen, selbst ein kleines Python-Skript zu schreiben, das bislang zu funktionieren scheint:
"""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)
Hier die obligatorische Beispielausgabe:
$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>
Anmerkung:Ich bin relativ neu bei Python und völlig neu bei XML, daher wäre ich für alle Kommentare zur Verbesserung des obigen Codes sehr dankbar.