I have 3 functions which are annoyingly similar, but I can't figure out a way to refactor them without making the code unreadable.
The three functions deal with xml files (.resx
), the first function reads all files in a directory and "collects" all strings inside a data.value
tag, adds them to a set and returns that set, for example:
<data name="AccessibilityTitleResource1.Text" xml:space="preserve">
<value>Pages Accessibility</value>
The second function reads these same files, and swaps the values read previously with a translation which is inside a dict called definicoes
(definicoes[english] = translation
), with the previous example, then saves the file. So from our previous example definicoes["Pages Accessibility"] = "Acessibilidade de Páginas"
. The xml file would become:
<data name="AccessibilityTitleResource1.Text" xml:space="preserve">
<value>Acessibilidade de Páginas</value>
The third function simply checks if the xml file is fully translatable, so it checks all the values <value>
tags inside the <data>
ones against the ones in the dict, if there is any value not present on the dict it returns False.
Here are the three functions:
def ler_todos(caminho) -> set:
definicoes = set()
for file in os.listdir(caminho):
if file.endswith(".ascx.resx") or file.endswith(".aspx.resx"):
tree = ET.parse(caminho + file)
root = tree.getroot()
for child in root.iter('data'):
if child.attrib.get('namespace') == 'preserve':
node = child[0]
if node.tag == "value" and node.text != None and not node.text in definicoes:
definicoes.add(node.text)
return definicoes
def escrever_arquivo(definicoes, caminho):
if caminho.endswith(".pt.resx"):
tree = ET.parse(caminho)
root = tree.getroot()
for child in root.iter('data'):
if child.attrib.get('namespace') == 'preserve':
node = child[0]
if node.tag == "value" and node.text != None and node.text in definicoes:
node.text = definicoes[node.text]
tree.write(caminho, encoding="UTF-8")
anexar_cabecalho(caminho)
def existe_traducao(definicoes, caminho):
if caminho.endswith(".resx"):
tree = ET.parse(caminho)
root = tree.getroot()
for child in root.iter('data'):
if child.attrib.get('namespace') == 'preserve':
node = child[0]
if node.tag == "value" and node.text != None and len(node.text) > 0 and node.text not in definicoes:
return False
return True
1 Answer 1
One of the possible ways to improve on following the DRY principle would be to extract the XML tree iteration part which is the same in all 3 functions. Something like this generator:
def values(tree):
root = tree.getroot()
for child in root.iter('data'):
if child.attrib.get('namespace') == 'preserve':
node = child[0]
if node.tag == "value" and node.text is not None:
yield node
Then, you can use it this way:
tree = ET.parse(caminho)
for node in values(tree):
# do something with node
ResourceFile.pt_PT.resx
\$\endgroup\$