Найти - Пользователи
Полная версия: Создание xml
Начало » Python для новичков » Создание xml
1 2
SHDW
Итак есть входные данные в виде текстовика типа
ThreadDiam.	Pitch	HoleDiam.	M	DESC_IN_DRAFTING
2mm	0,4mm	1,567mm	M2	
2,5mm	0,45mm	2,013mm	M2,5	
3mm	0,5mm	2,459mm	M3	
4mm	0,7mm	3,242mm	M4	 
есть формат выходных данных типа
<?xml version="1.0" ?>
<!-- -->
<!-- ******************************************************************* -->
<!-- *         Standard Metric_Thin_Pitch                              * -->
<!-- ******************************************************************* -->
	  
<std:node name="Thread_standard" xmlns:std="http://www.dsweb.com/std">
	<std:node name="Key">
		<std:strval name="Key">M</std:strval>
		<std:strval name="KeyDrafting">NO_DESC_IN_DRAFTING</std:strval>
	</std:node>
  <std:typedef name="Standard">
    <std:floatval name="ThreadDiameter">0.0</std:floatval>
    <std:floatval name="Pitch">1.0</std:floatval>
    <std:floatval name="NominalDiameter">0.13</std:floatval>
    <std:strval name="Description">M8</std:strval>
  </std:typedef>
  
  <std:node name="Values">
    <std:typeval name="Standard">
      <std:floatval name="ThreadDiameter">8.0</std:floatval>
      <std:floatval name="Pitch">1.0</std:floatval>
      <std:floatval name="NominalDiameter">6.917</std:floatval>
      <std:strval name="Description">M8x1</std:strval>
    </std:typeval>
    
    <std:typeval name="Standard">
      <std:floatval name="ThreadDiameter">10.0</std:floatval>
      <std:floatval name="Pitch">1.0</std:floatval>
      <std:floatval name="NominalDiameter">8.917</std:floatval>
      <std:strval name="Description">M10x1</std:strval>
    </std:typeval>
    <std:typeval name="Standard">
      <std:floatval name="ThreadDiameter">10.0</std:floatval>
      <std:floatval name="Pitch">1.25</std:floatval>
      <std:floatval name="NominalDiameter">8.647</std:floatval>
      <std:strval name="Description">M10x1.25</std:strval>
    </std:typeval>
        
    </std:node>
</std:node>
Написал маленький конвертер
# -*- coding: utf-8 -*-
'''
Утилита для переноса стандартов резьбы.
Разработана и оттестирована на Catia V5R22sp3
ThreadConverter.py input_file output_file dots_flag
\tinput_file -\tпуть с указанием файла для конвертации,
\t\t\tформат файла текстовый, кодировка не принципиальна,
\t\t\tрасширение тоже.
\toutput_file -\tпуть с указанием файла для записи,
\t\t\tформат файла xml.
\tdots_flag-\tTrue or False
\t\t\tЗамена decimal separator в output_file
\t\t\tif dots_flag:
\t\t\t\tdecimal separator = '.'
\t\t\telse:
\t\t\t\tdecimal separator = ','
Тестировалось на CatiaV5R22.
Конвертировались стандарты с сайта http://www.plm-forum.ru/forum/
Created on 13.02.2013
@author: Бирюков
'''
from sys import argv
from sys import exit
try:
    i_file, o_file, dots = argv[1:]
except ValueError:
    print(__doc__)
    print('Неверно заданы аргументы!')
    input('Press any key to exit...')
    exit('Terminated...')
ppprint = False
try:
    from lxml import etree as etree
    print('from lxml import etree as etree')
    ppprint = True
except ImportError:
    try:
        from xml.etree import cElementTree as etree
        print('from xml.etree import cElementTree as etree')
        ppprint = False
    except ImportError:
        try:
            from xml.etree import ElementTree as etree
            print('from xml.etree import ElementTree as etree')
            ppprint = False
        except ImportError:
            exit('Импортирование провалилось.\nИсправьте зависимости!')
class SameFileExeption(Exception):
    '''
    Простой класс для ошибок.
    Пока не используется;)
    '''
    def __str__(self, *args, **kwargs):
        return repr(self.value)
    def __init__(self, msg):
        self.value = msg
class ThreadConverterClass:
    '''
    Зависимости: lxml, возможно будет работать без оной, не тестировалось
    Класс для конвертирования стандарта резьбы в стиле CatiaV5R20 и более
    ранних релизов в стандарт CatiaV5R21 и старше,
    включая, предположительно, V6.
    input_file -\tпуть с указанием файла для конвертации,
    \tinput_file -\tпуть с указанием файла для конвертации,
    \t\t\tформат файла текстовый, кодировка не принципиальна,
    \t\t\tрасширение тоже.
    \toutput_file -\tпуть с указанием файла для записи,
    \t\t\tформат файла xml.
    \tdots_flag-\tTrue or False
    \t\t\tЗамена decimal separator в output_file
    \t\t\tif dots_flag:
    \t\t\t\tdecimal separator='.'
    \t\t\telse:
    \t\t\t\tdecimal separator=','
    Тестировалось на CatiaV5R22.
    Конвертировались стандарты с сайта http://www.plm-forum.ru/forum/
    '''
    # input_file = 'input_file.txt'
    # output_file = 'output_file.xml'
    # enable_dots = True
    def eq_block(self, elem, name_spase, T, P, N, D):
        sub_elem = etree.SubElement(elem, name_spase + 'floatval')
        sub_elem.set('name', 'ThreadDiameter')
        sub_elem.text = T
        sub_elem = etree.SubElement(elem, name_spase + 'floatval')
        sub_elem.set('name', 'Pitch')
        sub_elem.text = P
        sub_elem = etree.SubElement(elem, name_spase + 'floatval')
        sub_elem.set('name', 'NominalDiameter')
        sub_elem.text = N
        sub_elem = etree.SubElement(elem, name_spase + 'strval')
        sub_elem.set('name', 'Description')
        sub_elem.text = D
        return
    def typedef_block(self, elem, name_spase, T, P, N, D):
        sub_elem = etree.SubElement(elem, name_spase + 'typedef')
        sub_elem.set('name', 'Standard')
        self.eq_block(sub_elem, name_spase, T, P, N, D)
        return
    def typeval_block(self, elem, name_spase, T, P, N, D):
        sub_elem = etree.SubElement(elem, name_spase + 'typeval')
        sub_elem.set('name', 'Standard')
        self.eq_block(sub_elem, name_spase, T, P, N, D)
        return
    def ThreadStdGenerator(self, input_file, output_file, enable_dots=True):
        # получение имени выходного файла
        # output_file = input_file[:-4] + '.xml'
        # XML_NAMESPACE
        XML_NAMESPACE = 'http://www.dsweb.com/std'
        # PREFIX
        PREFIX = '{%s}' % XML_NAMESPACE
        # NSMAP не стандарт
        NSMAP = {'std': XML_NAMESPACE}
        # lxml only!
        xml_root = etree.Element(PREFIX + 'node', nsmap=NSMAP)
        xml_root.set('name', 'Thread_standard')
        #======================================================================
        # <std:node name="Key">
        #    <std:strval name="Key">M</std:strval>
        #    <std:strval name="KeyDrafting">NO_DESC_IN_DRAFTING</std:strval>
        # </std:node>
        #======================================================================
        block_key = etree.SubElement(xml_root, PREFIX + 'node')
        # <std:node name="Key">
        block_key.set('name', 'Key')
        # <std:strval name="Key">M</std:strval>
        block_key_subkey = etree.SubElement(block_key, PREFIX + 'strval')
        block_key_subkey.set('name', 'Key')
        block_key_subkey.text = 'M'
        # <std:strval name="KeyDrafting">NO_DESC_IN_DRAFTING</std:strval>
        block_key_draft = etree.SubElement(block_key, PREFIX + 'strval')
        block_key_draft.set('name', 'KeyDrafting')
        block_key_draft.text = 'NO_DESC_IN_DRAFTING'
        #======================================================================
        # <std:typedef name="Standard">
        #  <std:floatval name="ThreadDiameter">0.0</std:floatval>
        #  <std:floatval name="Pitch">1.0</std:floatval>
        #  <std:floatval name="NominalDiameter">0.13</std:floatval>
        #  <std:strval name="Description">M8</std:strval>
        # </std:typedef>
        #======================================================================
        self.typedef_block(xml_root, PREFIX, '0.0', '1.0', '0.13', 'M8')
        block_value_data = etree.SubElement(xml_root, PREFIX + 'node')
        block_value_data.set('name', 'Values')
        with open(input_file, 'r') as f_input:
            data_lines = f_input.readlines()
            data_header_std = ['ThreadDiam',
                               'Pitch',
                               'HoleDiam',
                               'Minordiam',
                               'M']
            rslt = False
        for txt in data_header_std:
            if txt in data_lines[0]:
                rslt = True
            else:
                rslt = False
        if rslt:
            data_lines.remove(data_lines[0])
        else:
            print("Нет заголовка")
        for line in data_lines:
            if enable_dots:
                line = line.replace(',', '.')
                ln = line.split('\t')
            self.typeval_block(block_value_data, PREFIX,
                               ln[0], ln[1],
                               ln[2], ln[3])
        with open(output_file, 'wb') as f_output:
            b_comment = etree.Comment(text='*' * 20)
            if ppprint:
                f_output.write(etree.tostring(xml_root,
                                              pretty_print=True,
                                              encoding='utf-8',
                                              xml_declaration=True,
                                              doctype=b_comment.__str__()
                                              )
                               )
            else:
                etree.ElementTree(xml_root).write(output_file,
                                                  encoding='utf-8',
                                                  xml_declaration=True,
                                                  method='xml'
                                                  )
        return
    def __init__(self,
                 input_file='.txt',
                 output_file='.xml',
                 enable_dots=True):
        '''
        Constructor
        '''
        self.input_file = input_file
        self.output_file = output_file
        self.enable_dots = enable_dots
        self.ThreadStdGenerator(self.input_file,
                                self.output_file,
                                self.enable_dots
                                )
