ComicRack_Scripts/CVIssueCount/xml2py.py

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