2013-04-30 2 views
0

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

ввод 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> 

Любая помощь будет очень ценна. Спасибо!!

+0

Как вы хотите получить String со всех входов - возьмите первую или общую часть? – Mark

ответ

0

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

#!/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> 
Смежные вопросы