Buscando diferentes etiquetas en dos archivos XML cuando el contenido es diferente

1

De vez en cuando traduzco algunas aplicaciones de Android: el desarrollador me envía un archivo XML, p. Ej.

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

y le devuelvo un archivo XML donde se ha traducido el contenido de cada elemento, p. ej.

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

El problema surge cuando el desarrollador agrega un nuevo elemento de texto y me envía un nuevo archivo para traducir, por ejemplo

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

Pregunta: ¿Cómo puedo comparar esto con mi archivo traducido anterior buscando solo las etiquetas con nuevos atributos o, mejor aún, hay una manera simple (ish) de fusionar los dos archivos, posiblemente agregando un marcador al comienzo de las nuevas líneas? ¿a ser traducido?

Dado el ejemplo anterior, esto significaría generar un archivo como

<string name="foo">Translated foo</string>
<!-- new --><string name="bar">Bar</string>
<string name="baz">Translated baz</string>
AP
fuente
3
Dígale al desarrollador que le envíe nuevas versiones basadas en las versiones ya traducidas que proporcionó, o marque las diferencias antes de que se lo envíen. Tener que buscar repetidamente a través de etiquetas viejas como esta (después de proporcionar traducciones y archivos actualizados) es una estupidez, ya que el desarrollador. conoce sus cambios mejor que nadie. / opinion :)
Ƭᴇcʜιᴇ007

Respuestas:

0

Como no encontré ninguna solución preexistente, decidí escribir un pequeño script de Python que hasta ahora parece hacer el trabajo:

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

Aquí está la salida de ejemplo obligatoria:

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

Observación: Soy relativamente nuevo en Python y completamente nuevo en XML, por lo que cualquier comentario sobre cómo mejorar el código anterior sería muy apreciado.

AP
fuente