2 A library of useful helper classes to the SAX classes, for the
3 convenience of application and driver writers.
6 import os
, urlparse
, urllib
, types
11 _StringTypes
= [types
.StringType
, types
.UnicodeType
]
12 except AttributeError:
13 _StringTypes
= [types
.StringType
]
16 def escape(data
, entities
={}):
17 """Escape &, <, and > in a string of data.
19 You can escape other strings of data by passing a dictionary as
20 the optional entities parameter. The keys and values must all be
21 strings; each key will be replaced with its corresponding value.
23 data
= data
.replace("&", "&")
24 data
= data
.replace("<", "<")
25 data
= data
.replace(">", ">")
26 for chars
, entity
in entities
.items():
27 data
= data
.replace(chars
, entity
)
31 class XMLGenerator(handler
.ContentHandler
):
33 def __init__(self
, out
=None, encoding
="iso-8859-1"):
37 handler
.ContentHandler
.__init
__(self
)
39 self
._ns
_contexts
= [{}] # contains uri -> prefix dicts
40 self
._current
_context
= self
._ns
_contexts
[-1]
41 self
._undeclared
_ns
_maps
= []
42 self
._encoding
= encoding
44 # ContentHandler methods
46 def startDocument(self
):
47 self
._out
.write('<?xml version="1.0" encoding="%s"?>\n' %
50 def startPrefixMapping(self
, prefix
, uri
):
51 self
._ns
_contexts
.append(self
._current
_context
.copy())
52 self
._current
_context
[uri
] = prefix
53 self
._undeclared
_ns
_maps
.append((prefix
, uri
))
55 def endPrefixMapping(self
, prefix
):
56 self
._current
_context
= self
._ns
_contexts
[-1]
57 del self
._ns
_contexts
[-1]
59 def startElement(self
, name
, attrs
):
60 self
._out
.write('<' + name
)
61 for (name
, value
) in attrs
.items():
62 self
._out
.write(' %s="%s"' % (name
, escape(value
)))
65 def endElement(self
, name
):
66 self
._out
.write('</%s>' % name
)
68 def startElementNS(self
, name
, qname
, attrs
):
70 # if the name was not namespace-scoped, use the unqualified part
73 # else try to restore the original prefix from the namespace
74 name
= self
._current
_context
[name
[0]] + ":" + name
[1]
75 self
._out
.write('<' + name
)
77 for pair
in self
._undeclared
_ns
_maps
:
78 self
._out
.write(' xmlns:%s="%s"' % pair
)
79 self
._undeclared
_ns
_maps
= []
81 for (name
, value
) in attrs
.items():
82 name
= self
._current
_context
[name
[0]] + ":" + name
[1]
83 self
._out
.write(' %s="%s"' % (name
, escape(value
)))
86 def endElementNS(self
, name
, qname
):
90 name
= self
._current
_context
[name
[0]] + ":" + name
[1]
91 self
._out
.write('</%s>' % name
)
93 def characters(self
, content
):
94 self
._out
.write(escape(content
))
96 def ignorableWhitespace(self
, content
):
97 self
._out
.write(content
)
99 def processingInstruction(self
, target
, data
):
100 self
._out
.write('<?%s %s?>' % (target
, data
))
103 class XMLFilterBase(xmlreader
.XMLReader
):
104 """This class is designed to sit between an XMLReader and the
105 client application's event handlers. By default, it does nothing
106 but pass requests up to the reader and events on to the handlers
107 unmodified, but subclasses can override specific methods to modify
108 the event stream or the configuration requests as they pass
111 def __init__(self
, parent
= None):
112 xmlreader
.XMLReader
.__init
__(self
)
113 self
._parent
= parent
115 # ErrorHandler methods
117 def error(self
, exception
):
118 self
._err
_handler
.error(exception
)
120 def fatalError(self
, exception
):
121 self
._err
_handler
.fatalError(exception
)
123 def warning(self
, exception
):
124 self
._err
_handler
.warning(exception
)
126 # ContentHandler methods
128 def setDocumentLocator(self
, locator
):
129 self
._cont
_handler
.setDocumentLocator(locator
)
131 def startDocument(self
):
132 self
._cont
_handler
.startDocument()
134 def endDocument(self
):
135 self
._cont
_handler
.endDocument()
137 def startPrefixMapping(self
, prefix
, uri
):
138 self
._cont
_handler
.startPrefixMapping(prefix
, uri
)
140 def endPrefixMapping(self
, prefix
):
141 self
._cont
_handler
.endPrefixMapping(prefix
)
143 def startElement(self
, name
, attrs
):
144 self
._cont
_handler
.startElement(name
, attrs
)
146 def endElement(self
, name
):
147 self
._cont
_handler
.endElement(name
)
149 def startElementNS(self
, name
, qname
, attrs
):
150 self
._cont
_handler
.startElement(name
, attrs
)
152 def endElementNS(self
, name
, qname
):
153 self
._cont
_handler
.endElementNS(name
, qname
)
155 def characters(self
, content
):
156 self
._cont
_handler
.characters(content
)
158 def ignorableWhitespace(self
, chars
):
159 self
._cont
_handler
.ignorableWhitespace(chars
)
161 def processingInstruction(self
, target
, data
):
162 self
._cont
_handler
.processingInstruction(target
, data
)
164 def skippedEntity(self
, name
):
165 self
._cont
_handler
.skippedEntity(name
)
169 def notationDecl(self
, name
, publicId
, systemId
):
170 self
._dtd
_handler
.notationDecl(name
, publicId
, systemId
)
172 def unparsedEntityDecl(self
, name
, publicId
, systemId
, ndata
):
173 self
._dtd
_handler
.unparsedEntityDecl(name
, publicId
, systemId
, ndata
)
175 # EntityResolver methods
177 def resolveEntity(self
, publicId
, systemId
):
178 self
._ent
_handler
.resolveEntity(publicId
, systemId
)
182 def parse(self
, source
):
183 self
._parent
.setContentHandler(self
)
184 self
._parent
.setErrorHandler(self
)
185 self
._parent
.setEntityResolver(self
)
186 self
._parent
.setDTDHandler(self
)
187 self
._parent
.parse(source
)
189 def setLocale(self
, locale
):
190 self
._parent
.setLocale(locale
)
192 def getFeature(self
, name
):
193 return self
._parent
.getFeature(name
)
195 def setFeature(self
, name
, state
):
196 self
._parent
.setFeature(name
, state
)
198 def getProperty(self
, name
):
199 return self
._parent
.getProperty(name
)
201 def setProperty(self
, name
, value
):
202 self
._parent
.setProperty(name
, value
)
209 def setParent(self
, parent
):
210 self
._parent
= parent
212 # --- Utility functions
214 def prepare_input_source(source
, base
= ""):
215 """This function takes an InputSource and an optional base URL and
216 returns a fully resolved InputSource object ready for reading."""
218 if type(source
) in _StringTypes
:
219 source
= xmlreader
.InputSource(source
)
220 elif hasattr(source
, "read"):
222 source
= xmlreader
.InputSource()
223 source
.setByteStream(f
)
224 if hasattr(f
, "name"):
225 source
.setSystemId(f
.name
)
227 if source
.getByteStream() is None:
228 sysid
= source
.getSystemId()
229 if os
.path
.isfile(sysid
):
230 basehead
= os
.path
.split(os
.path
.normpath(base
))[0]
231 source
.setSystemId(os
.path
.join(basehead
, sysid
))
232 f
= open(sysid
, "rb")
234 source
.setSystemId(urlparse
.urljoin(base
, sysid
))
235 f
= urllib
.urlopen(source
.getSystemId())
237 source
.setByteStream(f
)