2014-11-06 1 views
0

У меня есть два файла XML, которые я пытаюсь объединить. Я посмотрел на другие предыдущие вопросы, но я не чувствую, что могу решить свою проблему, читая их. Я считаю, что моя ситуация уникальна в том, что мне приходится находить элементы по значению атрибута, а затем сливаться в противоположный файл.Объединить два файла XML с помощью сопоставления элементов по значению атрибута

У меня есть два файла. Один из них - английский переводческий каталог, а второй - японский каталог переводов. Просьба см. Ниже.

В приведенном ниже коде вы увидите, что в XML есть три элемента, с которыми я буду объединять детей: MessageCatalogueEntry, MessageCatalogueFormEntry и MessageCatalogueFormItemEntry. У меня есть сотни файлов, и каждый файл имеет тысячи строк. Может быть больше элементов, чем те, которые я только что перечислил, но я точно знаю, что все элементы имеют «ключевой» атрибут.

Мой план:

  • Итерация через File 1 и создать список всех значений «ключа» атрибута.
    • В этом примере список будет key_values = [321, 260, 320]
  • Далее, я пойду через key_value список один за другим.
  • Я буду искать файл 1 для элемента с атрибутом key=321.
  • Далее, возьмите ребенка элемента с key=321 из файла 1.
  • Далее в файле 2, найти элемент с key=321 и добавить дочерний элемент Я ранее захваченный из файла 1.
  • Далее я буду продолжить тот же цикл процесса через список key_values.
  • Далее я напишу новый корень xml в файл, чтобы сохранить кодировку utf8.

Файл 1:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE MessageCatalogue []> 
<PackageEntry> 
    <MessageCatalogue designNotes="Undefined" isPrivate="false" lastKey="362" name="AddKMRichSearchEngineAdmin_AutoTranslationCatalogue" nested="false" version="3.12.0"> 
     <MessageCatalogueEntry key="321"> 
     <MessageCatalogueEntry_loc locale="" message="active"/> 
     </MessageCatalogueEntry> 
     <MessageCatalogueFormEntry key="260"> 
     <MessageCatalogueFormEntry_loc locale="" shortTitle="Configuration" title="Spider Configuration"/> 
     </MessageCatalogueFormEntry> 
     <MessageCatalogueFormItemEntry key="320"> 
     <MessageCatalogueFormItemEntry_loc hintText="" label="Manage Recognised Phrases" locale="" mnemonic="" scriptText=""/> 
     </MessageCatalogueFormItemEntry> 
    </MessageCatalogue> 
    </PackageEntry> 

Файл 2:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE MessageCatalogue[]> 
<PackageEntry> 
    <MessageCatalogue designNotes="Undefined" isPrivate="false" lastKey="362" name="" nested="false" version="3.12.0"> 
    <MessageCatalogueEntry key="321"> 
     <MessageCatalogueEntry_loc locale="ja" message="アクティブ" /> 
    </MessageCatalogueEntry> 
    <MessageCatalogueFormEntry key="260"> 
     <MessageCatalogueFormEntry_loc locale="ja" shortTitle="設定" title="Spider Configuration/スパイダー設定" /> 
    </MessageCatalogueFormEntry> 
    <MessageCatalogueFormItemEntry key="320"> 
     <MessageCatalogueFormItemEntry_loc hintText="" label="認識されたフレーズを管理" locale="ja" mnemonic="" scriptText="" /> 
    </MessageCatalogueFormItemEntry> 
    </MessageCatalogue> 
</PackageEntry> 

Выход:

<?xml version="1.0" encoding="utf-8"?> 
<!DOCTYPE MessageCatalogue []> 
<PackageEntry> 
    <MessageCatalogue designNotes="Undefined" isPrivate="false" lastKey="362" name="AddKMRichSearchEngineAdmin_AutoTranslationCatalogue" nested="false" version="3.12.0"> 
     <MessageCatalogueEntry key="321"> 
     <MessageCatalogueEntry_loc locale="" message="active"/> 
     <MessageCatalogueEntry_loc locale="ja" message="アクティブ" /> 
     </MessageCatalogueEntry> 
     <MessageCatalogueFormEntry key="260"> 
     <MessageCatalogueFormEntry_loc locale="" shortTitle="Configuration" title="Spider Configuration"/> 
     <MessageCatalogueFormEntry_loc locale="ja" shortTitle="設定" title="Spider Configuration/スパイダー設定" /> 
     </MessageCatalogueFormEntry> 
     <MessageCatalogueFormItemEntry key="320"> 
     <MessageCatalogueFormItemEntry_loc hintText="" label="Manage Recognised Phrases" locale="" mnemonic="" scriptText=""/> 
     <MessageCatalogueFormItemEntry_loc hintText="" label="認識されたフレーズを管理" locale="ja" mnemonic="" scriptText="" /> 
     </MessageCatalogueFormItemEntry> 
    </MessageCatalogue> 
    </PackageEntry> 

