1 import itertools, StringIO
2 from wrw import dispatch
9 if isinstance(el, cons.element):
10 if el.ns not in names:
11 names[el.ns] = u"n" + unicode(nid[0])
13 for ch in el.children:
22 def flatiter(root, short=True):
27 if i >= len(el.children):
33 if isinstance(ch, cons.element):
34 if short and len(ch.children) == 0:
39 elif isinstance(ch, cons.text):
41 elif isinstance(ch, cons.raw):
44 raise Exception("Unknown object in element tree: " + el)
46 class formatter(object):
47 def __init__(self, src, nsnames=None, charset="utf-8"):
49 self.nsnames = nsnames or {}
52 self.buf = bytearray()
53 self.charset = charset
55 def write(self, text):
56 self.buf.extend(text.encode(self.charset))
58 def quotewrite(self, buf):
59 buf = buf.replace(u'&', u"&")
60 buf = buf.replace(u'<', u"<")
61 buf = buf.replace(u'>', u">")
68 ns = self.nsnames[el.ns]
72 return ns + u":" + el.name
75 qc, qt = (u"'", u"'") if u'"' in v else (u'"', u""")
77 v = v.replace(u'&', u"&")
78 v = v.replace(u'<', u"<")
79 v = v.replace(u'>', u">")
89 def attrs(self, attrs):
94 def inittag(self, el):
95 self.write(u"<" + self.elname(el))
96 attrs = el.attrs.iteritems()
99 for ns, name in self.nsnames.iteritems():
102 raise Exception("null namespace must have null name, not" + name)
104 nsnames.append((u"xmlns" if name is None else (u"xmlns:" + name), ns))
105 attrs = itertools.chain(attrs, iter(nsnames))
109 def starttag(self, el):
113 def shorttag(self, el):
117 def endtag(self, el):
118 self.write(u"</" + self.elname(el) + u">")
123 def rawcode(self, el):
127 self.write(u'<?xml version="1.0" encoding="' + self.charset + u'" ?>\n')
128 if isinstance(el, cons.doctype):
129 self.write(u'<!DOCTYPE %s PUBLIC "%s" "%s">\n' % (el.rootname,
137 def handle(self, ev, el):
155 raise StopIteration()
157 ev, el = next(self.src)
158 except StopIteration:
166 def nsname(self, el):
167 for t in type(self).__mro__:
168 ret = getattr(t, "defns", {}).get(el.ns, None)
173 ret = u"n" + unicode(self.nextns)
177 def findnsnames(self, root):
181 if isinstance(el, cons.element):
182 if el.ns not in fnames:
186 for ch in el.children:
189 if None not in rnames:
190 fnames[root.ns] = None
191 rnames[None] = root.ns
192 self.nsnames = fnames
195 def output(cls, out, root, nsnames=None, doctype=None, **kw):
196 if isinstance(doctype, cons.doctype):
198 elif doctype is not None:
199 doctype = cons.doctype(root.name, doctype[0], doctype[1])
200 src = itertools.chain(iter([("^", doctype)]), flatiter(root))
201 self = cls(src=src, nsnames=nsnames, **kw)
203 self.findnsnames(root)
209 def fragment(cls, out, root, nsnames=None, **kw):
210 self = cls(src=flatiter(root), nsnames=nsnames, **kw)
212 self.findnsnames(root)
217 def format(cls, root, **kw):
218 buf = StringIO.StringIO()
219 cls.output(buf, root, **kw)
220 return buf.getvalue()
222 class indenter(formatter):
223 def __init__(self, indent=u" ", *args, **kw):
224 super(indenter, self).__init__(*args, **kw)
231 self.last = None, None
233 def write(self, text):
234 lines = text.split(u"\n")
236 for ln in lines[:-1]:
237 self.buf.extend(ln.encode(self.charset))
238 self.buf.extend("\n")
240 self.buf.extend(lines[-1].encode(self.charset))
241 self.col += len(lines[-1])
246 self.buf.extend((u"\n" + self.curind).encode(self.charset))
250 def inlinep(self, el):
251 for ch in el.children:
252 if isinstance(ch, cons.text):
257 self.stack.append((el, self.curind, self.inline))
260 el, self.curind, self.inline = self.stack.pop()
263 def starttag(self, el):
265 if self.last[0] == "<" and self.last[1].name == el.name:
270 self.inline = self.inline or self.inlinep(el)
271 self.curind += self.indent
272 super(indenter, self).starttag(el)
274 def shorttag(self, el):
277 super(indenter, self).shorttag(el)
279 def endtag(self, el):
284 super(indenter, self).endtag(el)
287 super(indenter, self).start(el)
293 def handle(self, ev, el):
294 super(indenter, self).handle(ev, el)
297 class textindenter(indenter):
303 if len(left) + self.col > self.maxcol:
304 bp = max(self.maxcol - self.col, 0)
305 for i in xrange(bp, -1, -1):
306 if left[i].isspace():
307 while i > 0 and left[i - 1].isspace(): i -= 1
310 for i in xrange(bp + 1, len(left)):
311 if left[i].isspace():
316 self.quotewrite(left)
319 self.quotewrite(left[:i])
321 left = left[i + 1:].lstrip()
323 self.quotewrite(left)
326 class response(dispatch.restart):
331 def __init__(self, root):
332 super(response, self).__init__()
337 raise Exception("a subclass of wrw.sp.util.response must override ctype")
339 def handle(self, req):
340 ret = self.formatter.format(self.root, doctype=self.doctype, charset=self.charset)
341 req.ohead["Content-Type"] = self.ctype
342 req.ohead["Content-Length"] = len(ret)