Изменение элемента атрибута xml со значением дочернего элемента с помощью lxml - PullRequest
0 голосов
/ 03 мая 2018

У меня есть фрагмент XML, подобный этому:

<parent id="1">
    <child1>
        <child2>[content]I need to get[/content]Other text</child2>
    </child1>
</parent>

И я хотел бы добавить [content] "child1" в качестве атрибута в родительский элемент.

Получается что-то вроде этого:

<parent id="1" value = "I need to get">
    <child1>
        <child2>Other text</child2>
    </child1>
</parent>

У меня есть этот код, однако он не работает, так как похоже, что он только у первого ребенка и не переходит к следующему.

pattern = re.compile('[content](.*?)[/content]')
xml_parser = et.parse(str(xml_file))
root_xml = xml_parser.getroot()
translatable_elements = root_xml.xpath('//parent')
for element in translatable_elements:
    for child_element in element.iterchildren():
        if child_element.tag == 'child1':
            source_content = child_element.text
            value_str = pattern.match(source_content).group(1)
            element.attrib['value'] = value_str
            source_content = pattern.sub(source_content,'')
    tree = et.ElementTree(root_xml)
 tree.write(str(xml_file), encoding='utf-8', pretty_print=True)

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Другой вариант - вообще не использовать регулярные выражения и использовать простой xpath.

Поскольку вы сказали, что ваш XML - это фрагмент кода, я обернул его в элемент doc и добавил еще один parent, чтобы показать, что происходит, когда есть кратные значения.

Пример ...

Ввод XML (input.xml)

<doc>
    <parent id="1">
        <child1>
            <child2>[content]I need to get[/content]Other text</child2>
        </child1>
    </parent>
    <parent id="2">
        <child1>
            <child2>[content]I need to get this too[/content]More other text</child2>
        </child1>
    </parent>
</doc>

Python

from lxml import etree

tree = etree.parse("input.xml")

for parent in tree.xpath(".//parent"):
    child2 = parent.xpath("./child1/child2")[0]
    parent.attrib["value"] = child2.xpath("substring-before(substring-after(.,'[content]'),'[/content]')")
    child2.text = child2.xpath("substring-after(.,'[/content]')")

tree.write("output.xml")

Вывод (output.xml)

<doc>
    <parent id="1" value="I need to get">
        <child1>
            <child2>Other text</child2>
        </child1>
    </parent>
    <parent id="2" value="I need to get this too">
        <child1>
            <child2>More other text</child2>
        </child1>
    </parent>
</doc>
0 голосов
/ 03 мая 2018

Вам необходимо скомпилировать re с правильной экранированной строкой регулярного выражения. Кроме того, вы пытались получить текст из child1 вместо child2. Это должно быть примерно так:

import re
from lxml import etree

with open(path, 'r') as f:
    tree = etree.parse(f)

    pattern = re.compile(r'\[content\](.*?)\[\/content\]')
    root = tree.getroot()
    pars = root.xpath('//parent')

    for par in pars:
        for child1 in par.iterchildren('child1'):
            child2 = child1.getchildren()[0]
            val = pattern.match(child2.text).group(1)
            par.set('value', val)
            child2.text = pattern.sub('', child2.text)

    print(etree.tostring(tree, encoding='utf-8', pretty_print=True))
...