Suchen nach unterschiedlichen Tags in zwei XML-Dateien, wenn der Inhalt unterschiedlich ist

Suchen nach unterschiedlichen Tags in zwei XML-Dateien, wenn der Inhalt unterschiedlich ist

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.

verwandte Informationen