• 26.04.2024, 13:58
  • Registrieren
  • Anmelden
  • Sie sind nicht angemeldet.

 

[python] xml parsen

Montag, 4. Oktober 2010, 09:48

moin,

ich möchte mir ein kleines python skript schreiben, welches xml in eine passende (c struct ähnliche) datenstruktur umwandelt, sodass ich einfach auf die xml daten zugreifen kann. konkret stelle ich mir sowas vor:

xml:

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<campus_search> 
	<status> 
		<status_msg>success</status_msg> 
	</status> 
	<result> 
		<rank>9</rank> 
		<netbios_name>NZSERVER</netbios_name> 
		<ip>192.168.0.1</ip> 
		<type>file</type> 
		<full_path>smb://192.168.0.1/Movies/IMDB top 30/30 - The Matrix/The Matrix [1].avi</full_path> 
		<dir>Movies/IMDB top 30/30 - The Matrix</dir> 
		<name>The Matrix [1].avi</name> 
		<online>no</online> 
		<size>735412224</size> 
		<meta> 
			<imdb_url>http://imdb.com/title/tt0133093</imdb_url> 
			<imdb_rating>8.7</imdb_rating> 
			<imdb_year>1999</imdb_year> 
		</meta> 
	</result> 
	<result> 
		<rank>10</rank> 
		<netbios_name>WOLVERINE</netbios_name> 
		<ip>192.168.0.2</ip> 
		<type>directory</type> 
		<full_path>smb://192.168.0.2/FILMS/Animatrix</full_path> 
		<dir>FILMS</dir> 
		<name>Animatrix</name> 
		<online>yes</online> 
		<size>1457489248</size> 
		<meta> 
			<imdb_url>http://imdb.com/title/tt0328832</imdb_url> 
			<imdb_rating>7.5</imdb_rating> 
			<imdb_year>2003</imdb_year> 
		</meta> 
	</result> 
</campus_search>


dann hätte ich gerne sowas wie: xmldata[0].name = The Matrix [1].avi

sowas geht sicherlich ganz einfach, nur bin ich python noch nicht so zuhause ;) wer kann mir also eben auf die sprünge helfen?

danke,
infinite

Montag, 4. Oktober 2010, 11:27

http://wiki.python.org/moin/PythonXml
such dir halt eins aus ;)

Dienstag, 5. Oktober 2010, 17:08

ich kriegs irgendwie ned so ganz hin, schon zu lange nix mehr in python gemacht.

ich will von jedem root element <result> den inhalt des tags <full_path> + <name> haben, aber NUR wenn der inhalt von <online> yes ist. wie berwerkstellige ich das am elegantesten?

am liebsten wäre mir eigtl ne art result array, so dass ich einfach was machen kann ala if (result[0].online = yes, dann bla...)

edit: ich will natürlich ned selbst einen parser schreiben :D hab mir ET angeschaut und komme halt schon soweit mir alle tags anzeigen zu lassen, die zbsp online heissen, nur wie komm ich dann an die anderen elemente im selben root tag?

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »infinite« (5. Oktober 2010, 17:16)

Dienstag, 5. Oktober 2010, 22:42

sowas einfaches macht man einfach per regex, das ist dann auch gleich noch einfacher ;)

so oder so ähnlich ist da das regex pattern:
"<result>.*<full_path>(.*)</full_path>.*<name>(.*)</name>.*<online>yes</online>.*</result>"
dann benutzte das mit der groupall (oder so ähnlich) funktion, und bekommst einfach nen 2 dimensionales tupel zurück, halt für jeden treffer, und bei jedem treffer die 2 treffer die an der stelle von (.*) stehen
ich glaube bei einigen sprachen beinhaltet der . keine zeilenumbrücke, musste mal googlen und dann dafür evtl noch was umbasteln

Mittwoch, 6. Oktober 2010, 20:44

