Уведомления

Группа в Telegram: @pythonsu

#1 Фев. 18, 2013 14:46:42

SHDW
От:
Зарегистрирован: 2011-11-07
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Создание xml

Итак есть входные данные в виде текстовика типа

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 приму ллюбую критику



Офлайн

#2 Фев. 18, 2013 14:52:14

SHDW
От:
Зарегистрирован: 2011-11-07
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Создание xml

PS:Еще не реализованная функция- при изменении аргументов класса пересчитывать выходные данные
реализовать функцию записи данных класса.

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



Офлайн

#3 Фев. 18, 2013 18:33:45

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Создание xml

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
Еще не реализованная функция- при изменении аргументов класса пересчитывать выходные данные
реализовать функцию записи данных класса.
Не совсем понятно, чего хотите добиться. Но если бы для чтения данных, создания дерева и сохранения дерева в файл были отдельные функции (и генераторы), было бы проще.

Отредактировано reclosedev (Фев. 18, 2013 18:39:11)

Офлайн

#4 Фев. 19, 2013 07:48:39

SHDW
От:
Зарегистрирован: 2011-11-07
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Создание xml

Посмотрите в сторону 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 файлов несколько не более десятка,с кол-вом строчек до тысячи, лежат в одной директории
Скрипт нужен для их форматирования и последующего копирования в другую директорию.



Офлайн

#5 Фев. 19, 2013 16:44:10

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Создание xml

SHDW
Соглашусь, что вы правы, используя функции было бы короче,но я решил потренироваться на
кошках классах.
Я имел ввиду не отказ от классов (хотя здесь без них спокойно можно обойтись), а разделение метода ThreadStdGenerator() на несколько.

SHDW
и второе мой код работает впринципе и без lxml, что для конечного пользователя лучше.
Согласен. Но с другой стороны, Catia это ведь для Windows? А для конечного пользователя win удобнее exe, сделанный cx_freeze или подобным.

Отредактировано reclosedev (Фев. 19, 2013 16:45:54)

Офлайн

#6 Фев. 21, 2013 15:02:26

SHDW
От:
Зарегистрирован: 2011-11-07
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Создание xml

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



Офлайн

#7 Фев. 21, 2013 17:10:37

reclosedev
От: Н.Новгород
Зарегистрирован: 2012-03-29
Сообщения: 870
Репутация: +  173  -
Профиль   Отправить e-mail  

Создание xml

SHDW
Правильно ли я понимаю, что внутрь функции передается экземпляр переменной. А над самой и все действия производится над переменной и после выхода из функции экземпляр уничтожается?
Сначала советую прочитать про типы в wiki
Все объекты делятся на ссылочные и атомарные. К атомарным относятся int, long, complex и некоторые другие. При присваивании атомарных объектов копируется их значение, в то время как для ссылочных копируется только указатель на объект, таким образом, обе переменные после присваивания используют одно и то же значение. Ссылочные объекты бывают изменяемые и неизменяемые. Например, строки и кортежи являются неизменяемыми, а списки, словари и многие другие объекты — изменяемыми. Кортеж в Питоне является, по сути, неизменяемым списком.
и еще про ссылки

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

SHDW
А эта функциЯ проверяет является ли children списком или кортежем?
http://docs.python.org/3.3/library/functions.html#isinstance
Да (только
children[0]
, возможно парсер съел).

Офлайн

#8 Фев. 22, 2013 08:54:41

SHDW
От:
Зарегистрирован: 2011-11-07
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Создание xml

reclosedev
Сначала советую прочитать про типы в wiki
Это стало понятно, просто в разных языках по разному называются, хотя смысл одинаковый.
Основное понятно,подробности выяснятся на практике)
PS в lxml.etree коментарий перед деревом можно записать двумя способами: первый через addprevious как показано в примере выше,
второй через указание строки в etree.tostring( …,doctype='строка перед деревом')



Офлайн

#9 Фев. 22, 2013 10:57:25

GaiveR
От:
Зарегистрирован: 2011-08-13
Сообщения: 122
Репутация: +  16  -
Профиль   Отправить e-mail  

Создание xml

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

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

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

Всегда считал так:
Всё есть объект. Объекты бывают изменяемые и неизменяемые. Переменная = указатель на объект. Операция присваивания изменяет указатель, но не трогает сам объект.



Офлайн

#10 Фев. 22, 2013 11:31:54

SHDW
От:
Зарегистрирован: 2011-11-07
Сообщения: 15
Репутация: +  0  -
Профиль   Отправить e-mail  

Создание xml

Все узнается опытным путем:) как обычно одним словом.
Заметь, если ты изменишь а, b не изменится, те его значение скопировалось.
Но если подобное сделать со списком, то ситуация буден несколько иной, покрайней мере в 3 версии



Отредактировано SHDW (Фев. 22, 2013 11:34:06)

Офлайн

Board footer

Модераторировать

Powered by DjangoBB

Lo-Fi Version