Frage zu xml einlesen :-)

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
mocca
User
Beiträge: 84
Registriert: Mittwoch 4. März 2009, 16:44

Hi,

Ich versuche aus ner xml-Datei Infos auszulesen und in neuer Syntax auszugeben. Kriege aber das Kombinieren der einzelnen Werte nicht hin.

Also, xml sieht so aus, besteht aus massenweise solcher Services:

Code: Alles auswählen

  <Service>
    <SatId>2</SatId>
    <Frequency>11778</Frequency>
    <ChannelNo>65</ChannelNo>
    <ServiceName>Freedom</ServiceName>
    <ServiceType>RADIO</ServiceType>
    <Scrambled>false</Scrambled>
    <Sid>4026</Sid>
    <Oid>2</Oid>
    <Tsid>2004</Tsid>
    <VideoPid>0</VideoPid>
    <AudioPid>0</AudioPid>
    <PcrPid>0</PcrPid>
    <ChildrenLock>false</ChildrenLock>
    <Skip>false</Skip>
    <HD>false</HD>
    <FavoriteNo>0</FavoriteNo>
  </Service>
Ich hätte das ganz gerne in der Form

Code: Alles auswählen

Frequency#VideoPid#AudioPid
bisher habe ich

Code: Alles auswählen

import os
import sys
from xml.etree import ElementTree as etree
tlist = [ ]
os.getcwd()
currDir = os.getcwd()
szapxml = os.path.join(currDir,'szap.xml')
Frequencylist = []
tree = etree.parse(szapxml)
for Frequency in tree.findall('//Frequency'):
	Frequencylist.append(Frequency.text)
Frequencyfinal = '\n'.join(Frequencylist)
print Frequencyfinal
Das liest die Frequency korrekt ein und gibt diese als Liste aus. Nun bin ich nur nicht sicher, wie ich es hinkriege, dass er mehrere Werte einliest und in den korrekten Gruppen und mit der gewünschten Syntax wieder ausgibt.

Könnt ihr mir da vielleicht weiterhelfen?

habs auch mal so probiert, aber da kommt trotzdem nix raus, weder beim print Gesamt noch beim print ()

Code: Alles auswählen

import os
import sys
from xml.etree import ElementTree as etree
tlist = [ ]
os.getcwd()
currDir = os.getcwd()
szapxml = os.path.join(currDir,'szap.xml')
Frequencylist = []
VideoPidlist = []
tree = etree.parse(szapxml)
for Frequency in tree.findall('//Frequency'):
	Frequencylist.append(Frequency.text)
for VideoPid in tree.findall('//VideoPid'):
	VideoPidlist.append(VideoPid.text)
Frequencyfinal = '\n'.join(Frequencylist)
VideoPidfinal = '\n'.join(VideoPidlist)
Gesamt = (Frequencylist, "#" , VideoPidlist)
print Gesamt
print (Frequencylist, "#" , VideoPidlist)
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

evtl nicht optimal, aber es macht was es soll:

Code: Alles auswählen

service_list = []
tree = etree.parse(szapxml)
for f in tree.findall('//Service'):
    service_list.append(f.find('Frequency').text + '#' + f.find('VideoPid').text + '#' + f.find('AudioPid').text)
Frequencyfinal = '\n'.join(service_list)
print Frequencyfinal
mocca
User
Beiträge: 84
Registriert: Mittwoch 4. März 2009, 16:44

danke!
mit minimaler anpassung funktioniert das schon sehr gut.

jetzt hab ich nur ein problem festgestellt.
und zwar müsste ich nun noch eine zuordnung machen.

beispiel

Code: Alles auswählen

  <Service>
    <SatId>1</SatId>
    <Frequency>11361</Frequency>
    <ChannelNo>1</ChannelNo>
    <ServiceName>Das Erste HD</ServiceName>
    <ServiceType>TV</ServiceType>
    <Scrambled>false</Scrambled>
    <Sid>11100</Sid>
    <Oid>1</Oid>
    <Tsid>1011</Tsid>
    <VideoPid>6010</VideoPid>
    <AudioPid>6020</AudioPid>
    <PcrPid>6010</PcrPid>
    <ChildrenLock>false</ChildrenLock>
    <Skip>false</Skip>
    <HD>true</HD>
    <FavoriteNo>1</FavoriteNo>
  </Service>
  <Service>
    <SatId>1</SatId>
    <Frequency>11361</Frequency>
    <ChannelNo>2</ChannelNo>
    <ServiceName>ZDF HD</ServiceName>
    <ServiceType>TV</ServiceType>
    <Scrambled>false</Scrambled>
    <Sid>11110</Sid>
    <Oid>1</Oid>
    <Tsid>1011</Tsid>
    <VideoPid>0</VideoPid>
    <AudioPid>0</AudioPid>
    <PcrPid>0</PcrPid>
    <ChildrenLock>false</ChildrenLock>
    <Skip>false</Skip>
    <HD>true</HD>
    <FavoriteNo>1</FavoriteNo>
  </Service>

Frequency ist hier angegeben, aber nicht die Polarisation. Die Polarisation ist nämlich jeweils beim Transponder mit abgespeichert.
Es gibt also zu jeder Frequency mehrere "Service" aber nur einen "Transponder". Nun würde ich gerne allen Einträgen mit der Frequency die jeweilige Polarisation und SymbolRate des korrespondierenden Transponders zuweisen.

Code: Alles auswählen

  <Transponder>
    <SatId>1</SatId>
    <Frequency>11361</Frequency>
    <SymbolRate>22000</SymbolRate>
    <Tsid>1011</Tsid>
    <Oid>1</Oid>
    <Polarisation>H</Polarisation>
    <FEC>8PSK_2_3</FEC>
  </Transponder>
Wisst ihr, was ich meine?

Auf jedem Transponder liegen mehrere Sender. Diese haben alle die gleiche Frequenz und die gleiche Polarisation und die gleiche SymbolRate. Während die Frequenz aber bei jedem Sender individuell mit abgespeichert wird im jeweiligen "Service"-Zweig, sind Polarisation und SymbolRate zentral nur einmal in "Transponder" abgespeichert.
Ist jetzt die Frage, wie ich die Werte nun zusammenbringe.

Er müsste im Prinzip den Wert für "Frequency" in den <Transponder> Zweigen suchen und wenn er einen Zweig mit der Frequency findet, müsste er von dem Zweig die "Polarisation" und "SymbolRate" nehmen.
nemomuk
User
Beiträge: 862
Registriert: Dienstag 6. November 2007, 21:49

Lies alle Transponder ein und speichere sie in einem dict (Frequency als key) ab. Danach liest du alle Services ein und holst dir den entsprechenden Transponder aus dem dict.
mocca
User
Beiträge: 84
Registriert: Mittwoch 4. März 2009, 16:44

ähm, ok :K

ich nehme an du meinst
dict(Frequency=Polarisation)
bzw konkret dann
dict(11341=h)
falls ja hab ich leider keine ahnung, wie ich das aber hier konkret umsetzen müsste :oops:
und auch nicht, wie ich es zugeordnet wieder auslesen könnte :oops:

ich hatt schon überlegt, ob ich die "Transponder" alle auslesen sollte und als separate liste speichern sollte. und dann mit nem extra bash skript mit grep die frequenzen gegen die werte aus dieser extra liste prüfen und alle ersetzen lassen sollte.
aber das ist natürlich eine sehr hässliche lösung.

deine lösung, ahojnnes, klingt schon sehr viel eleganter, nur leider bräucht ich da mehr hilfe dazu :)
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

inetwa so kannst du es an die Liste anhängen:

Code: Alles auswählen

frequency = f.find('Frequency').text 
service_list.append(frequency + '#' + f.find('VideoPid').text + '#' + f.find('AudioPid').text + '#' + polarisation_info[frequency])
Die Erzeugung der 'polarisation_info' Liste ist deine Aufgabe...
mocca
User
Beiträge: 84
Registriert: Mittwoch 4. März 2009, 16:44

ja gut, das auslesen der daten aus dem Transponder-Teil ist nicht mehr das Problem, dank euch. Und das einfügen danach an sich auch nicht.

mein problem liegt in der zuordnung.
es sind ja im prinzip werte-paare.

sprich
Frequenz1 = Polarisation1
Sender1 = Frequenz1 => Polarisation1
Sender2 = Frequenz1 => Polarisation1
Sender3 = Frequenz2 => Polarisation2

die daten einzeln auszulesen kriege ich hin. denke ich. aber ich weiss nicht, wie ich die dann zusammenfüge, sodass die korrekten werte zugewiesen werden.

wie gesagt, bei jedem sender steht nur die frequenz. und diese frequenz korrespondiert mit der frequenz eines transponders. und in diesem transponder-zweig steckt die nötige info über die polarisation. diese muss entsprechend zugewiesen werden.
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

ahojnnes hat geschrieben:Lies alle Transponder ein und speichere sie in einem dict (Frequency als key) ab. Danach liest du alle Services ein und holst dir den entsprechenden Transponder aus dem dict.
das auslesen des dict habe ich ja bereits gemacht:
DaMutz hat geschrieben:

Code: Alles auswählen

frequency = f.find('Frequency').text 
service_list.append(frequency + '#' + f.find('VideoPid').text + '#' + f.find('AudioPid').text + '#' + polarisation_info[frequency])
Und das erzeugen ist nicht schwerer...

Code: Alles auswählen

polarisation_info[frequency] = polarisation
mocca
User
Beiträge: 84
Registriert: Mittwoch 4. März 2009, 16:44

ne, tut mir leid, steh noch auf dem schlauch.
das erzeugen erfolgt also einfach mit

Code: Alles auswählen

polarisation_info[frequency] = polarisation
aber wie baue ich das dann korrekt ein? es muss ihm ja gesagt werden, dass er im Transponder-ZWeig schauen muss. also hab ichs jetzt da mal reingesetzt.
"polarisation_info[frequency]" ist jetzt die Bezeichnung von dir für die Polarisation zu der Frequenz.
Aber jetzt muss ja die Polarisation ausgelesen werden, vermutlich mit nem f.find und auch die Frequenz dazu ausgelesen werden.
Da steh ich auf dem Schlauch.

Hier mal das bisherige mit einfügen deiner Änderungen und wie ich vermute, dass es untergebracht werden muss :oops:
aber so kanns ja nicht sein, weil jetzt noch keine verknüpfung zwischen gefundener frequenz und gefundener polarisation besteht. oder erkennt python anhand der bezeichnung "polarisation_info[frequency]", dass er das pro frequenz anlegen muss?
oder müsste da ne for schleife nach dem finden der frequenz? aber dann ist immernoch nicht für später die zuordnung mit eingebaut.

Code: Alles auswählen

import os
import sys
from xml.etree import ElementTree as etree
service_list = []
polarisation_info = []
os.getcwd()
currDir = os.getcwd()
kanalxml = os.path.join(currDir,'kanal.xml')
tree = etree.parse(kanalxml)

for f in tree.findall('//Transponder'):
  frequency = f.find('Frequency').text 
  polarisation = f.find('Polarisation').text 
  polarisation_info[frequency] = polarisation

for f in tree.findall('//Service'):
  frequency = f.find('Frequency').text 
service_list.append(frequency + '#' + f.find('VideoPid').text + '#' + f.find('AudioPid').text + '#' + polarisation_info[frequency])
Frequencyfinal = '\n'.join(service_list)
kanalchannels = open(os.path.join(currDir,'kanal.channels'), 'w')
print >> kanalchannels, Frequencyfinal.encode('utf-8')

nur zur info, damit ihr nicht doppelt und dreifach arbeit mit mir habt:
hab den code so mal versucht laufen zu lassen, aber kommt ein
TypeError: list indices must be integers, not str
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Code: Alles auswählen

import os
# muss ein dict sein!
polarisation_info = {}
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mocca
User
Beiträge: 84
Registriert: Mittwoch 4. März 2009, 16:44

duh :D

das ist ja spitze. scheint soweit zu funktionieren.

ich muss jetzt mal ein paar tests damit machen, ob auch alles passt, aber schonmal DICKES DICKES DANKE!


mal nebenbei:
geht das ähnlich einfach auch wenn eine datei nicht als xml vorliegt, sondern z.b. so

Code: Alles auswählen

2b5c:00c00000:03f3:0001:25:0
Das Erste HD
p:ARD,c:00177a,c:011784,c:02178e,c:03177a,c:050001
245e:00c00000:0456:0001:25:0
M6 HD
p:CSAT
1b62:00eb0000:0c88:0003:25:0
Discovery HD
p:CANALDIGITAAL
2b66:00c00000:03f3:0001:25:0
ZDF HD
p:ZDFvision
jeder kanal besteht dabei aus 3 zeilen. eine vor und eine nach dem ServiceName. Die Infos sind teils hexadezimal abgespeichert. getrennt werden die infos wie man sieht durch "," oder ":"

dürfte deutlich schwerer sein auszulesen, richtig? zumal teilweise nicht alle infos zu jedem sender immer vorhanden sind.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

mocca hat geschrieben:

Code: Alles auswählen

