Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 129 lines (107 sloc) 4.486 kB
72acd3a @acspike first commit
authored
1 #
2 # Escape: implements just enough of the deliverance concept to be useful
3 # Copyright (c) 2010 Aaron C Spike <aaron@ekips.org>
4 #
5 # WSGI Code patterned after the XSLT Middleware found at
6 # http://www.decafbad.com/2005/07/xmlwiki/lib/xmlwiki/xslfilter.py
7 #
8
9
a31a195 @acspike allow append to work with attribute nodes; use the root node rather t…
authored
10 from xml.dom.minidom import parseString, Node
72acd3a @acspike first commit
authored
11 from xml.parsers.expat import ExpatError
12
13 import xpath
14
15
16 def append(from_doc, from_path, to_doc, to_path):
17 '''append one or more nodes from the source doc to a node in the destination doc'''
18 to_node = xpath.findnode(to_path, to_doc)
19 if to_node:
20 from_nodes = xpath.find(from_path, from_doc)
21 for x in from_nodes:
a31a195 @acspike allow append to work with attribute nodes; use the root node rather t…
authored
22 if x.nodeType == Node.ATTRIBUTE_NODE:
23 to_node.setAttribute(x.name, x.value)
24 else:
25 to_node.appendChild(x)
72acd3a @acspike first commit
authored
26
27 def prepend(from_doc, from_path, to_doc, to_path):
28 '''append one or more nodes from the source doc to a node in the destination doc'''
35c6da3 @acspike implement prepend() and replace()
authored
29 to_node = xpath.findnode(to_path, to_doc)
30 if to_node:
31 from_nodes = xpath.find(from_path, from_doc)
32 first = to_node.firstChild
33 if first:
34 for x in from_nodes:
35 to_node.insertBefore(x, first)
36 else:
37 for x in from_nodes:
38 to_node.appendChild(x)
72acd3a @acspike first commit
authored
39
40 def replace(from_doc, from_path, to_doc, to_path):
41 '''replace one node in the destination doc with one or more nodes from the source doc'''
35c6da3 @acspike implement prepend() and replace()
authored
42 to_node = xpath.findnode(to_path, to_doc)
43 if to_node:
44 parent = to_node.parentNode
45 from_nodes = xpath.find(from_path, from_doc)
46 for x in from_nodes:
47 parent.insertBefore(x, to_node)
48 parent.removeChild(to_node)
72acd3a @acspike first commit
authored
49
50 def drop(from_doc, from_path):
51 '''drop one or more nodes from a doc'''
52 from_nodes = xpath.find(from_path, from_doc)
53 for x in from_nodes:
54 x.parentNode.removeChild(x)
55
56
57 class Filter(object):
58 def __init__(self, wrapped_app):
59 self.wrapped_app = wrapped_app
60 self.status = '200 OK'
61 self.headers = []
62 self.exc_info = None
2e4dc56 @acspike implement and use the write() callable specified in the WSGI PEP
authored
63 self.body = []
72acd3a @acspike first commit
authored
64 # ruleset: list of tuples in the form (test(status, headers, env), transform(doc, template), template_str)
65 self.ruleset = []
2e4dc56 @acspike implement and use the write() callable specified in the WSGI PEP
authored
66
67 def write(self, body):
68 self.body.append(body)
69
72acd3a @acspike first commit
authored
70 def start_response(self, status, response_headers, exc_info=None):
71 self.status = status
72 self.headers = response_headers
73 self.exc_info = exc_info
2e4dc56 @acspike implement and use the write() callable specified in the WSGI PEP
authored
74 return self.write
72acd3a @acspike first commit
authored
75
76 def __call__(self, environ, start_response):
77 self.environ = environ
78 self.server_start_response = start_response
79 return self.__iter__()
80
81 def __iter__(self):
82 input_iter = self.wrapped_app(self.environ, self.start_response).__iter__()
83 output_headers = []
84
85 # check rules to see if any apply
86 rules = []
87 for rule in self.ruleset:
88 if rule[0](self.status, self.headers, self.environ):
89 rules.append(rule)
90
91 # if there are applicable rules
92 # try parsing
93 input_doc = None
94 if rules:
95 try:
2e4dc56 @acspike implement and use the write() callable specified in the WSGI PEP
authored
96 input_str = ''.join(self.body) + ''.join(list(input_iter))
a31a195 @acspike allow append to work with attribute nodes; use the root node rather t…
authored
97 input_doc = parseString(input_str)
72acd3a @acspike first commit
authored
98 except ExpatError:
99 pass
100
101 # if no rules or parse failure return original
102 if len(rules)==0 or input_doc is None:
103 output_headers = self.headers
104 output_iter = input_iter
105 else:
106 # apply applicable rules in turn
107 for rule in rules:
108 test, transform, template_str = rule
109 try:
a31a195 @acspike allow append to work with attribute nodes; use the root node rather t…
authored
110 template_doc = parseString(template_str)
72acd3a @acspike first commit
authored
111 except ExpatError:
112 continue
113 transform(input_doc, template_doc)
114 input_doc = template_doc
115
116 # back to xml
117 output = input_doc.toxml()
118 output_iter = [output].__iter__()
119
120 # copy headers to output and adjust length
121 for header_name,header_value in self.headers:
122 if header_name.lower() == 'content-length':
123 header_value = len(output)
124 output_headers.append((header_name,header_value))
125
2e4dc56 @acspike implement and use the write() callable specified in the WSGI PEP
authored
126 server_write = self.server_start_response(self.status, output_headers, self.exc_info)
72acd3a @acspike first commit
authored
127 return output_iter
128
Something went wrong with that request. Please try again.