Beginning Python - From Novice to Professional
Beginning Python - From Novice to Professional Beginning Python - From Novice to Professional
CHAPTER 22 ■ PROJECT 3: XML FOR ALL OCCASIONS 431 In addition, some care should be taken with the parameters. The custom handlers (for example, startFoo) do not need the tag name as a parameter, while the custom default handlers (for example, defaultStart) do. Also, only the start handlers need the attributes. Confused? Let’s begin by writing the simplest parts of the class: class Dispatcher: # ... def startElement(self, name, attrs): self.dispatch('start', name, attrs) def endElement(self, name): self.dispatch('end', name) Here, the basic event handlers are implemented, and they simply call a method called dispatch, which takes care of finding the appropriate handler, constructing the argument tuple, and then calling the handler with those arguments. Here is the code for the dispatch method: def dispatch(self, prefix, name, attrs=None): mname = prefix + name.capitalize() dname = 'default' + prefix.capitalize() method = getattr(self, mname, None) if callable(method): args = () else: method = getattr(self, dname, None) args = name, if prefix == 'start': args += attrs, if callable(method): method(*args) What happens is this: 1. From a prefix (either 'start' or 'end') and a tag name (for example, 'page'), construct the method name of the handler (for example, 'startPage'). 2. Using the same prefix, construct the name of the default handler (for example, 'defaultStart'). 3. Try to get the handler with getattr, using None as the default value. 4. If the result is callable, assign an empty tuple to args. 5. Otherwise, try to get the default handler with getattr, again using None as the default value. Also, set args to a tuple containing only the tag name (because the default handler needs that). 6. If you are dealing with a start handler, add the attributes to the argument tuple (args). 7. If your handler is callable (that is, it is either a viable specific handler, or a viable default handler), call it with the correct arguments.
432 CHAPTER 22 ■ PROJECT 3: XML FOR ALL OCCASIONS Got that? This basically means that you can now write content handlers like this: class TestHandler(Dispatcher, ContentHandler): def startPage(self, attrs): print 'Beginning page', attrs['name'] def endPage(self): print 'Ending page' Because the dispatcher mix-in takes care of most of the plumbing, the content handler is fairly simple and readable. (Of course, you’ll add more functionality in a little while.) Factoring Out the Header, Footer, and Default Handling This section is much easier than the previous one. Instead of doing the calls to self.out.write directly in the event handler, we’ll create separate methods for writing the header and footer. That way you can easily override these methods by subclassing the event handler. Let’s make the default header and footer really simple: def writeHeader(self, title): self.out.write("\n \n ") self.out.write(title) self.out.write("\n \n \n") def writeFooter(self): self.out.write("\n \n\n") Handling of the XHTML contents was also linked a bit too intimately with our original handlers. The XHTML will now be handled by defaultStart and defaultEnd: def defaultStart(self, name, attrs): if self.passthrough: self.out.write('') def defaultEnd(self, name): if self.passthrough: self.out.write('' % name) This works just like before, except that I’ve moved the code to separate methods (which is usually a good thing). Now, on to the last piece of the puzzle. Support for Directories To create the necessary directories, you need a couple of useful functions from the os and os.path modules. One of these functions is os.makedirs, which makes all the necessary directories in a given path. For example, os.makedirs('foo/bar/baz') creates the directory foo in the
- Page 412 and 413: CHAPTER 19 ■ ■ ■ Playful Prog
- Page 414 and 415: CHAPTER 19 ■ PLAYFUL PROGRAMMING
- Page 416 and 417: CHAPTER 19 ■ PLAYFUL PROGRAMMING
- Page 418 and 419: CHAPTER 19 ■ PLAYFUL PROGRAMMING
- Page 420: CHAPTER 19 ■ PLAYFUL PROGRAMMING
- Page 423 and 424: 392 CHAPTER 20 ■ PROJECT 1: INSTA
- Page 425 and 426: 394 CHAPTER 20 ■ PROJECT 1: INSTA
- Page 427 and 428: 396 CHAPTER 20 ■ PROJECT 1: INSTA
- Page 429 and 430: 398 CHAPTER 20 ■ PROJECT 1: INSTA
- Page 431 and 432: 400 CHAPTER 20 ■ PROJECT 1: INSTA
- Page 433 and 434: 402 CHAPTER 20 ■ PROJECT 1: INSTA
- Page 435 and 436: 404 CHAPTER 20 ■ PROJECT 1: INSTA
- Page 437 and 438: 406 CHAPTER 20 ■ PROJECT 1: INSTA
- Page 439 and 440: 408 CHAPTER 20 ■ PROJECT 1: INSTA
- Page 442 and 443: CHAPTER 21 ■ ■ ■ Project 2: P
- Page 444 and 445: CHAPTER 21 ■ PROJECT 2: PAINTING
- Page 446 and 447: CHAPTER 21 ■ PROJECT 2: PAINTING
- Page 448 and 449: CHAPTER 21 ■ PROJECT 2: PAINTING
- Page 450 and 451: CHAPTER 21 ■ PROJECT 2: PAINTING
- Page 452 and 453: CHAPTER 22 ■ ■ ■ Project 3: X
- Page 454 and 455: CHAPTER 22 ■ PROJECT 3: XML FOR A
- Page 456 and 457: CHAPTER 22 ■ PROJECT 3: XML FOR A
- Page 458 and 459: CHAPTER 22 ■ PROJECT 3: XML FOR A
- Page 460 and 461: CHAPTER 22 ■ PROJECT 3: XML FOR A
- Page 464 and 465: CHAPTER 22 ■ PROJECT 3: XML FOR A
- Page 466 and 467: CHAPTER 22 ■ PROJECT 3: XML FOR A
- Page 468: CHAPTER 22 ■ PROJECT 3: XML FOR A
- Page 471 and 472: 440 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 473 and 474: 442 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 475 and 476: 444 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 477 and 478: 446 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 479 and 480: 448 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 481 and 482: 450 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 483 and 484: 452 CHAPTER 23 ■ PROJECT 4: IN TH
- Page 486 and 487: CHAPTER 24 ■ ■ ■ Project 5: A
- Page 488 and 489: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 490 and 491: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 492 and 493: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 494 and 495: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 496 and 497: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 498 and 499: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 500 and 501: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 502 and 503: CHAPTER 24 ■ PROJECT 5: A VIRTUAL
- Page 504 and 505: CHAPTER 25 ■ ■ ■ Project 6: R
- Page 506 and 507: CHAPTER 25 ■ PROJECT 6: REMOTE ED
- Page 508 and 509: CHAPTER 25 ■ PROJECT 6: REMOTE ED
- Page 510 and 511: CHAPTER 25 ■ PROJECT 6: REMOTE ED
CHAPTER 22 ■ PROJECT 3: XML FOR ALL OCCASIONS 431<br />
In addition, some care should be taken with the parameters. The cus<strong>to</strong>m handlers (for<br />
example, startFoo) do not need the tag name as a parameter, while the cus<strong>to</strong>m default handlers<br />
(for example, defaultStart) do. Also, only the start handlers need the attributes.<br />
Confused? Let’s begin by writing the simplest parts of the class:<br />
class Dispatcher:<br />
# ...<br />
def startElement(self, name, attrs):<br />
self.dispatch('start', name, attrs)<br />
def endElement(self, name):<br />
self.dispatch('end', name)<br />
Here, the basic event handlers are implemented, and they simply call a method called<br />
dispatch, which takes care of finding the appropriate handler, constructing the argument tuple,<br />
and then calling the handler with those arguments. Here is the code for the dispatch method:<br />
def dispatch(self, prefix, name, attrs=None):<br />
mname = prefix + name.capitalize()<br />
dname = 'default' + prefix.capitalize()<br />
method = getattr(self, mname, None)<br />
if callable(method): args = ()<br />
else:<br />
method = getattr(self, dname, None)<br />
args = name,<br />
if prefix == 'start': args += attrs,<br />
if callable(method): method(*args)<br />
What happens is this:<br />
1. <strong>From</strong> a prefix (either 'start' or 'end') and a tag name (for example, 'page'), construct<br />
the method name of the handler (for example, 'startPage').<br />
2. Using the same prefix, construct the name of the default handler (for example,<br />
'defaultStart').<br />
3. Try <strong>to</strong> get the handler with getattr, using None as the default value.<br />
4. If the result is callable, assign an empty tuple <strong>to</strong> args.<br />
5. Otherwise, try <strong>to</strong> get the default handler with getattr, again using None as the default<br />
value. Also, set args <strong>to</strong> a tuple containing only the tag name (because the default<br />
handler needs that).<br />
6. If you are dealing with a start handler, add the attributes <strong>to</strong> the argument tuple (args).<br />
7. If your handler is callable (that is, it is either a viable specific handler, or a viable default<br />
handler), call it with the correct arguments.