122 lines
3.5 KiB
Python
122 lines
3.5 KiB
Python
#####################################################################################
|
|
#
|
|
# Copyright (c) Harry Pierson. All rights reserved.
|
|
#
|
|
# This source code is subject to terms and conditions of the Microsoft Public License.
|
|
# A copy of the license can be found at http://opensource.org/licenses/ms-pl.html
|
|
# By using this source code in any fashion, you are agreeing to be bound
|
|
# by the terms of the Microsoft Public License.
|
|
#
|
|
# You must not remove this notice, or any other, from this software.
|
|
#
|
|
#####################################################################################
|
|
|
|
import ipypulldom
|
|
from System.Xml import XmlNodeType
|
|
|
|
class _type_factory(object):
|
|
class _type_node(object):
|
|
def __init__(self, node):
|
|
ty = type(node)
|
|
self.name = ty.__name__
|
|
self.namespace = ty.xmlns
|
|
|
|
def __init__(self):
|
|
self.types = {}
|
|
|
|
def find_type(self, node, parent):
|
|
def create_type(node, parent):
|
|
return type(node.name, (parent,), {'xmlns':node.namespace})
|
|
|
|
if parent not in self.types:
|
|
self.types[parent] = {}
|
|
|
|
tp = self.types[parent]
|
|
if node.name not in tp:
|
|
tp[node.name] = [create_type(node, parent)]
|
|
|
|
tpn = tp[node.name]
|
|
|
|
for t in tpn:
|
|
if t.xmlns == node.namespace:
|
|
return t
|
|
|
|
#if there's no matching namespace type, create one and add it to the list
|
|
new_type = create_type(node, parent)
|
|
tpn.append(new_type)
|
|
return new_type
|
|
|
|
def __call__(self, node, parent=object):
|
|
if isinstance(node, ipypulldom.XmlNode):
|
|
return self.find_type(node, parent)
|
|
return self.find_type(self._type_node(node), parent)
|
|
|
|
|
|
xtype = _type_factory()
|
|
|
|
|
|
def xml2py(nodelist):
|
|
|
|
def children(nodelist):
|
|
while True:
|
|
child = xml2py(nodelist)
|
|
if child is None:
|
|
break
|
|
yield child
|
|
|
|
def set_attribute(parent, child):
|
|
name = type(child).__name__
|
|
if not hasattr(parent, name):
|
|
setattr(parent, name, child)
|
|
else:
|
|
val = getattr(parent, name)
|
|
if isinstance(val, list):
|
|
val.append(child)
|
|
else:
|
|
setattr(parent, name, [val, child])
|
|
|
|
node = nodelist.next()
|
|
if node.nodeType == XmlNodeType.EndElement:
|
|
return None
|
|
|
|
elif node.nodeType == XmlNodeType.Text or node.nodeType == XmlNodeType.CDATA:
|
|
return node.value
|
|
|
|
elif node.nodeType == XmlNodeType.Element:
|
|
|
|
#create a new object type named for the element name
|
|
cur = xtype(node)()
|
|
cur._nodetype = XmlNodeType.Element
|
|
|
|
#collect all the attributes and children in lists
|
|
attributes = [xtype(attr, str)(attr.value) for attr in node.attributes]
|
|
children = [child for child in children(nodelist)]
|
|
|
|
if len(children) == 1 and isinstance(children[0], str):
|
|
#fold up elements with a single text node
|
|
cur = xtype(cur, str)(children[0])
|
|
cur._nodetype = XmlNodeType.Element
|
|
else:
|
|
#otherwise, add child elements as properties on the current node
|
|
for child in children:
|
|
set_attribute(cur, child)
|
|
|
|
for attr in attributes:
|
|
attr._nodetype = XmlNodeType.Attribute
|
|
set_attribute(cur, attr)
|
|
|
|
return cur
|
|
|
|
|
|
def parse(xml):
|
|
return xml2py(ipypulldom.parse(xml))
|
|
|
|
def parseString(xml):
|
|
return xml2py(ipypulldom.parseString(xml))
|
|
|
|
|
|
if __name__ == '__main__':
|
|
rss = parse('http://feeds.feedburner.com/Devhawk')
|
|
for item in rss.channel.item:
|
|
print item.title
|