if __name__ == '__main__':
    print('Script: '+argv[0])
    if i_file == o_file:
        exit('Входной и выходной файлы должны различаться!\nTerminated....')
        input('>>>')
    print('input_data=', i_file)
    print('output_data=', o_file)
    try:
        ThreadConverterClass(i_file, o_file, dots)
        print('Конвертация прошла успешно!')
        input('Press any key to exit...')
    except:
        exit('Конвертация не удалась!')
        input('Press any key to exit...')
Вопросы:
1. как вывести коммент
<!-- -->
<!-- ******************************************************************* -->
<!-- *         Standard Metric_Thin_Pitch                              * -->
<!-- ******************************************************************* -->
2. тк новичек в python приму ллюбую критику
SHDW
PS:Еще не реализованная функция- при изменении аргументов класса пересчитывать выходные данные
реализовать функцию записи данных класса.

сожно сказать это моя первая более менее работающая программа, Класс задумал больше для тренировки, чем для надобности
reclosedev
SHDW
1. как вывести коммент
etree.Comment()
но тут хитрость в том, что он перед корневым элементом:
root = ...
comments = (
"""*******************************************************************
*         Standard Metric_Thin_Pitch                              *
*******************************************************************"""
)
for line in comments.splitlines():
    root.addprevious(etree.Comment(line))
SHDW
2. тк новичек в python приму ллюбую критику
Посмотрите в сторону http://lxml.de/api/lxml.builder.ElementMaker-class.html
Код с ним получается короче, так как не нужно писать префиксы и можно задавать атрибуты и значения в конструкторе. А с помощью функций-помощников выходит почти в декларативном стиле:
# -*- coding: utf-8 -*-
from lxml import etree
from lxml.builder import ElementMaker
 
XML_NAMESPACE = 'http://www.dsweb.com/std'
NSMAP = {'std': XML_NAMESPACE}
E = ElementMaker(namespace=XML_NAMESPACE, nsmap=NSMAP)
 
 
def A(node, *children):
    """ Добавляет дочерние элементы к `node`
    возвращает `node`
    """
    if len(children) == 1 and isinstance(children[0], (list, tuple)):
        children = children[0]
    for child in children:
        node.append(child)
    return node
 
 
def eq_block(T, P, N, D):
    return (
        E.floatval(T, name='ThreadDiameter'),
        E.floatval(P, name='Pitch'),
        E.floatval(N, name='NominalDiameter'),
        E.strval(D, name='Description'),
    )
 
root = (
    A(E.node(name='Thread_standard'),
        A(E.node(name='Key'), 
            E.strval('M', name='Key'),
            E.strval('NO_DESC_IN_DRAFTING', name='KeyDrafting'),
        ),
        A(E.typedef(name="Standard"), eq_block('0.0', '1.0', '0.13', 'M8')),
        A(E.node(name="Values"),
            # вместо этих двух записей - генератор значений из файла
            A(E.typeval(name="Standard"), eq_block('0.0', '1.0', '0.13', 'M8')),
            A(E.typeval(name="Standard"), eq_block('0.0', '1.0', '0.13', 'M8')),
        )
    )   
)
tree = etree.ElementTree(root)
comments = (
"""*******************************************************************
*         Standard Metric_Thin_Pitch                              *
*******************************************************************"""
)
for line in comments.splitlines():
    root.addprevious(etree.Comment(line))
print(etree.tostring(tree, pretty_print=True,
                     xml_declaration=True, encoding='utf-8'))
Для данной задачи, вместо ElementTree библиотеки подошел бы шаблонизатор, например, Jinja2. Так как никаких операций с деревом здесь не производится.

