Найти - Пользователи
Полная версия: трансляция из .xml документа в форматированный текствой файл.
Начало » Python для новичков » трансляция из .xml документа в форматированный текствой файл.
1
Metheo
Добрый день!

Есть xml-документ который надо “отпарсить” и часть документа (контейнер с вложенными контейнерами)
преобразовать в текстовый файл определенного формата (не html!).
Какими средствами (читай:библиотеками) на питоне можно возпользоваться и чего почитать по теме.

Спасибо.
cleg
а может просто XSLT использовать? он для этого предназначен.
а на Пайтоне - надо делать связку из парсера ХМЛ (коих много) и шаблонного движка для организации правильного вывода (mako, cheetah и т.п.)
shiza
я думаю - вполне можно воспользоваться парсером xml.etree.ElementTree (поставляеться с питоном).
С помощью него можно довольно просто сделать вышеописанное.
Смотреть по теме можно в документации.
И туториалы здесь: http://effbot.org/zone/element-index.htm
Metheo
Вообщем пробую сделать это через xml.parsers.expat.
Есть .xml файл:
<?xml version="1.0" encoding="UTF-8"?>
<!--Sample XML file generated by XMLSpy v2008 sp1 (http://www.altova.com)-->
<NET xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<server xmlns="">
<ro:router router_name="Router1">
<ro:cisco_series_7200>
<ro:cisco_model_7200>
<ro:model>7200</ro:model>
<ro:image>/home/ios/images/C7200-IK.BIN</ro:image>
<ro:slot0>
<ro:module_C7200-IO-2FE name_module="C7200-IO-2FE">
<ro:connect name_interface="f0/0" target_router="Router2" target_router_interface="f0/0"/>
<ro:connect name_interface="f0/1" target_router="Router3" target_router_interface="f0/1"/>
</ro:module_C7200-IO-2FE>
</ro:slot0>
<ro:slot1>
<ro:module_PA-FE-TX name_module="PA-FE-TX"/>
</ro:slot1>
</ro:cisco_model_7200>
</ro:cisco_series_7200>
</ro:router>
<ro:router router_name="Router2">
<ro:cisco_series_3600>
<ro:cisco_model_3660>
<ro:model>3660</ro:model>
<ro:image>/home/ios/images/C3660-IK.BIN</ro:image>
<ro:connect name_interface="f0/0" target_router="Router1" target_router_interface="f0/0"/>
<ro:connect name_interface="f0/1" target_router="Router3" target_router_interface="f0/0"/>
</ro:cisco_model_3660>
</ro:cisco_series_3600>
</ro:router>
<ro:router router_name="Router3">
<ro:cisco_series_7200>
<ro:cisco_model_7200>
<ro:model>7200</ro:model>
<ro:image>/home/ios/images/C7200-IK.BIN</ro:image>
<ro:slot0>
<ro:module_C7200-IO-2FE name_module="C7200-IO-2FE">
<ro:connect name_interface="f0/0" target_router="Router2" target_router_interface="f0/1"/>
<ro:connect name_interface="f0/1" target_router="Router1" target_router_interface="f0/1"/>
</ro:module_C7200-IO-2FE>
</ro:slot0>
</ro:cisco_model_7200>
</ro:cisco_series_7200>
</ro:router>
</server>
</NET>
Необходимо преобразовать его в файл:
[[router Router1]]
model=7200
image=/home/ios/images/C7200-IK.BIN
slot0=C7200-IO-2FE
f0/0=Router2 f0/0
f0/1=Router3 f0/1
slot1=PA-FE-TX
[[router Router2]]
model=3660
image=/home/ios/images/C3660-IK.BIN
f0/0=Router1 f0/0
f0/1=Router3 f0/0
[[router Router3]]
model=7200
image=/home/ios/images/C7200-IK.BIN
slot0=C7200-IO-FE
f0/0=Router2 f0/1
f0/1=Router1 f0/1
Пока что(с выводом на экран а не в файл) получается вот это:
#!/usr/bin/python
# -*- coding:utf-8 -*-

from xml.parsers import expat

file = '/opt/test_socket/example.xml'

def start_element(name, attr):
if name == 'ro:router':
print '[[router %s]]'%(attr['router_name'])

p = expat.ParserCreate()

p.StartElementHandler = start_element

h = open(file,'r')
p.ParseFile(h)
h.close
Выдает:
[[router Router1]]
[[router Router2]]
[[router Router3]]
Не получается ( не понимаю логики работы) обработать child-тэги с текстовой частью(CharElement).
Как это сделать?

Спасибо.
kostyasa
Metheo
я бы сделал проще
сначала разбил бы исходный текст на разделы-роутеры - split('<ro:router')
дальше пробежался бы циклом по полученным разделам, выдерая из строк информацию,
здесь же в этом цикле добавил бы все в массив, уже в том виде, в котором будет новый файл
вроде задача элементарна
Metheo
:( :( :\ не получается!

Вот этот код выводит мне построчно списки с элементами состоящими из слов строк xml файла.
Как разбивать файл на части по опред. признаку (тэгу <ro:router), как обращаться к формируемым string.split() спискам - не понимаю! =(

file = '/opt/test_socket/example.xml'
h = open(file,'r')

for lines in h:
ln = string.split(lines)
print ln

h.close
вывод:
['<?xml', 'version="1.0"', 'encoding="UTF-8"?>']
['<!--Sample', 'XML', 'file', 'generated', 'by', 'XMLSpy', 'v2008', 'sp1', '(http://www.altova.com)-->']
['<NET', 'xsi:schemaLocation="http://www.avalon.ru', 'Schema.xsd"']
['xmlns="http://www.avalon.ru"']
['xmlns:dev="http://www.avalon.ru/devices"']
['xmlns:ht="http://www.avalon.ru/host"']
['xmlns:in="http://www.avalon.ru/interface"']
['xmlns:net="http://www.avalon.ru/network"']
['xmlns:os="http://www.avalon.ru/os"']
['xmlns:port="http://www.avalon.ru/port"']
['xmlns:ro="http://www.avalon.ru/router"']
['xmlns:sw="http://www.avalon.ru/switch"']
['xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">']
[]
['<server', 'xmlns="">']
['<ro:router', 'router_name="Router1">']
['<ro:cisco_series_7200>']
['<ro:cisco_model_7200>']
['<ro:model>7200</ro:model>']
['<ro:image>http://www.altova.com</ro:image>']
['<ro:slot0>']
['<ro:module_C7200-IO-2FE', 'name_module="C7200-IO-2FE">']
['<ro:connect', 'name_interface="f0/0"', 'target_router="Router2"', 'target_router_interface="f0/0"/>']
['<ro:connect', 'name_interface="f0/1"', 'target_router="Router3"', 'target_router_interface="f0/1"/>']
['</ro:module_C7200-IO-2FE>']
['</ro:slot0>']
['<ro:slot1>']
['<ro:module_PA-FE-TX', 'name_module="PA-FE-TX"/>']
['</ro:slot1>']
['</ro:cisco_model_7200>']
['</ro:cisco_series_7200>']
['</ro:router>']
['<ro:router', 'router_name="Router2">']
['<ro:cisco_series_3600>']
['<ro:cisco_model_3660>']
['<ro:model>3660</ro:model>']
['<ro:image>http://www.altova.com</ro:image>']
['<ro:connect', 'name_interface="f0/0"', 'target_router="Router1"', 'target_router_interface="f0/0"/>']
['<ro:connect', 'name_interface="f0/1"', 'target_router="Router3"', 'target_router_interface="f0/0"/>']
['</ro:cisco_model_3660>']
['</ro:cisco_series_3600>']
['</ro:router>']
['<ro:router', 'router_name="Router3">']
['<ro:cisco_series_7200>']
['<ro:cisco_model_7200>']
['<ro:model>7200</ro:model>']
['<ro:image>http://www.altova.com</ro:image>']
['<ro:slot0>']
['<ro:module_C7200-IO-2FE', 'name_module="C7200-IO-2FE">']
['<ro:connect', 'name_interface="f0/0"', 'target_router="Router2"', 'target_router_interface="f0/1"/>']
['<ro:connect', 'name_interface="f0/1"', 'target_router="Router1"', 'target_router_interface="f0/1"/>']
['</ro:module_C7200-IO-2FE>']
['</ro:slot0>']
['</ro:cisco_model_7200>']
['</ro:cisco_series_7200>']
['</ro:router>']
['<sw:switch>text</sw:switch>']
['</server>']
['</NET>']
PooH
Зря бросили первый вариант, были почти у цели:
#!/usr/bin/env python
# -*- coding:utf-8 -*-

from xml.parsers import expat

class Handler():

def __init__(self, parser):
parser.StartElementHandler = self.start_element
parser.CharacterDataHandler = self.char_data
self.key = None
self.slot = None

def start_element(self, name, attr):
if name == 'ro:router':
print '[[router %s]]' % (attr['router_name'])
elif name in ('ro:model', 'ro:image'):
self.key = name[3:]
elif name.startswith('ro:slot'):
self.slot = name[3:]
elif name.startswith('ro:module'):
print '%s=%s' % (self.slot, attr['name_module'])
elif name == 'ro:connect':
print '%s=%s %s' % (attr['name_interface'], attr['target_router'], attr['target_router_interface'])

def char_data(self, data):
if self.key:
print '%s=%s' % (self.key, data.strip())
self.key = None

p = expat.ParserCreate()
handler = Handler(p)

h = open('test.xml','r')
p.ParseFile(h)
h.close
Хотя такие маленькие файлы проще было через DOM обрабатывать, ну а самый красивый вариант был бы XSLT
Metheo
PooH
Зря бросили первый вариант, были почти у цели:
Хотя такие маленькие файлы проще было через DOM обрабатывать, ну а самый красивый вариант был бы XSLT
PooH! Спасибо за наводку! =) Вообщем, попробовал разобраться с вариантом через XSLT. Для питона использую библиотеку 4Suite. Исходный .xml файл, который надо отпарсить - в треде выше.
Сделал вот такой вот stylesheet.xsl:
[root@gamma test_socket]# cat stylesheet6.xsl
<xsl:stylesheet xmlns:xsl='http://www.w3.org/1999/XSL/Transform'
xmlns:ro='http://mydomain.ru/router' version='1.0'>

<xsl:output method="text" indent="no"/>

<xsl:template match="server">
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="ro:router">
[[router <xsl:value-of select="@router_name"/>]]
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="ro:model">
model=<xsl:value-of select="."/>
</xsl:template>

<xsl:template match="ro:image">
image=<xsl:value-of select="."/>
</xsl:template>

<xsl:template match="ro:connect">
<xsl:value-of select="@name_interface"/>=<xsl:value-of select="@target_router"/><xsl:text> </xsl:text><xsl:value-of select="@target_router_interface"/>
</xsl:template>

<xsl:template match="ro:slot0">
slot0=<xsl:call-template name="modules"/>
<xsl:apply-templates/>
</xsl:template>

<xsl:template match="ro:slot1">
slot1=<xsl:call-template name="modules"/>
<xsl:apply-templates/>
</xsl:template>

<xsl:template name="modules">
<xsl:for-each select="ro:module_C7200-IO-2FE">
<xsl:value-of select="@name_module"/>
</xsl:for-each>
<xsl:for-each select="ro:module_PA-FE-TX">
<xsl:value-of select="@name_module"/>
</xsl:for-each>
</xsl:template>
Вот код парсера:
#!/usr/bin/python
# -*- coding:utf-8 -*-
from Ft.Xml.Xslt import Processor
from Ft.Xml import InputSource
from Ft.Lib.Uri import OsPathToUri

processor = Processor.Processor()

srcAsUri = OsPathToUri('/opt/test_socket/example.xml')
source = InputSource.DefaultFactory.fromUri(srcAsUri)

ssAsUri = OsPathToUri('/opt/test_socket/stylesheet.xsl')
transform = InputSource.DefaultFactory.fromUri(ssAsUri)

processor.appendStylesheet(transform)
result = processor.run(source)

print result
А вот результат вывода:
[root@gamma test_socket]# python parser3




[[router Router1]]




model=7200

image=http://www.altova.com

slot0=C7200-IO-2FE

f0/0=Router2 f0/0
f0/1=Router3 f0/1



slot1=PA-FE-TX






[[router Router2]]




model=3660

image=http://www.altova.com
f0/0=Router1 f0/0
f0/1=Router3 f0/0




[[router Router3]]




model=7200

image=http://www.altova.com

slot0=C7200-IO-2FE

f0/0=Router2 f0/1
f0/1=Router1 f0/1
Все вроде правильно обрабатывается в формат который я и хотел. Но меня вот чего смущает…
Откуда эти пустые строки и такие большие отступы? Хотелось бы отровнять все по левому краю, убрать пустые строки и сохранить в таком приличном виде в файл. Это проблема парсера или можно что-то в xsl добавить?

Спасибо!
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