2b5c:00c00000:03f3:0001:25:0
Das Erste HD
p:ARD,c:00177a,c:011784,c:02178e,c:03177a,c:050001
245e:00c00000:0456:0001:25:0
M6 HD
p:CSAT
1b62:00eb0000:0c88:0003:25:0
Discovery HD
p:CANALDIGITAAL
2b66:00c00000:03f3:0001:25:0
ZDF HD
p:ZDFvision
jeder kanal besteht dabei aus 3 zeilen. eine vor und eine nach dem ServiceName. Die Infos sind teils hexadezimal abgespeichert. getrennt werden die infos wie man sieht durch "," oder ":"

dürfte deutlich schwerer sein auszulesen, richtig? zumal teilweise nicht alle infos zu jedem sender immer vorhanden sind.
Im Gegensatz zum XML-Format, musst Du hier erst einen Parser schreiben, der Dir die Syntax liefert. Der Rest bleibt dann prinzipiell gleich / ähnlich. (Also Dinge wie bestimmte Dinge rausfiltern und Referenzen erkennen und Werte entsprechend setzen).

sma kann Dir das in 5 Minuten perfekt erledigen denke ich mal - vielleicht auch schneller ;-)

Edit: Um was für ein Format handelt es sich denn da? Evtl. gibts dafür ja schon einen Parser für Python

Außerdem wären noch ein paar Fragen zu klären:
- sind es def. und immer drei Zeilen?
- gibt es passende Namen für c, p und die 3. zeile?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
mocca
User
Beiträge: 84
Registriert: Mittwoch 4. März 2009, 16:44

sma?

die anzahl der zeilen ist immer 3. allerdings nur im bereich der services.

sprich erst kommen die transponder und dann end und dann die services

Code: Alles auswählen

/
014ab0ea:0000:0001
	s 12522000:27500000:1:4:330:2:0
/
end
services
1600:011a0000:0807:0002:0:0

p:,f:40
1601:011a0000:0966:0002:0:0

p:,f:40
1406:011a0000:0807:0002:0:0
wie man sieht kann eine zeile auch leer sein, aber es sind immer drei zeilen vorhanden.

ich hab auch gerade einen code gefunden, in dem an sich fast alles drinsteckt. ich krieg nur grad nicht raus, wie ich die einzelnen werte separat ausgeben lassen kann.
ist halt doch etwas mehr code als ich normalerweise so bewerkstelligen kann :oops:


p.s.: kann man hier irgendwie dateien an einen post anhängen? kriegs nicht angezeigt.
Benutzeravatar
DaMutz
User
Beiträge: 202
Registriert: Freitag 31. Oktober 2008, 17:25

ich weiss jetzt nicht so genau was du mit diesen Daten machen willst, aber hier habe ich dir einmal den Anfang gemacht:

Code: Alles auswählen

info_string = '''2b5c:00c00000:03f3:0001:25:0
Das Erste HD
p:ARD,c:00177a,c:011784,c:02178e,c:03177a,c:050001
245e:00c00000:0456:0001:25:0
M6 HD
p:CSAT
1b62:00eb0000:0c88:0003:25:0
Discovery HD
p:CANALDIGITAAL
2b66:00c00000:03f3:0001:25:0
ZDF HD
p:ZDFvision'''.split('\n')

for line in range(0, len(info_string), 3):
    print info_string[line].split(':')
    print info_string[line+1]
    print info_string[line+2].split(',')
Jetzt muss man nur noch die einzelnen Felder irgendwie neu anordnen (wie hast du ja nicht geschrieben). Man sollte auch jeweils prüfen ob das Feld überhaupt vorhanden ist.
mocca
User
Beiträge: 84
Registriert: Mittwoch 4. März 2009, 16:44

ja, ist ein echtes problem, weil die syntax recht umständlich ist.

die werte stehen für unterschiedliche subwerte, wenn man so will.

sprich in der dritten zeile an der fünften stelle ist z.b. die VIDEOTYPE
0 VIDEO_PID
1 AUDIO_PID
2 TXT_PID
3 PCR_PID
4 AC3_PID
5 VIDEOTYPE
6 AUDIOCHANNEL
7 AC3_DELAY
8 PCM_DELAY
9 SUBTITLE_PID

und VIDEOTYPE wiederum gibt die Werte für
0 MPEG2
1 MPEG4_H264
2 MPEG1
3 MPEG4_Part2
4 VC1
5 VC1_SM

und ähnliches an. alles recht viel und recht umständlich. hab selbst noch nicht den kompletten überblick.