SHDW
Еще не реализованная функция- при изменении аргументов класса пересчитывать выходные данные
реализовать функцию записи данных класса.
Не совсем понятно, чего хотите добиться. Но если бы для чтения данных, создания дерева и сохранения дерева в файл были отдельные функции (и генераторы), было бы проще.
SHDW
Посмотрите в сторону http://lxml.de/api/lxml.builder.ElementMaker-class.html
Код с ним получается короче, так как не нужно писать префиксы и можно задавать атрибуты и значения в конструкторе. А с помощью функций-помощников выходит почти в декларативном стиле:
очень интересное решение, не нашел по первой в документации про префиксы…и второе мой код работает впринципе и без lxml, что для конечного пользователя лучше.
Соглашусь, что вы правы, используя функции было бы короче,но я решил потренироваться на
кошках классах.
идея такая:
for f in filelist:
   a =class(file)
   if a.result_status:
       a.write()
Как видите- класс не нужен(просто я так захотел, с функциями я уже немного могу оперировать, а вот с классами мало работал) можно просто использовать функцию которая будет возвращать None или данные. потом просто запись в файл.
спасибо про append. попробую.
PS файлов несколько не более десятка,с кол-вом строчек до тысячи, лежат в одной директории
Скрипт нужен для их форматирования и последующего копирования в другую директорию.
reclosedev
SHDW
Соглашусь, что вы правы, используя функции было бы короче,но я решил потренироваться на
кошках классах.
Я имел ввиду не отказ от классов (хотя здесь без них спокойно можно обойтись), а разделение метода ThreadStdGenerator() на несколько.

SHDW
и второе мой код работает впринципе и без lxml, что для конечного пользователя лучше.
Согласен. Но с другой стороны, Catia это ведь для Windows? А для конечного пользователя win удобнее exe, сделанный cx_freeze или подобным.
SHDW
reclosedev
Согласен. Но с другой стороны, Catia это ведь для Windows? А для конечного пользователя win удобнее exe, сделанный cx_freeze или подобным.
последнее время да, но есть unix версии и пара других поддерживаемых платформ
Задам несколько вопросов больше, по языку, чем связанного с созданием xml
есть функция
def foo(bar)
    bar=4
    return
Правильно ли я понимаю, что внутрь функции передается экземпляр переменной. А над самой и все действия производится над переменной и после выхода из функции экземпляр уничтожается?
и второе
isinstance(children[0], (list, tuple))
А эта функциЯ проверяет является ли children списком или кортежем?
reclosedev
SHDW
Правильно ли я понимаю, что внутрь функции передается экземпляр переменной. А над самой и все действия производится над переменной и после выхода из функции экземпляр уничтожается?
Сначала советую прочитать про типы в wiki
Все объекты делятся на ссылочные и атомарные. К атомарным относятся int, long, complex и некоторые другие. При присваивании атомарных объектов копируется их значение, в то время как для ссылочных копируется только указатель на объект, таким образом, обе переменные после присваивания используют одно и то же значение. Ссылочные объекты бывают изменяемые и неизменяемые. Например, строки и кортежи являются неизменяемыми, а списки, словари и многие другие объекты — изменяемыми. Кортеж в Питоне является, по сути, неизменяемым списком.
и еще про ссылки

Передается ссылка на объект (в случае с атомарными типами - ссылка на копию объекта). Запись bar = 4 означает, что переменная с именем bar теперь содержит ссылку на 4, а не на то что было передано. При выходе из функции ссылка удаляется.

SHDW
А эта функциЯ проверяет является ли children списком или кортежем?
http://docs.python.org/3.3/library/functions.html#isinstance
Да (только
children[0]
, возможно парсер съел).
SHDW
reclosedev
Сначала советую прочитать про типы в wiki
Это стало понятно, просто в разных языках по разному называются, хотя смысл одинаковый.
Основное понятно,подробности выяснятся на практике)
PS в lxml.etree коментарий перед деревом можно записать двумя способами: первый через addprevious как показано в примере выше,
второй через указание строки в etree.tostring( …,doctype='строка перед деревом')
GaiveR
При присваивании атомарных объектов копируется их значение, в то время как для ссылочных копируется только указатель на объект, таким образом, обе переменные после присваивания используют одно и то же значение.

Разве копируются?

>>> a = 5
>>> b = a
>>> id(a)
507081344
>>> id(b)
507081344
>>> id(5)
507081344

Всегда считал так:
Всё есть объект. Объекты бывают изменяемые и неизменяемые. Переменная = указатель на объект. Операция присваивания изменяет указатель, но не трогает сам объект.
SHDW
Все узнается опытным путем:) как обычно одним словом.
Заметь, если ты изменишь а, b не изменится, те его значение скопировалось.
Но если подобное сделать со списком, то ситуация буден несколько иной, покрайней мере в 3 версии
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB