2013-07-22 2 views
1

У меня есть файл txt, содержащий более 100 тысяч строк, и для каждой строки я хочу создать дерево XML. НО все строки имеют один и тот же корень.Создание файла xml с помощью Loop в python

Здесь TXT файл:

LIBRARY: 
1,1,1,1,the 
1,2,1,1,world 
2,1,1,2,we 
2,5,2,1,have 
7,3,1,1,food 

Нужный выход:

<LIBRARY> 
    <BOOK ID ="1"> 
     <CHAPTER ID ="1"> 
      <SENT ID ="1"> 
       <WORD ID ="1">the</WORD> 
      </SENT> 
     </CHAPTER> 
    </BOOK> 
    <BOOK ID ="1"> 
     <CHAPTER ID ="2"> 
      <SENT ID ="1"> 
       <WORD ID ="1">world</WORD> 
      </SENT> 
     </CHAPTER> 
    </BOOK> 
    <BOOK ID ="2"> 
     <CHAPTER ID ="1"> 
      <SENT ID ="1"> 
       <WORD ID ="2">we</WORD> 
      </SENT> 
     </CHAPTER> 
    </BOOK> 
    <BOOK ID ="2"> 
     <CHAPTER ID ="5"> 
      <SENT ID ="2"> 
       <WORD ID ="1">have</WORD> 
      </SENT> 
     </CHAPTER> 
    </BOOK> 
    <BOOK ID ="7"> 
     <CHAPTER ID ="3"> 
      <SENT ID ="1"> 
       <WORD ID ="1">food</WORD> 
      </SENT> 
     </CHAPTER> 
    </BOOK> 
</LIBRARY> 

Я использую дерево элементов для преобразования текстового файла в XML-файл, это код, я бегу

def expantree(): 
    lines = txtfile.readlines() 
    for line in lines: 
    split_line = line.split(',') 
    BOOK.set('ID ', split_line[0]) 
    CHAPTER.set('ID ', split_line[1]) 
    SENTENCE.set('ID ', split_line[2]) 
    WORD.set('ID ', split_line[3]) 
    WORD.text = split_line[4] 
    tree = ET.ElementTree(Root) 
    tree.write(xmlfile) 

Хорошо, код работает, но я не получил желаемый результат, я получил следующее:

<LIBRARY> 
    <BOOK ID ="1"> 
     <CHAPTER ID ="1"> 
      <SENT ID ="1"> 
       <WORD ID ="1">the</WORD> 
      </SENT> 
     </CHAPTER> 
    </BOOK> 
</LIBRARY> 
<LIBRARY> 
    <BOOK ID ="1"> 
     <CHAPTER ID ="2"> 
      <SENT ID ="1"> 
       <WORD ID ="1">world</WORD> 
      </SENT> 
     </CHAPTER> 
    </BOOK> 
</LIBRARY> 
<LIBRARY> 
    <BOOK ID ="2"> 
     <CHAPTER ID ="1"> 
      <SENT ID ="1"> 
       <WORD ID ="2">we</WORD> 
      </SENT> 
     </CHAPTER> 
    </BOOK> 
</LIBRARY> 
<LIBRARY> 
    <BOOK ID ="2"> 
     <CHAPTER ID ="5"> 
      <SENT ID ="2"> 
       <WORD ID ="1">have</WORD> 
      </SENT> 
     </CHAPTER> 
    </BOOK> 
</LIBRARY> 
<LIBRARY> 
    <BOOK ID ="7"> 
     <CHAPTER ID ="3"> 
      <SENT ID ="1"> 
       <WORD ID ="1">food</WORD> 
      </SENT> 
     </CHAPTER> 
    </BOOK> 
</LIBRARY> 

Как объединить корень дерева, поэтому вместо получения большого корневого тега я получаю один корневой тег?

ответ

0

Одним из способов было бы создать полное дерево и распечатать его. Я использовал следующий код:

from lxml import etree as ET 

def create_library(lines): 
    library = ET.Element('LIBRARY') 
    for line in lines: 
     split_line = line.split(',') 
     library.append(create_book(split_line)) 
    return library 

def create_book(split_line): 
    book = ET.Element('BOOK',ID=split_line[0]) 
    book.append(create_chapter(split_line)) 
    return book 

