Poszukiwanie różnych tagów w dwóch plikach XML, gdy zawartość jest inna

1

Od czasu do czasu tłumaczę niektóre aplikacje na Androida: deweloper wysyła mi plik XML, np.

<string name="foo">Foo</string>
<string name="baz">Baz</string>

i wysyłam mu plik XML, w którym treść każdego elementu została przetłumaczona, np.

<string name="foo">Translated foo</string>
<string name="baz">Translated baz</string>

Problem pojawia się, gdy programista dodaje nowy element tekstowy i wysyła mi nowy plik do przetłumaczenia, np.

<string name="foo">Foo</string>
<string name="bar">Bar</string>
<string name="baz">Baz</string>

Pytanie: Jak mogę porównać to z moim poprzednim przetłumaczonym plikiem, szukając tylko tagów z nowymi atrybutami lub, jeszcze lepiej, czy istnieje prosty (ish) sposób na łączyć dwa pliki, ewentualnie dodanie znacznika na początku nowych linii do przetłumaczenia?

Biorąc pod uwagę poprzedni przykład, oznaczałoby to wygenerowanie takiego pliku

<string name="foo">Translated foo</string>
<!-- new --><string name="bar">Bar</string>
<string name="baz">Translated baz</string>
A.P.
źródło
3
Poproś programistę o wysłanie Ci nowych wersji opartych na już przetłumaczonych wersjach, które dostarczyłeś, lub zaznacz różnice, zanim prześlesz je do Ciebie. Wielokrotne przeszukiwanie starych tagów, takich jak ten (już po dostarczeniu tłumaczeń i zaktualizowanych plików), jest proste, ponieważ dev. zna jego zmiany lepiej niż ktokolwiek inny. / opinia :)
Ƭᴇcʜιᴇ007

Odpowiedzi:

0

Ponieważ nie znalazłem żadnego wcześniej istniejącego rozwiązania, postanowiłem sam napisać mały skrypt Pythona, który jak dotąd wydaje się działać:

"""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)

Oto obowiązkowe przykładowe wyjście:

$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>

Uwaga: Jestem stosunkowo nowy w Pythonie i całkowicie nowy w XML, więc wszelkie komentarze dotyczące ulepszenia powyższego kodu byłyby bardzo mile widziane.

A.P.
źródło