Найти - Пользователи
Полная версия: Коллеги, помогите правильно разобрать XML, вопрос скорее архитектурный
Начало » Python для экспертов » Коллеги, помогите правильно разобрать XML, вопрос скорее архитектурный
1
pmus
Дорогие коллеги-товарищи, очень нуждаюсь в помощи.

В Питоне я, в общем-то, новичок, но полюбил его сразу, и считаю его почти идеальным инструментом для решения моей задачи.

Пишу привод для торговли на бирже, и сейчас разбираю биржевые данные, которые приезжают в формате “почти” XML (без заголовка)

Данные примерно такие:
<securities><security secid="2326" active="true"><seccode>LK13500BE3</seccode><shortname>LKOH-6.13M140513CA 13500</shortname><decimals>0</decimals><market>4</market><sectype>OPT</sectype><opmask usecredit="no" bymarket="no" nosplit="no" immorcancel="no" cancelbalance="yes"/><minstep>1</minstep><lotsize>1</lotsize><point_cost>100</point_cost></security><security secid="2327" active="true"><seccode>RU000A0JTFZ1</seccode><shortname>СтаврКрай1</shortname><decimals>2</decimals><market>1</market><sectype>BOND</sectype><opmask usecredit="yes" bymarket="no" nosplit="yes" immorcancel="yes" cancelbalance="yes"/><minstep>0.01</minstep><lotsize>1</lotsize><point_cost>10</point_cost></security></securities>
<quotations><quotation secid="907"><accruedintvalue>0.00</accruedintvalue><closeprice>6510</closeprice><volatility>22.06</volatility><theoreticalprice>6790</theoreticalprice><buydeposit>9397.46</buydeposit><selldeposit>5328.24</selldeposit></quotation></quotations>

Код такой:

#coding=utf8
import sqlite3
import xml.etree.cElementTree as ET
## now parse
encs = '<?xml version="1.0" encoding="UTF-8"?>'
mybase = sqlite3.connect('stock.db')
sqlres = mybase.execute('SELECT [recv].[rawtext] FROM [recv] ORDER BY [time] ASC') # LIMIT 10
for row in sqlres:
    sqlanswer = encs + str(row[0])
    try:
        root = ET.fromstring(sqlanswer)
    except:
        print('Error parsing XML: %s' % sqlanswer) # если где-то вдруг косяк
        pass
    for elem in root.iter():
        print(' TAG -> ' + elem.tag, end='')
        if elem.text:
            print(' TEXT = ' + elem.text, end='') # TEXT
        for attr in elem.attrib:
            print(' ATTR ' + attr + " = " + elem.attrib[attr])

Получаю вывод:

 TAG -> seccode TEXT = TATNP TAG -> shortname TEXT = Татнфт 3ап TAG -> decimals TEXT = 2 TAG -> market TEXT = 1 TAG -> sectype TEXT = SHARE TAG -> opmask ATTR cancelbalance = yes
ATTR bymarket = yes
ATTR usecredit = yes
ATTR nosplit = yes
ATTR immorcancel = yes
TAG -> minstep TEXT = 0.01 TAG -> lotsize TEXT = 10 TAG -> point_cost TEXT = 1 TAG -> security ATTR active = true
ATTR secid = 29

 TAG -> quotations TAG -> quotation ATTR secid = 907
TAG -> accruedintvalue TEXT = 0.00 TAG -> closeprice TEXT = 6510 TAG -> volatility TEXT = 22.06 TAG -> theoreticalprice TEXT = 6790 TAG -> buydeposit TEXT = 9397.46 TAG -> selldeposit TEXT = 5328.24

Есть целый набор возможных тэгов, в данном случае я привожу только <seccode>, который описывает список торгуемых бумаг и <quotations> - цены.

Я упёрся в то, что 1) описания приходят пачками, 2) не знаю, как же их ПРАВИЛЬНО вернуть из парсера, чтобы затем заполнить tuples для дальнейшего использования.

То ли список списков тут нужен, то ли…. неясно, в общем. Подскажите?!

Как потом разбирать, тоже вопрос. if TAG == ‘seccode’ then…. и так 55 линий? Глупо.

Прошу совета.
s0rg
Какие именно данные вам нужны из этой пачки?
Кроме кортежей есть еще словари и именованные кортежи (namedtuple)
pmus
Там все данные важны, разве что OPMASK черт бы с ними.

Пока представляю что-то типа:

sec[n]['name', 'shortname', 'minstep', 'lotsize', 'point_cost'] = 'TATNP', ' Татнфт 3ап', '0.01', '10', '1'
или
quotations['TATNP', 'lastprice'] += lastprice

или даже

class sec(object):
    ''' class that handles security '''
    def __init__(self, secname):
        self.secname = secname
        self.last = []
        self.stakan = []
    def addlastprice(self, price):
        self.last.append (price)
    def addstakan(self, price):
        self.stakan.append (price)
rim = sec('RIM3')
rim.addlastprice(145000)
rim.addlastprice(144000)
rim.addlastprice(144300)
print rim.last

В общем, чего-то я серьезно не впиливаю.


reclosedev
Проще использовать lxml и его модуль objectify

# -*- coding: utf-8 -*-
from lxml import etree, objectify
 
 
text = '<securities>...</securities>'
securities = objectify.fromstring(text)
for security in securities.security:
    print(
        security.get('secid'), 
        security.shortname.text, 
        security.market,
        security.opmask.get('usecredit'),
        # ...
    )
 
pmus
reclosedev, спасибище Вам огромное! Наконец-то мои жалкие потуги сдвинулись с места.
pmus
seclist = {}
...
    try:
        for security in tree.security:
            seclist[security.seccode] = (
            {'seccode':security.seccode, 'secid': security.get('secid'), 'shortname': security.shortname, 'market': security.market})
    except:
        pass
....
print(seclist['RIM3'])
....
>{'shortname': 'RTS-6.13', 'seccode': 'RIM3', 'secid': '4016', 'market': 4}

А как мне теперь вытащить только ‘secid’ из списка?
Что-то вроде:
print(seclist['RIM3'].'secid')
>4016
Или, может быть, я вообще зря список сюда приплел?
pmus
Ну, конечно!
 print(seclist['RIM3']['secid'])

pmus
Вдогонку (для тех, кому попадется подобная задача)

tree = objectify.fromstring (text)
def result():
	global tree
	print tree.text
	print tree.attrib
	#и так далее...
def server_status():
	global tree
	#и так далее...
def security():
	global tree
	for s in tree.security :
		seclist.append (s.seccode)
                            secdict [s.seccode] = (
                           { 'secid' : s.get ('secid') , 'active' : s.get ('active') , 'seccode' : s.seccode ,
	#и так далее...
options = {'result' : result,
           'server_status' : server_status,
           'security' : security
}
options[tree.tag]()
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