115 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			115 lines
		
	
	
		
			3.5 KiB
		
	
	
	
		
			Python
		
	
	
	
| # 
 | |
| # a generic conversion serializer 
 | |
| #
 | |
| 
 | |
| import sys
 | |
| from py.xml import escape 
 | |
| 
 | |
| if sys.version_info > (3, 0):
 | |
|     def u(s):
 | |
|         return s
 | |
| else:
 | |
|     def u(s):
 | |
|         return unicode(s)
 | |
| 
 | |
| class SimpleUnicodeVisitor(object):
 | |
|     """ recursive visitor to write unicode. """
 | |
|     def __init__(self, write, indent=0, curindent=0, shortempty=True): 
 | |
|         self.write = write
 | |
|         self.cache = {}
 | |
|         self.visited = {} # for detection of recursion
 | |
|         self.indent = indent 
 | |
|         self.curindent = curindent
 | |
|         self.parents = []
 | |
|         self.shortempty = shortempty  # short empty tags or not 
 | |
| 
 | |
|     def visit(self, node): 
 | |
|         """ dispatcher on node's class/bases name. """
 | |
|         cls = node.__class__
 | |
|         try:
 | |
|             visitmethod = self.cache[cls]   
 | |
|         except KeyError:
 | |
|             for subclass in cls.__mro__: 
 | |
|                 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(obj) 
 | |
|         self.write(escape(unicode(obj)))
 | |
| 
 | |
|     def raw(self, obj):
 | |
|         self.write(obj.uniobj) 
 | |
| 
 | |
|     def list(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
 | |
|         try: 
 | |
|             tag.parent = self.parents[-1]
 | |
|         except IndexError: 
 | |
|             tag.parent = None 
 | |
|         self.visited[id(tag)] = 1
 | |
|         tagname = getattr(tag, 'xmlname', tag.__class__.__name__)
 | |
|         if self.curindent and not self._isinline(tagname):
 | |
|             self.write("\n" + u(' ') * self.curindent) 
 | |
|         if tag:
 | |
|             self.curindent += self.indent 
 | |
|             self.write(u('<%s%s>') % (tagname, self.attributes(tag)))
 | |
|             self.parents.append(tag) 
 | |
|             map(self.visit, tag)
 | |
|             self.parents.pop() 
 | |
|             self.write(u('</%s>') % tagname) 
 | |
|             self.curindent -= self.indent 
 | |
|         else:
 | |
|             nameattr = tagname+self.attributes(tag) 
 | |
|             if self._issingleton(tagname): 
 | |
|                 self.write(u('<%s/>') % (nameattr,))
 | |
|             else: 
 | |
|                 self.write(u('<%s></%s>') % (nameattr, tagname))
 | |
| 
 | |
|     def attributes(self, tag):
 | |
|         # serialize attributes
 | |
|         attrlist = dir(tag.attr) 
 | |
|         attrlist.sort() 
 | |
|         l = []
 | |
|         for name in attrlist: 
 | |
|             res = self.repr_attribute(tag.attr, name)
 | |
|             if res is not None: 
 | |
|                 l.append(res) 
 | |
|         l.extend(self.getstyle(tag))
 | |
|         return u("").join(l)
 | |
| 
 | |
|     def repr_attribute(self, attrs, name): 
 | |
|         if name[:2] != '__': 
 | |
|             value = getattr(attrs, name) 
 | |
|             if name.endswith('_'): 
 | |
|                 name = name[:-1]
 | |
|             return u(' %s="%s"') % (name, escape(unicode(value)))
 | |
| 
 | |
|     def getstyle(self, tag): 
 | |
|         """ return attribute list suitable for styling. """ 
 | |
|         try: 
 | |
|             styledict = tag.style.__dict__
 | |
|         except AttributeError: 
 | |
|             return [] 
 | |
|         else: 
 | |
|             stylelist = [x+': ' + y for x,y in styledict.items()]
 | |
|             return [u(' style="%s"') % u('; ').join(stylelist)]
 | |
| 
 | |
|     def _issingleton(self, tagname):
 | |
|         """can (and will) be overridden in subclasses"""
 | |
|         return self.shortempty
 | |
| 
 | |
|     def _isinline(self, tagname):
 | |
|         """can (and will) be overridden in subclasses"""
 | |
|         return False
 | |
| 
 |