Чтение файла CSV и замена тега xml

Я хочу прочитать файл CSV и заменить теги в файле xml вторым столбцом файла CSV. Значения тега «имя» находятся в первом столбце.

A         |    B

Value1    |    ValueX
Value2    |    ValueX
Value3    |    ValueY

Структура XML выглядит так.

<products>
   <product>
      <name>Value1</name>
   </product>
   <product>
      <name>Values2</name>
   </product>
   <product>
      <name>Values3</name>
   </product>
</products>

Код Python

import csv 
import collections
import xml.etree.ElementTree
tree = xml.etree.ElementTree.parse("jolly.xml").getroot()

with open('file.csv', 'r') as f:
    reader = csv.DictReader(f)# read rows into a dictionary format
    reader = csv.reader(f, dialect=csv.excel_tab)
    list = list(reader)
    columns = collections.defaultdict(list)# each value in each column is appended to a list

for (k, v) in row.items(): #go over each column name and value
    columns[k].append(v)# append the value into the appropriate list

print columns['A']
print columns['B']
for elem in tree.findall('.//name'):
    if elem.attrib['name'] == columns['A']:
        elem.attrib['name'] == columns['B']

Как я могу справиться с этим?

Вот как выглядит CSV-файл:

Чтение CSV-файла выглядит так

Вывод должен выглядеть так:

Value1 следует заменить на ValueX

Хорошо, вот мое решение:

import lxml.etree as ET


arr = ["Value1", "Value2", "Value3"]
arr2 = ["ValuX", "ValuX", "ValueY"]

with open('file.xml', 'rb+') as f:
    tree = ET.parse(f)
    root = tree.getroot()
    for i, item in enumerate(arr):
         for elem in root.findall('.//Value1'):
             print(elem);
             if elem.tag:
                 print(item)
                 print(arr2[i])

                 elem.text = elem.text.replace(item, arr2[i])



    f.seek(0)
    f.write(ET.tostring(tree, encoding='UTF-8', xml_declaration=True))
    f.truncate()

Ну, я использую массив. Я могу просто скопировать значения из файла в массив. Для огромных файлов нужен лучший код.


person Tony    schedule 30.12.2015    source источник
comment
Вы искали модули csv и ElementTree в документации Python? Какой код вы написали?   -  person barny    schedule 30.12.2015
comment
Отлично, у вас есть код. В чем проблема?   -  person barny    schedule 30.12.2015


Ответы (1)


Рассмотрите возможность использования XSLT, специального декларативного языка, предназначенного для реструктуризации XML-файлов. Как и большинство других языков общего назначения, включая ASP, C#, Java, PHP, Perl, VB, Python поддерживает процессор XSLT 1.0, особенно в его модуле lxml.

А для своих целей вы можете динамически создать строку XSLT, которую можно использовать для преобразования. Нужен только цикл через данные csv:

import csv
import lxml.etree as ET

# READ IN CSV DATA AND APPEND TO LIST
csvdata = []
with open('file.csv'), 'r') as csvfile:
    readCSV = csv.reader(csvfile)
    for line in readCSV:
        csvdata.append(line)

# DYNAMICALLY CREATE XSLT STRING
xsltstr = '''<xsl:transform xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
            <xsl:output version="1.0" encoding="UTF-8" indent="yes" />
            <xsl:strip-space elements="*"/>

              <!-- Identity Transform -->
              <xsl:template match="@*|node()">
                <xsl:copy>
                  <xsl:apply-templates select="@*|node()"/>
                </xsl:copy>
              </xsl:template>

        '''

for i in range(len(csvdata)):
    xsltstr = xsltstr + \
              '''<xsl:template match="name[.='{0}']">
                  <xsl:element name="{1}">
                     <xsl:apply-templates />
                  </xsl:element>
              </xsl:template>

              '''.format(*csvdata[i])

xsltstr = xsltstr + '</xsl:transform>'

# PARSE ORIGINAL FILE AND XSLT STRING
dom = ET.parse('jolly.xml')
xslt = ET.fromstring(xsltstr)

# TRANSFORM XML
transform = ET.XSLT(xslt)
newdom = transform(dom)

# OUTPUT FINAL XML (PRETTY PRINT)
tree_out = ET.tostring(newdom, encoding='UTF-8', pretty_print=True,  xml_declaration=True)

xmlfile = open('final.xml'),'wb')
xmlfile.write(tree_out)
xmlfile.close()

ВЫВОД

<?xml version='1.0' encoding='UTF-8'?>
<products>
  <product>
    <ValueX>Value1</ValueX>
  </product>
  <product>
    <ValueY>Value2</ValueY>
  </product>
  <product>
    <ValueZ>Value3</ValueZ>
  </product>
</products>
person Parfait    schedule 30.12.2015
comment
Привет, большое спасибо за вашу помощь. Я получаю следующую ошибку: Traceback (последний последний вызов): файл readCSVReplaceTags.py, строка 2, в «модуле» импортирует lxml.etree как ET ImportError: нет модуля с именем lxml.etree. Я установил lxml, но он не работает. Есть ли другой модуль, который я могу использовать таким же образом? - person Tony; 31.12.2015
comment
У вас не установлен lxml. Я установил lxml, но он не работает? Попробуйте переустановить pip install lxml и вам также понадобятся libxml2-dev и libxslt1-dev. См. публикацию SO. - person Parfait; 31.12.2015
comment
Я использую Mac OS X 10.11. - person Tony; 31.12.2015
comment
Трассировка (последний последний вызов): Файл readCSVReplaceTags.py, строка 11, в ‹module› для строки в readCSV: Файл /usr/local/Cellar/python3/3.5.1/Frameworks/Python.framework/Versions/3.5/lib /python3.5/codecs.py, строка 321, при декодировании (результат, потребление) = self._buffer_decode(data, self.errors, final) UnicodeDecodeError: кодек utf-8 не может декодировать байт 0xdf в позиции 33: недопустимый байт продолжения - person Tony; 31.12.2015
comment
В вашем CSV-файле есть специальные символы: акценты, элементы иностранного языка и т. д. Для которых может потребоваться кодировка. Опубликуйте реальные данные, чтобы мы могли видеть. Обратите внимание, что теги XML не должны иметь пробела и не должны начинаться с цифры. Итак, проверьте столбец B. - person Parfait; 31.12.2015
comment
jup У меня есть ü, ä и т. д... Как я могу расшифровать код? - person Tony; 31.12.2015
comment
Также возникает эта ошибка: Файл readCSVReplaceTags.py, строка 36, в ‹module› '''.format(*csvdata[i]) IndexError: индекс кортежа вне допустимого диапазона - person Tony; 31.12.2015
comment
Если вам не удалось импортировать, csvdata будет пустым. И даже если вы импортируете в Python, вы столкнетесь с проблемами кодирования в XML. Укажите тип кодировки в open() и в ET.tostring(). Из ваших опубликованных данных примера я уверяю вас, что этот ответ работает. - person Parfait; 31.12.2015
comment
Нет, это не работает. Файл readCSVReplaceTags.py, строка 33, в ‹module› '''.format(*csvdata[i]) IndexError: индекс кортежа вне допустимого диапазона. Если удалить .format(), то он работает без utf-8. Если я добавлю uft-8, то я получаю ответ (последний последний вызов): Файл readCSVReplaceTags.py, строка 6, в ‹module› с open('file.csv', 'r', 'utf-8') как csvfile: TypeError: требуется целое число (получен тип str) - person Tony; 31.12.2015
comment
Пожалуйста, опубликуйте фрагмент фактических данных. Есть что-то в данных, вызывающих эти проблемы. Любой символ [A-Za-z0-9] данных csv должен работать. Я могу только предполагать на данный момент. - person Parfait; 31.12.2015
comment
Смотрите первый пост от меня! спасибо - person Tony; 31.12.2015