deshalb war ich ganz froh als ich einen code gefunden hatte, der im prinzip das ganze auslesen der lamedb übernimmt. nur reichen meine kenntnisse nicht aus, um nun aus den ausgelesenen daten, die alle im cache oder puffer gespeichert werden, in eine datei nach meinen reihenfolgen auszugeben.

hier mal die beiden dateien lamedb.py und plugin.py als snippets
http://www.python-forum.de/pastebin.php?mode=view&s=15
http://www.python-forum.de/pastebin.php?mode=view&s=16
und hier noch eine eigentliche lamedb aus der gelesen werden soll (snippet actuallamedbsource):
http://www.python-forum.de/pastebin.php?mode=view&s=17


das ganze stammt aus einem plugin, dass letztlich diese ganzen infos als on-screen-info ausgibt.
die datei lamedb.py (snippet lamedb) dürfte soweit ich das sehe dabei die ganzen infos auslesen.
nun müsste halt die plugin.py (snippet pluginlamedb) so angepasst werden, dass sie die ganzen angaben aus der lamedb.py einfach wieder in der gleichen weise in eine datei schreibt, wie wir das beim xml gemacht hatten.

sprich
servicename#frequency#polarisation#.....
mocca
User
Beiträge: 84
Registriert: Mittwoch 4. März 2009, 16:44

ich editiere mal nicht, da der andere post sonst zu lang wird.

falls jemand ne idee zum vorherigen post hat, bin ich natürlich super dankbar, aber falls da keiner lust drauf hat weils massig code ist, kann ich das natürlich gut verstehen.


ich hab auch meinen ursprünglichen code zum xml problem mal erweitert, weil ich einen weg gefunden habe eine der fehlenden infos noch einzulesen.

blöde dabei ist nur, dass ich letztlich einen wert für serviceid bekomme, der in abhängigkeit vom servicename (=channelname) vorliegt.

ich bin nciht ganz sicher, wie ich jetzt die korrekte zuweisung hinkriege. aktuell schreibt er nämlich bei jedem eintrag die gleiche serviceid rein.

im prinzip nehme ich an muss eine abfrage rein, die schaut, ob channelname = servicename ist und dann die serviceid in die zeile schreibt. bin nur nicht sicher wie.

Code: Alles auswählen

import os
import sys
from Screens.MessageBox import MessageBox
from Plugins.Plugin import PluginDescriptor
from Components.FileList import FileList
from Screens.ChannelSelection import service_types_tv, service_types_radio
from enigma import eServiceReference, eServiceCenter
from xml.etree import ElementTree as etree

class ServiceReferenceChecker(MessageBox):
	def __init__(self, session):
		service_list = []
		polarisation_info = {}
		serviceid_info = {}
		symbolrate_info = {}
		os.getcwd()
		kanallistexml = "/tmp/kanalliste.xml"
		tree = etree.parse(kanallistexml)
		serviceHandler = eServiceCenter.getInstance()
		refstr = '%s ORDER BY name' % (service_types_tv)
		servicelist = serviceHandler.list(eServiceReference(refstr))
		channels = servicelist and servicelist.getContent("NSR", True)
		counter = 0
		
		if channels is not None:
			for channel in channels:
				counter += 1
				serviceid = channel[1]
				channelname = channel[0]
				serviceid_info[channelname] = serviceid
						
		for f in tree.findall('//Transponder'):
		  frequency = f.find('Frequency').text 
		  polarisation = f.find('Polarisation').text 
		  symbolrate = f.find('SymbolRate').text
		  polarisation_info[frequency] = polarisation
		  symbolrate_info[frequency] = symbolrate
		
		for f in tree.findall('//Service'):
		  frequency = f.find('Frequency').text
		  service_list.append(f.find('ServiceName').text + '#' + f.find('Frequency').text + '#' + polarisation_info[frequency] + '#' + f.find('SatId').text + '#' + symbolrate_info[frequency] + '#' + f.find('VideoPid').text + '#' + f.find('AudioPid').text + '#' + f.find('Sid').text + '#' + serviceid_info[channelname])
		
		Frequencyfinal = '\n'.join(service_list)
		kanallistechannels = open("/tmp/kanalliste.channels", 'w')
		print >> kanallistechannels, Frequencyfinal.encode('utf-8')

EDIT: hab nen eigenen thread für das problem des vorherigen posts erzeugt, damits hier übersichtlich auf xml begrenzt bleibt.
Antworten