def create_chapter(split_line): 
    chapter = ET.Element('CHAPTER',ID=split_line[1]) 
    chapter.append(create_sentence(split_line)) 
    return chapter 

def create_sentence(split_line): 
    sentence = ET.Element('SENT',ID=split_line[2]) 
    sentence.append(create_word(split_line)) 
    return sentence 

def create_word(split_line): 
    word = ET.Element('WORD',ID=split_line[3]) 
    word.text = split_line[4] 
    return word 

Тогда ваш код, чтобы создать файл будет выглядеть следующим образом:

def expantree(): 
    lines = txtfile.readlines() 
    library = create_library(lines) 
    ET.ElementTree(lib).write(xmlfile) 

Если вы не хотите, чтобы загрузить все дерево в памяти (вы упомянули там больше чем 100 тысяч строк), вы можете вручную создать тег, написать каждую книгу по одному, а затем добавить тег. В этом случае ваш код будет выглядеть следующим образом:

def expantree(): 
    lines = txtfile.readlines() 
    f = open(xmlfile,'wb') 
    f.write('<LIBRARY>') 
    for line in lines: 
     split_line = line.split(',') 
     book = create_book(split_line) 
     f.write(ET.tostring(book)) 
    f.write('</LIBRARY>') 
    f.close() 

Я не имею много опыта с LXML, так что может быть более изящными решения, но оба этих работ.

+0

спасибо, ваш ответ ценный –

+0

Рад, что я мог помочь. –

1

Другой вариант, который, возможно, более емким выглядит следующим образом:

from xml.etree import ElementTree as ET 
import io 
import os 

# Setup the test input 
inbuf = io.StringIO(''.join(['LIBRARY:\n', '1,1,1,1,the\n', '1,2,1,1,world\n', 
          '2,1,1,2,we\n', '2,5,2,1,have\n', '7,3,1,1,food\n'])) 

tags = ['BOOK', 'CHAPTER', 'SENT', 'WORD'] 
with inbuf as into, io.StringIO() as xmlfile: 
    root_name = into.readline() 
    root = ET.ElementTree(ET.Element(root_name.rstrip(':\n'))) 
    re = root.getroot() 
    for line in into: 
     values = line.split(',') 
     parent = re 
     for i, v in enumerate(values[:4]): 
      parent = ET.SubElement(parent, tags[i], {'ID': v}) 
      if i == 3: 
       parent.text = values[4].rstrip(':\n') 
    root.write(xmlfile, encoding='unicode', xml_declaration=True) 
    xmlfile.seek(0, os.SEEK_SET) 
    for line in xmlfile: 
     print(line) 

Что делает этот код, чтобы построить ElementTree из входных данных и записать его в файл-подобный объект в виде файла XML. Этот код будет работать либо со стандартным пакетом Python xml.etree, либо с lxml. Код был протестирован с использованием Python 3.3.

1

Вот предложение, которое использует lxml (проверено на Python 2.7). Код может быть легко адаптирован для работы с ElementTree, но сложнее получить красивую печатную версию (см. https://stackoverflow.com/a/16377996/407651 для получения дополнительной информации об этом).

Входной файл - library.txt, а выходной файл - library.xml.

from lxml import etree 

lines = open("library.txt").readlines() 
library = etree.Element('LIBRARY') # The root element 

# For each line with data in the input file, create a BOOK/CHAPTER/SENT/WORD structure 
for line in lines: 
    values = line.split(',') 
    if len(values) == 5: 
     book = etree.SubElement(library, "BOOK") 
     book.set("ID", values[0]) 
     chapter = etree.SubElement(book, "CHAPTER") 
     chapter.set("ID", values[1]) 
     sent = etree.SubElement(chapter, "SENT") 
     sent.set("ID", values[2]) 
     word = etree.SubElement(sent, "WORD") 
     word.set("ID", values[3]) 
     word.text = values[4].strip() 

etree.ElementTree(library).write("library.xml", pretty_print=True) 
+1

Я поддерживал, но поскольку SubElement позволяет устанавливать атрибуты как в 'book = etree.SubElement (библиотека, 'BOOK', ID = values ​​[0])', операции set() могут быть устранены. – tdelaney

Смежные вопросы