У меня возникли проблемы просто даже захватывая элементы, фигу, захватывая их с помощью ключа стоимость. Например, я играл с библиотекой ElementTree, и я написал этот код в надежде получить только MessageCatalogueEntry, но я получаю только своих детей:

from xml.etree import ElementTree as et 

tree_japanese = et.parse('C:\\blah\\blah\\blah\\AddKMRichSearchEngineAdmin_AutoTranslationCatalogue_JA.xml') 
root_japanese = tree_japanese.getroot() 
MC_japanese = root_japanese.findall("MessageCatalogue") 

for x in MC_japanese: 
    messageCatalogueEntry = x.findall("MessageCatalogueEntry") 
    for m in messageCatalogueEntry: 
     print et.tostring(m[0], encoding='utf8') 

tree_english = et.parse('C:\\blah\\blah\\blah\\AddKMRichSearchEngineAdmin\\AddKMRichSearchEngineAdmin_AutoTranslationCatalogue.xml') 
root_english = tree_english.getroot() 
MC_english = root_english.findall("MessageCatalogue") 

for x in MC_english: 
    messageCatalogueEntry = x.findall("MessageCatalogueEntry") 
    for m in messageCatalogueEntry: 
     print et.tostring(m[0], encoding='utf8') 

Любая помощь будет оценена. Я занимаюсь этим уже несколько рабочих дней, и я не ближе к финишу, чем когда был, когда начал!

ответ

2

Фактически вы получаете сообщение MessageCatalogEntry. Проблема заключается в заявлении печати. Элемент действует как список, поэтому m[0] является первым дочерним элементом MessageCatalogEntry. В

messageCatalogueEntry = x.findall("MessageCatalogueEntry") 
for m in messageCatalogueEntry: 
    print et.tostring(m[0], encoding='utf8') 

изменить печать на print et.tostring(m, encoding='utf8'), чтобы увидеть правый элемент.

Я лично предпочитаю lxml для elementtree. Предполагая, что вы хотите связать записи с помощью атрибута «ключ», вы можете использовать xpath для индексации одного из документов, а затем вывести их в другой документ.

import lxml.etree 

tree_english = lxml.etree.parse('english.xml') 
tree_japanese = lxml.etree.parse('japanese.xml') 

# index the japanese catalog 
j_index = {} 
for catalog in tree_japanese.xpath('MessageCatalogue/*[@key]'): 
    j_index[catalog.get('key')] = catalog 

# find catalog entries in english and merge the japanese 
for catalog in tree_english.xpath('MessageCatalogue/*[@key]'): 
    j_catalog = j_index.get(catalog.get('key')) 
    if j_catalog is not None: 
     print 'found match' 
     for child in j_catalog: 
      print 'add one' 
      catalog.append(child) 

print lxml.etree.tostring(tree_english, pretty_print=True, encoding='utf8') 
+0

Спасибо! Это работает так, как мне было нужно. Я действительно ценю твою помощь. Я бы поднял тебя, но у меня недостаточно репутации. Я обязательно вернусь и сделаю это, когда я получу квалификацию.
Одна вещь, которую мне интересно, это то, что мои заголовки (см. Ниже), если это правильный термин, не выписываются. Это не очень важно, я просто напишу строки в файл, так как заголовок одинаковый для всех файлов, с которыми я работаю. Еще раз спасибо! – alfonso

+0

Да, lxml ожидает, что вы сами выведете заголовок. Я не помню всех подробностей. – tdelaney

+0

Мне было интересно, знаете ли вы о другом способе разбора? Следующий ниже код удаляет теги CDATA, которые мне нужны: tree_english = lxml.etree.parse ('english.xml'). Я проверил документацию и, видимо, вы можете хранить теги CDATA, но похоже, что они используют один и тот же метод для анализа. Документация здесь: http://lxml.de/2.1/api.html – alfonso