Nimm auf jeden Fall ElementTree (wird ja seit 2.5 auch mitgeliefert, wahlweise auch über lxml). Regex ist quatsch, dafür ist XML zu gut maschinenlesbar.

Update: Na gut, weil du's bist (hier gibt's das Ganze in lesbar):

Quellcode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
>>> from xml.etree import ElementTree
>>> xml = open('data.xml', 'rb').read()
>>> xml
'<campus_search> \n\t<status> \n\t\t<status_msg>success</status_msg> \n\t</status> \n\t<result> \n\t\t<rank>9</rank> \n\t\t<netbios_name>NZSERVER</netbios_name
> \n\t\t<ip>192.168.0.1</ip> \n\t\t<type>file</type> \n\t\t<full_path>smb://192.168.0.1/Movies/IMDB top 30/30 - The Matrix/The Matrix [1].avi</full_path> \n\t\
t<dir>Movies/IMDB top 30/30 - The Matrix</dir> \n\t\t<name>The Matrix [1].avi</name> \n\t\t<online>no</online> \n\t\t<size>735412224</size> \n\t\t<meta> \n\t\t
\t<imdb_url>http://imdb.com/title/tt0133093</imdb_url> \n\t\t\t<imdb_rating>8.7</imdb_rating> \n\t\t\t<imdb_year>1999</imdb_year> \n\t\t</meta> \n\t</result> \
n\t<result> \n\t\t<rank>10</rank> \n\t\t<netbios_name>WOLVERINE</netbios_name> \n\t\t<ip>192.168.0.2</ip> \n\t\t<type>directory</type> \n\t\t<full_path>smb://1
92.168.0.2/FILMS/Animatrix</full_path> \n\t\t<dir>FILMS</dir> \n\t\t<name>Animatrix</name> \n\t\t<online>yes</online> \n\t\t<size>1457489248</size> \n\t\t<meta
> \n\t\t\t<imdb_url>http://imdb.com/title/tt0328832</imdb_url> \n\t\t\t<imdb_rating>7.5</imdb_rating> \n\t\t\t<imdb_year>2003</imdb_year> \n\t\t</meta> \n\t</r
esult> \n</campus_search>\n'
>>> root = ElementTree.parse(open('data.xml', 'rb'))
>>> root
<xml.etree.ElementTree.ElementTree instance at 0x99eaf0c>
>>> results = [dict((elem.tag, elem.text) for elem in result.getchildren()) for result in root.findall('result')]
>>> from pprint import pprint
>>> pprint(results)
[{'dir': 'Movies/IMDB top 30/30 - The Matrix',
  'full_path': 'smb://192.168.0.1/Movies/IMDB top 30/30 - The Matrix/The Matrix [1].avi',
  'ip': '192.168.0.1',
  'meta': ' \n\t\t\t',
  'name': 'The Matrix [1].avi',
  'netbios_name': 'NZSERVER',
  'online': 'no',
  'rank': '9',
  'size': '735412224',
  'type': 'file'},
 {'dir': 'FILMS',
  'full_path': 'smb://192.168.0.2/FILMS/Animatrix',
  'ip': '192.168.0.2',
  'meta': ' \n\t\t\t',
  'name': 'Animatrix',
  'netbios_name': 'WOLVERINE',
  'online': 'yes',
  'rank': '10',
  'size': '1457489248',
  'type': 'directory'}]


Wenn du an die Kindelemente von `<meta>` ranwillst, musst du das ganze natürlich etwas weniger kompakt machen. Da dürfe sich dann aber eine Funktion lohnen, die Key/Value-Paare `yield`ed, die du dann an `dict()` übergeben kannst.

Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von »Y0Gi« (6. Oktober 2010, 20:59)

Donnerstag, 7. Oktober 2010, 12:19

danke für die anregungen, habs zwischenzeitlich sehr kompakt mit minidom gelöst :)

Samstag, 9. Oktober 2010, 20:32

minidom = uncool! :)