Объединить значение похожих тегов в один тег

Я пытался объединить значение аналогичного тега и получить вывод в виде одного тега, как показано ниже.

ввод XML:

<root>
    <data>
        <slide name="file.xml">
             <subtitle>Text1</subtitle> 
             <MainTitle>Text2</MainTitle> 
             <MainTitle>text3</MainTitle> 
         </slide>
        <slide name="file.xml">
             <Title>String1</Title> 
             <Title>String2</Title> 
             <Title>String3</Title> 
             <Title>String4</Title> 
             <Title>String5</Title> 
             <Title>String6</Title> 
             <Title>String7</Title> 
             <Title>String8</Title> 
         </slide>
     </data>
 </root>

Ожидаемый результат:

<root>
    <data>
        <slide name="file.xml">
             <subtitle>Text1</subtitle> 
             <MainTitle>Text2</MainTitle> 
             <MainTitle>text3</MainTitle> 
         </slide>
        <slide name="file.xml">
             <Title>String</Title>
        </slide>
     </data>
 </root>

Любая помощь могла бы быть полезна. благодарю вас!!

1 ответ

Решение

Вам нужно рекурсивно сгруппировать общие теги. Вот реализация, которая позволяет передать функцию, которая решает, что делать с текстом:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import itertools
import operator
import os.path

from lxml import etree


text = """
<root>
    <data>
        <slide name="file.xml">
             <subtitle>Text1</subtitle> 
             <MainTitle>Text2</MainTitle> 
             <MainTitle>text3</MainTitle> 
         </slide>
        <slide name="file.xml">
             <Title>String1</Title> 
             <Title>String2</Title> 
             <Title>String3</Title> 
             <Title>String4</Title> 
             <Title>String5</Title> 
             <Title>String6</Title> 
             <Title>String7</Title> 
             <Title>String8</Title> 
        </slide>
    </data>
</root>
"""


def combine_elements(elements, combine_text=', '.join):
    result = []
    for key, group in itertools.groupby(elements, operator.attrgetter('tag')):
        items = list(group)
        first_item = items[0]
        # combine only if item don't have children
        if len(items) > 1 and not len(first_item):
            combined = combine_text([el.text for el in items])
            # and if combine_text returned something, e.g. strings have 
            # common prefix
            if combined:
                first_item.text = combined
                result.append(first_item)
                continue
        result.extend(items)
    elements[:] = result
    # recursively combine others
    for element in elements:
        combine_elements(element, combine_text)


doc = etree.fromstring(text)
combine_elements(doc, os.path.commonprefix)
print etree.tostring(doc)

С помощью os.path.commonprefix() как объединитель текста, вы получите следующий результат:

<root>
    <data>
        <slide name="file.xml">
             <subtitle>Text1</subtitle> 
             <MainTitle>Text2</MainTitle> 
             <MainTitle>text3</MainTitle> 
         </slide>
        <slide name="file.xml">
             <Title>String</Title> 
             </slide>
    </data>
</root>

Если вы хотите, чтобы все тексты сочетались с косой чертой / (например) вы можете использовать следующее:

doc = etree.fromstring(text)
combine_elements(doc, ' / '.join)

Результат:

<root>
    <data>
        <slide name="file.xml">
             <subtitle>Text1</subtitle> 
             <MainTitle>Text2 / text3</MainTitle> 
             </slide>
        <slide name="file.xml">
             <Title>String1 / String2 / String3 / String4 / String5 / String6 / String7 / String8</Title> 
             </slide>
    </data>
</root>
Другие вопросы по тегам