blob: 8f8f42e811a60b67a22165c1f18ad49959b33022 [file] [log] [blame]
Fred Drakea12adfe2000-09-18 17:40:22 +00001"""\
2A library of useful helper classes to the SAX classes, for the
Fred Drake45cd9de2000-06-29 19:34:54 +00003convenience of application and driver writers.
Fred Drake45cd9de2000-06-29 19:34:54 +00004"""
5
Lars Gustäbel523b0a62000-09-24 18:54:49 +00006import os, urlparse, urllib
Fred Drake45cd9de2000-06-29 19:34:54 +00007import handler
Lars Gustäbelfc643c32000-09-24 10:53:31 +00008import xmlreader
Fred Drakea12adfe2000-09-18 17:40:22 +00009
10def escape(data, entities={}):
Fred Drake45cd9de2000-06-29 19:34:54 +000011 """Escape &, <, and > in a string of data.
Fred Drakea12adfe2000-09-18 17:40:22 +000012
Fred Drake45cd9de2000-06-29 19:34:54 +000013 You can escape other strings of data by passing a dictionary as
14 the optional entities parameter. The keys and values must all be
15 strings; each key will be replaced with its corresponding value.
16 """
Fred Drakea12adfe2000-09-18 17:40:22 +000017 data = data.replace("&", "&amp;")
18 data = data.replace("<", "&lt;")
19 data = data.replace(">", "&gt;")
Fred Drake45cd9de2000-06-29 19:34:54 +000020 for chars, entity in entities.items():
Fred Drakea12adfe2000-09-18 17:40:22 +000021 data = data.replace(chars, entity)
Fred Drake45cd9de2000-06-29 19:34:54 +000022 return data
23
Fred Drakea12adfe2000-09-18 17:40:22 +000024
Fred Drake45cd9de2000-06-29 19:34:54 +000025class XMLGenerator(handler.ContentHandler):
26
Lars Gustäbelc5cec512000-09-21 08:25:28 +000027 def __init__(self, out=None, encoding="iso-8859-1"):
Fred Drakea12adfe2000-09-18 17:40:22 +000028 if out is None:
29 import sys
30 out = sys.stdout
Fred Drake45cd9de2000-06-29 19:34:54 +000031 handler.ContentHandler.__init__(self)
32 self._out = out
Lars Gustäbelc5cec512000-09-21 08:25:28 +000033 self._ns_contexts = [{}] # contains uri -> prefix dicts
34 self._current_context = self._ns_contexts[-1]
Lars Gustäbelfc643c32000-09-24 10:53:31 +000035 self._undeclared_ns_maps = []
Lars Gustäbelc5cec512000-09-21 08:25:28 +000036 self._encoding = encoding
Fred Drake45cd9de2000-06-29 19:34:54 +000037
38 # ContentHandler methods
Fred Drakea12adfe2000-09-18 17:40:22 +000039
Fred Drake45cd9de2000-06-29 19:34:54 +000040 def startDocument(self):
Lars Gustäbelc5cec512000-09-21 08:25:28 +000041 self._out.write('<?xml version="1.0" encoding="%s"?>\n' %
42 self._encoding)
Fred Drake45cd9de2000-06-29 19:34:54 +000043
44 def startPrefixMapping(self, prefix, uri):
Lars Gustäbelc5cec512000-09-21 08:25:28 +000045 self._ns_contexts.append(self._current_context.copy())
46 self._current_context[uri] = prefix
Lars Gustäbelfc643c32000-09-24 10:53:31 +000047 self._undeclared_ns_maps.append((prefix, uri))
Fred Drake45cd9de2000-06-29 19:34:54 +000048
49 def endPrefixMapping(self, prefix):
Lars Gustäbelfc643c32000-09-24 10:53:31 +000050 self._current_context = self._ns_contexts[-1]
51 del self._ns_contexts[-1]
Fred Drake45cd9de2000-06-29 19:34:54 +000052
53 def startElement(self, name, attrs):
Fred Drake45cd9de2000-06-29 19:34:54 +000054 self._out.write('<' + name)
55 for (name, value) in attrs.items():
56 self._out.write(' %s="%s"' % (name, escape(value)))
57 self._out.write('>')
Lars Gustäbelc5cec512000-09-21 08:25:28 +000058
Fred Drake45cd9de2000-06-29 19:34:54 +000059 def endElement(self, name):
Fred Drake45cd9de2000-06-29 19:34:54 +000060 self._out.write('</%s>' % name)
61
Lars Gustäbelc5cec512000-09-21 08:25:28 +000062 def startElementNS(self, name, qname, attrs):
63 name = self._current_context[name[0]] + ":" + name[1]
64 self._out.write('<' + name)
Lars Gustäbelfc643c32000-09-24 10:53:31 +000065
66 for pair in self._undeclared_ns_maps:
67 self._out.write(' xmlns:%s="%s"' % pair)
68 self._undeclared_ns_maps = []
69
Lars Gustäbelc5cec512000-09-21 08:25:28 +000070 for (name, value) in attrs.items():
71 name = self._current_context[name[0]] + ":" + name[1]
72 self._out.write(' %s="%s"' % (name, escape(value)))
73 self._out.write('>')
74
75 def endElementNS(self, name, qname):
76 name = self._current_context[name[0]] + ":" + name[1]
77 self._out.write('</%s>' % name)
78
Fred Drake45cd9de2000-06-29 19:34:54 +000079 def characters(self, content):
80 self._out.write(escape(content))
81
82 def ignorableWhitespace(self, content):
83 self._out.write(content)
Fred Drakea12adfe2000-09-18 17:40:22 +000084
Fred Drake45cd9de2000-06-29 19:34:54 +000085 def processingInstruction(self, target, data):
86 self._out.write('<?%s %s?>' % (target, data))
87
Fred Drakea12adfe2000-09-18 17:40:22 +000088
Lars Gustäbelfc643c32000-09-24 10:53:31 +000089class XMLFilterBase(xmlreader.XMLReader):
Fred Drake45cd9de2000-06-29 19:34:54 +000090 """This class is designed to sit between an XMLReader and the
91 client application's event handlers. By default, it does nothing
92 but pass requests up to the reader and events on to the handlers
93 unmodified, but subclasses can override specific methods to modify
94 the event stream or the configuration requests as they pass
95 through."""
96
97 # ErrorHandler methods
98
99 def error(self, exception):
100 self._err_handler.error(exception)
101
102 def fatalError(self, exception):
103 self._err_handler.fatalError(exception)
104
105 def warning(self, exception):
106 self._err_handler.warning(exception)
107
108 # ContentHandler methods
Fred Drakea12adfe2000-09-18 17:40:22 +0000109
Fred Drake45cd9de2000-06-29 19:34:54 +0000110 def setDocumentLocator(self, locator):
111 self._cont_handler.setDocumentLocator(locator)
Fred Drakea12adfe2000-09-18 17:40:22 +0000112
Fred Drake45cd9de2000-06-29 19:34:54 +0000113 def startDocument(self):
114 self._cont_handler.startDocument()
115
116 def endDocument(self):
117 self._cont_handler.endDocument()
118
119 def startPrefixMapping(self, prefix, uri):
120 self._cont_handler.startPrefixMapping(prefix, uri)
121
122 def endPrefixMapping(self, prefix):
123 self._cont_handler.endPrefixMapping(prefix)
124
125 def startElement(self, name, attrs):
126 self._cont_handler.startElement(name, attrs)
127
Lars Gustäbelc5cec512000-09-21 08:25:28 +0000128 def endElement(self, name):
129 self._cont_handler.endElement(name)
130
131 def startElementNS(self, name, qname, attrs):
132 self._cont_handler.startElement(name, attrs)
133
134 def endElementNS(self, name, qname):
135 self._cont_handler.endElementNS(name, qname)
Fred Drake45cd9de2000-06-29 19:34:54 +0000136
137 def characters(self, content):
138 self._cont_handler.characters(content)
139
Lars Gustäbelfc643c32000-09-24 10:53:31 +0000140 def ignorableWhitespace(self, chars):
141 self._cont_handler.ignorableWhitespace(chars)
Fred Drake45cd9de2000-06-29 19:34:54 +0000142
143 def processingInstruction(self, target, data):
144 self._cont_handler.processingInstruction(target, data)
145
146 def skippedEntity(self, name):
147 self._cont_handler.skippedEntity(name)
148
149 # DTDHandler methods
150
151 def notationDecl(self, name, publicId, systemId):
152 self._dtd_handler.notationDecl(name, publicId, systemId)
153
154 def unparsedEntityDecl(self, name, publicId, systemId, ndata):
155 self._dtd_handler.unparsedEntityDecl(name, publicId, systemId, ndata)
156
157 # EntityResolver methods
158
159 def resolveEntity(self, publicId, systemId):
160 self._ent_handler.resolveEntity(publicId, systemId)
161
162 # XMLReader methods
163
164 def parse(self, source):
165 self._parent.setContentHandler(self)
166 self._parent.setErrorHandler(self)
167 self._parent.setEntityResolver(self)
168 self._parent.setDTDHandler(self)
169 self._parent.parse(source)
170
171 def setLocale(self, locale):
172 self._parent.setLocale(locale)
Fred Drakea12adfe2000-09-18 17:40:22 +0000173
Fred Drake45cd9de2000-06-29 19:34:54 +0000174 def getFeature(self, name):
175 return self._parent.getFeature(name)
176
177 def setFeature(self, name, state):
178 self._parent.setFeature(name, state)
179
180 def getProperty(self, name):
181 return self._parent.getProperty(name)
182
183 def setProperty(self, name, value):
184 self._parent.setProperty(name, value)
Lars Gustäbel523b0a62000-09-24 18:54:49 +0000185
186# --- Utility functions
187
188def prepare_input_source(source, base = ""):
189 """This function takes an InputSource and an optional base URL and
190 returns a fully resolved InputSource object ready for reading."""
191
192 if type(source) == type(""):
193 source = xmlreader.InputSource(source)
194
195 if source.getByteStream() == None:
196 sysid = source.getSystemId()
197 if urlparse.urlparse(sysid)[0] == '':
198 basehead = os.path.split(os.path.normpath(base))[0]
199 source.setSystemId(os.path.join(basehead, sysid))
200 else:
201 source.setSystemId(urlparse.urljoin(base, sysid))
202
203 source.setByteStream(urllib.urlopen(source.getSystemId()))
204
205 return source