from xml sax import contenthandlerparse class recipehandler(contenthandler)def startdocument(self)self initem false def startelement(self,name,attrs)if name ='item'self num attrs get('num',' 'self units attrs get('units','none'self text [self initem true def endelement(self,name)if name ='item'text "join(self textif self units ='none'self units "unitstr "% % (self numself unitsprint("%- % (unitstr,text strip())self initem false def characters(self,data)if self initemself text append(dataparse("recipe xml",recipehandler()notes the xml sax module has many more features for working with different kinds of xml data and creating custom parsers for examplethere are handler objects that can be defined to parse dtd data and other parts of the document more information can be found in the online documentation xml sax saxutils the xml sax saxutils module defines some utility functions and objects that are often used with sax parsersbut are often generally useful elsewhere escape(data [entities]given stringdatathis function replaces certain characters with escape sequences for example'<gets replaced by '&lt;entities is an optional dictionary that maps characters to the escape sequences for examplesetting entities to '\xf '&ntilde;would replace occurences of with '&ntilde;unescape(data [entities]unescapes special escape sequences that appear in data for instance'&lt;is replaced by '<entities is an optional dictionary mapping entities to unescaped character values entities is the inverse of the dictionary used with escape()--for example'&ntilde; '\xf quoteattr(data [entities]escapes the string databut performs additional processing that allows the result value to be used as an xml attribute value the return value can be printed directly as an attribute value--for exampleprint "quoteattr(somevalueentities is dictionary compatible for use with the escape(function lib fl ff