""" """ import sys, re, inspect try: from iexec import getinstance except ImportError: getinstance = None from new import classobj class Frag(list): """ basic anonymous container for xml tags. """ def __repr__(self): return "" %(len(self)) def __unicode__(self): return self.to_unicode(indent=0) def to_unicode(self, indent=2): l = [] visitor = getvisitor(l.append, indent) visitor.visit(self) return u"".join(l) class Tag(Frag): def __init__(self, *args, **kwargs): super(Tag, self).__init__(args) self.__dict__['attr'] = d = {} d.update(kwargs) def __leave__(self): x = getinstance(Frag) if x is not None: x.append(self) def __setattr__(self, name, value): self.attr[name] = value def __repr__(self): name = getattr(self, 'xmlname', self.__class__.__name__) return "" % (name, id(self)) class capture(Frag): def __init__(self, list): super(capture, self).__init__() self.list = list def __leave__(self): self.list.extend(self) def append(obj): x = getinstance(Frag) if x is not None: x.append(obj) else: raise ValueError, "iexec.getinstance found None!" class Error: def __init__(self, tag, excinfo): if excinfo is None: excinfo = sys.exc_info() self.excinfo = excinfo self.tag = tag type = lambda self: self.excinfo[0] value = lambda self: self.excinfo[1] tb = lambda self: self.excinfo[2] type = property(type, None, None) value = property(value, None, None) tb = property(tb, None, None) def reraise(self): raise self.excinfo def getfilelineno(self): f = self.tb.tb_frame return f.f_code.co_filename, f.f_lineno # the generic xml namespace # provides Tag classes on the fly optionally checking for # a tagspecification class Namespace(object): __tagspec__ = None __tagclass__ = Tag def __init__(self, errorhandler=None): tagclassdict = {} tagclassdict['namespace'] = self if callable(errorhandler): # only catch exceptions locally if we have an errorhandler def __except__(self, *excinfo): errorhandler(Error(self, excinfo)) tagclassdict['__except__'] = __except__ self.__tagclassdict__ = tagclassdict def __getattr__(self, name): if name[:1] == '_' and name[-1:] == '_': raise AttributeError(name) tagspec = self.__tagspec__ if tagspec is not None: if name not in tagspec: clsname = self.__class__.__name__ raise AttributeError("%s.%s not in tagspec" % (clsname, name)) cls = classobj(name, (self.__tagclass__,), self.__tagclassdict__) setattr(self, name, cls) return cls # # a generic conversion serializer # def getvisitor(func, indent=2): """ return a visitor object fit for the given indentation level.""" if indent: return IndentedUnicodeVisitor(func, indent=indent) else: return UnicodeVisitor(func) class UnicodeVisitor(object): """ recursive visitor to write unicode. """ def __init__(self, write): self.write = write self.cache = {} self.visited = {} # for detection of recursion def visit(self, node): """ dispatcher on node's class/bases name. """ cls = node.__class__ try: visitmethod = self.cache[cls] except KeyError: for subclass in inspect.getmro(cls): visitmethod = getattr(self, subclass.__name__, None) if visitmethod is not None: break else: visitmethod = self.object self.cache[cls] = visitmethod visitmethod(node) def object(self, obj): self.write(unicode(obj)) def unicode(self, obj): self.write(obj) def Frag(self, obj): assert id(obj) not in self.visited self.visited[id(obj)] = 1 map(self.visit, obj) def Tag(self, tag): assert id(tag) not in self.visited self.visited[id(tag)] = 1 tagname = getattr(tag, 'xmlname', tag.__class__.__name__) if tag: self.write(u'<%s%s>' % (tagname, self.attributes(tag))) map(self.visit, tag) self.write(u'' % tagname) else: self.write(u'<%s%s/>' % (tagname, self.attributes(tag))) def attributes(self, tag): l = [] # serialize attributes items = tag.attr.items() items.sort() for name, value in items: if not name.startswith('_'): if name.endswith('_'): name = name[:-1] l.append(u' %s="%s"' % (name, escape(unicode(value)))) return u"".join(l) class IndentedUnicodeVisitor(UnicodeVisitor): def __init__(self, write, indent=2, curindent=0): self.indent = indent self.curindent = curindent super(IndentedUnicodeVisitor, self).__init__(write) def Tag(self, tag): assert id(tag) not in self.visited if self.curindent: self.write("\n" + u' ' * self.curindent) tagname = getattr(tag, 'xmlname', tag.__class__.__name__) if tag: self.curindent += self.indent self.write(u'<%s%s>' % (tagname, self.attributes(tag))) map(self.visit, tag) self.write(u'' % tagname) self.curindent -= self.indent else: self.write(u'<%s%s/>' % (tagname, self.attributes(tag))) class _escape: def __init__(self): self.escape = { u'"' : u'"', u'<' : u'<', u'>' : u'>', u'&' : u'&', u"'" : u''', } self.charef_rex = re.compile(u"|".join(self.escape.keys())) def _replacer(self, match): return self.escape[match.group(0)] def __call__(self, ustring): """ xml-escape the given unicode string. """ return self.charef_rex.sub(self._replacer, ustring) escape = _escape()