cmlenz@1: # -*- coding: utf-8 -*- cmlenz@1: # cmlenz@1: # Copyright (C) 2006 Christopher Lenz cmlenz@1: # All rights reserved. cmlenz@1: # cmlenz@1: # This software is licensed as described in the file COPYING, which cmlenz@1: # you should have received as part of this distribution. The terms cmlenz@27: # are also available at http://markup.cmlenz.net/wiki/License. cmlenz@1: # cmlenz@1: # This software consists of voluntary contributions made by many cmlenz@1: # individuals. For the exact contribution history, see the revision cmlenz@27: # history and logs, available at http://markup.cmlenz.net/log/. cmlenz@1: cmlenz@19: from markup.core import Attributes, Namespace, QName, Stream cmlenz@1: cmlenz@1: __all__ = ['Fragment', 'Element', 'tag'] cmlenz@1: cmlenz@1: cmlenz@1: class Fragment(object): cmlenz@28: """Represents a markup fragment, which is basically just a list of element cmlenz@28: or text nodes. cmlenz@28: """ cmlenz@1: __slots__ = ['children'] cmlenz@1: cmlenz@1: def __init__(self): cmlenz@1: self.children = [] cmlenz@1: cmlenz@65: def __add__(self, other): cmlenz@65: return Fragment()(self, other) cmlenz@65: cmlenz@65: def __call__(self, *args): cmlenz@65: for arg in args: cmlenz@65: self.append(arg) cmlenz@65: return self cmlenz@65: cmlenz@65: def __iter__(self): cmlenz@65: return iter(self.generate()) cmlenz@65: cmlenz@65: def __repr__(self): cmlenz@65: return '<%s>' % self.__class__.__name__ cmlenz@65: cmlenz@65: def __str__(self): cmlenz@65: return str(self.generate()) cmlenz@65: cmlenz@65: def __unicode__(self): cmlenz@65: return unicode(self.generate()) cmlenz@65: cmlenz@1: def append(self, node): cmlenz@1: """Append an element or string as child node.""" cmlenz@1: if isinstance(node, (Element, basestring, int, float, long)): cmlenz@1: # For objects of a known/primitive type, we avoid the check for cmlenz@1: # whether it is iterable for better performance cmlenz@1: self.children.append(node) cmlenz@1: elif isinstance(node, Fragment): cmlenz@1: self.children += node.children cmlenz@1: elif node is not None: cmlenz@1: try: cmlenz@1: children = iter(node) cmlenz@1: except TypeError: cmlenz@1: self.children.append(node) cmlenz@1: else: cmlenz@1: for child in node: cmlenz@1: self.append(children) cmlenz@1: cmlenz@1: def generate(self): cmlenz@28: """Return a markup event stream for the fragment.""" cmlenz@1: def _generate(): cmlenz@1: for child in self.children: cmlenz@1: if isinstance(child, Fragment): cmlenz@1: for event in child.generate(): cmlenz@1: yield event cmlenz@1: else: cmlenz@17: yield Stream.TEXT, unicode(child), (-1, -1) cmlenz@1: return Stream(_generate()) cmlenz@1: cmlenz@1: cmlenz@1: class Element(Fragment): cmlenz@1: """Simple XML output generator based on the builder pattern. cmlenz@1: cmlenz@1: Construct XML elements by passing the tag name to the constructor: cmlenz@1: cmlenz@1: >>> print Element('strong') cmlenz@1: cmlenz@1: cmlenz@1: Attributes can be specified using keyword arguments. The values of the cmlenz@1: arguments will be converted to strings and any special XML characters cmlenz@1: escaped: cmlenz@1: cmlenz@1: >>> print Element('textarea', rows=10, cols=60) cmlenz@1: