Re: PDesk - in progress: MRU, date stamping, shortcuts, CSV plugin, file info

"Jeff Mikels" <[email protected]> Tue, 15 Aug 2006 15:24:01 -0400
Newsgroups gmane.comp.handhelds.palm.progect
Message-ID <[email protected]>
I'd like to see a two way opml plugin. I'll send you what I've got so far.

On 8/15/06, Tomas <[email protected]> wrote:
> I plan to work a bit on PDesk:
>
> 1) MRU (most recently used files) functionality known from most
> Windows programs that work with files
> 2) date stamping
> 3) slightly improving the keyboard operations (new shortcuts)
> 4) fix the CSV plugin and Treepad plugin, they shall allow for both
> import and export
>
> Considering:
> 5) File information dialogue. Also standard feature of many Windows
> apps. Not sure if useful and what it shall contain?
>
> No. 1-3 is 90% done and works on my PC. No 1 shall work on both
> Windows and Linux (?), and store 10 last used files between sessions.
>
> If you have got requests re no. 2 or 3, or objections against any of
> them, please let me know.
>
> I might also attempt to implement any other feature request you might
> have, if easy to do, but I guess in 90% of such cases it will have to
> wait for later time, or for someone else...
>
> Tomas
>
>
>
>
>
>
>
> Remember to visit Polls, Files and Bookmarks sections at http://groups.yahoo.com/group/progect. You are welcome to vote, upload your files and submit bookmarks.
> Yahoo! Groups Links
>
>
>
>
>
>
>
>


-- 
Jeff Mikels
leading people one step closer to Jesus
http://jeff.mikels.cc
http://thesouthsidechurch.org

  ----------

#one !/usr/bin/env python
__author__  = "Jeff Mikels <[email protected]>"
__version__ = "$Revision: 0.1 $"
__date__	= "2006-02-10"

from PDeskPlugin import PDeskPlugin
from Db import *
from RecordFactory import *
from string import *
import re
import sys
from wxPython.wx import *

class OPMLInOut(PDeskPlugin):
	"""
	Import a text file to a project.

	@author Jeff Mikels <[email protected]>
	@since 0.1
	@version $Revision: 0.1 $
	"""
	def __init__(self, db, tree):
		"""
		Constructor.

		@param Db db : Database to read
		@param TreePlusNode tree : root of the tree
		@since 1.0
		"""
		PDeskPlugin.__init__(self, db, tree)
		self.__exportDone = 0
		self.__exportDate = 0
		self.__exportPriority = 0
		self.__exportProgress = 0
		self.__exportNote = 0
		self.__importType = 'info'
		self.__importOverwrite = 0
		self.oldTree = db
		self.logTree(db)
		
	
	def logTree(self,db):
		self.log('current tree looks like this\n----------------------------')
		
		for item in db.db:
			self.log("\t" * item.getLevel() + item.description)
			
		self.log('------------------------------')

		
	def log(self, a):
		return
		f = open('c:\\trash\\opml.log','a')
		f.write("%s\n" % a)
		f.close()

	
	def getPluginSystemVersion():
		"""
		Don't change this method.
		It's used internally to determine the version of the plugin system.

		@return int : Minimum plugin system version to use this plugin.
		"""
		return 1 # corresponding to the beta 3


	def getName():
		"""
		This method returns the name of the plugin.

		@return string
		@since 0.1
		"""
		return "OPML Import/Export"


	def getAuthor():
		"""
		This method returns the author of the plugin.

		@return string
		@since 0.1
		"""
		return "Jeff Mikels <[email protected]>"



	def getVersion():
		"""
		This method returns the version of the plugin.

		@return string
		@since 0.1
		"""
		return "0.1"



	def getInputFormat():
		"""
		Return a specification tupple.

		@return tupple
		@since 0.1
		"""
		# return None if this plugin can't read.
		# otherwise, return a tupple with
		# - name of the input format
		# - extension of the input format
		# - textual description of the plugin input format
		# example : return ("Text", "txt", "Tabbed text...")
		return ("OPML", "opml", "Outline Markup Format")


	def getOutputFormat():
		"""
		Return a specification tupple.

		@return tupple
		@since 0.1
		"""
		# return None if this plugin can't write.
		# otherwise, return a tupple with
		# - name of the output format
		# - extension of the output format
		# - textual description of the plugin output format
		# example : return ("Text", "txt", "Tabbed text...")
		
		return ("OPML", "opml", "Outline Markup Format")

	# make these methods static
	getName = staticmethod(getName)
	getAuthor = staticmethod(getAuthor)
	getVersion = staticmethod(getVersion)
	getInputFormat = staticmethod(getInputFormat)
	getOutputFormat = staticmethod(getOutputFormat)
	getPluginSystemVersion = staticmethod(getPluginSystemVersion)



	def readPrefs(self):
		"""
		Open a preferences dialog for import.

		@return boolean : true if ok, false if the user hit cancel
		@since 1.0
		"""
		dlg = wxDialog(None, -1, _("OPML Import Preferences"))
		sizer = wxBoxSizer(wxVERTICAL)

		text = wxStaticText(dlg, -1, "Select tasks type:")
		sizer.Add(text)

		sampleList = ['info (default)', 'action', 'progress', 'numeric', 'link']
		ch = wxChoice(dlg, 40, (80, 50), choices = sampleList)
		sizer.Add(ch)

		#text2 = wxStaticText(dlg, -1, "Select properties to import:")
		#sizer.Add(text2)

		chkOverwrite = wxCheckBox(dlg, -1, _("Overwrite Current Tree"))
		sizer.Add(chkOverwrite)

		def overwriteClick(event):
			self.__importOverwrite = event.IsChecked()
			
		def choiceClick(event):
			self.__importType = event.GetString()

		EVT_CHECKBOX(dlg, chkOverwrite.GetId()	, overwriteClick)
		EVT_CHOICE(dlg, ch.GetId()		  , choiceClick)

		hs = wxBoxSizer(wxHORIZONTAL)
		hs.Add(wxButton(dlg, wxID_OK, _("OK")))
		hs.Add(wxButton(dlg, wxID_CANCEL, _("Cancel")))
		sizer.Add(hs)

		dlg.SetAutoLayout(true)
		dlg.SetSizer(sizer)
		sizer.Fit(dlg)
		sizer.SetSizeHints(dlg)

		ans = dlg.ShowModal()

		dlg.Destroy()
		return ans == wxID_OK



	def writePrefs(self):
		"""
		Open a preferences dialog for export.

		@return boolean : true if ok, false if the user hit cancel
		@since 1.6
		"""
		dlg = wxDialog(None, -1, _("Text Export Preferences"))

		sizer = wxBoxSizer(wxVERTICAL)
		chkDone = wxCheckBox(dlg, -1, _("Export done tasks"))
		sizer.Add(chkDone)
		chkDate = wxCheckBox(dlg, -1, _("Export due dates"))
		sizer.Add(chkDate)
		chkPriority = wxCheckBox(dlg, -1, _("Export priorities"))
		sizer.Add(chkPriority)
		chkProgress = wxCheckBox(dlg, -1, _("Export progress"))
		sizer.Add(chkProgress)
		chkNotes = wxCheckBox(dlg, -1, _("Export notes"))
		sizer.Add(chkNotes)

		def doneClick(event):
			self.__exportDone = event.IsChecked()
		def dateClick(event):
			self.__exportDate = event.IsChecked()
		def prioClick(event):
			self.__exportPriority = event.IsChecked()
		def progClick(event):
			self.__exportProgress = event.IsChecked()
		def noteClick(event):
			self.__exportNote = event.IsChecked()

		EVT_CHECKBOX(dlg, chkDone.GetId()	, doneClick)
		EVT_CHECKBOX(dlg, chkDate.GetId()	, dateClick)
		EVT_CHECKBOX(dlg, chkPriority.GetId(), prioClick)
		EVT_CHECKBOX(dlg, chkProgress.GetId(), progClick)
		EVT_CHECKBOX(dlg, chkNotes.GetId()	, noteClick)

		hs = wxBoxSizer(wxHORIZONTAL)
		hs.Add(wxButton(dlg, wxID_OK, _("OK")))
		hs.Add(wxButton(dlg, wxID_CANCEL, _("Cancel")))
		sizer.Add(hs)

		dlg.SetAutoLayout(true)
		dlg.SetSizer(sizer)
		sizer.Fit(dlg)
		sizer.SetSizeHints(dlg)

		ans = dlg.ShowModal()

		dlg.Destroy()
		return ans == wxID_OK



	def read(self, file, db):
		"""
		Read the db from filename (indented text file).

		@param File file : from where to read
		@param Db db : the database to fill
		@since 1.0
		"""
		
		if self.__importOverwrite == 0:
			db.db[0] = self.oldTree.db[0]
			db.db.extend(self.oldTree.db[1:])
		
		self.logTree(db)
		lastElement = len(db.db) - 1
		self.log(lastElement)
		
		self.log('reading OPML file...')
		opml = OPML()
		opml.read(file)
		data = opml.outline
		self.log('got data')
		
		
		if len(data) > 0:
			if lastElement == 0:
				db.db[lastElement].attr.hasChild = 1
			else:
				db.db[lastElement].attr.hasNext = 1
		else:
			return
		
		baseLevel = db.db[lastElement].getLevel()
	
		for i in range(len(data)):
			self.log("parsing outline element %s" % i )
			item = data[i]
			for key in item:
				self.log("%s:%s" % (key, item[key]))
			desc = item['text']
			level = item['level']
			progress = 0
			note = ''
			
			for key in item:
				if key.strip() == 'text':
					continue
				elif key.strip() == 'level':
					continue
				elif key.strip() == '_status':
					if item[key] == 'checked':
						progress = 10
				else:
					note += "%s: %s\n" % (key.strip(), item[key])

			itemType = ''
			if self.__importType == "progress":
				#print 'progress'
				itemType=(ItemType.progressType)
			elif self.__importType == "action":
				#print 'action'
				itemType=(ItemType.actionType)
			elif self.__importType == "numeric":
				#print 'numeric'
				itemType=(ItemType.numericType)
			elif self.__importType == "info (default)":
				#print 'info'
				itemType=(ItemType.informativeType)
			elif self.__importType == "link":
				#print 'link'
				itemType=(ItemType.linkType)
			else:
				#print 'info'
				itemType=(ItemType.informativeType)

			
			rec = rf.getRecord(db, description=desc)
			rec.setType(itemType)
			rec.setProgress(progress)
			rec.setLevel(level)
			self.log('setting level to %s (baselevel is %s)' % (level,baseLevel))
			rec.note = note
			
			attr = rec.getAttr()
			# find child
			attr.hasChild = i < len(data) - 1 and data[i+1]['level'] == level + 1
			# find previous if it exists
			j = i - 1
			while j > 0:
				if data[j]['level'] == level:
					attr.hasPrev = 1
					break
				elif data[j]['level'] < level:
					attr.hasPrev = 0
					break
				else:
					j -= 1
			else:
				if lastElement == 0:
					attr.hasPrev = 0
				else:
					attr.hasPrev = 1
			
			j = i + 1
			# find next if it exists
			while j < len(data):
				if data[j]['level'] == level:
					attr.hasNext = 1
					break
				elif data[j]['level'] < level:
					attr.hasNext = 0
					break
				else:
					j += 1
			else:
				attr.hasNext = 0
			
			self.log('hasChild: %s' % attr.hasChild)
			self.log('hasPrev: %s' % attr.hasPrev)
			self.log('hasNext: %s' % attr.hasNext)
			self.log('level: %s' % rec.getLevel())
			self.log('appending...')
			db.db.append(rec)
		
		f = open('c:\\trash\\opml.out','w')
		self.rawwrite(f,db)
		f.close()
	
	def rawwrite(self,f,db):
		for item in db.db:
			tmpdata = []
			desc = item.description
			level = item.getLevel()
			attr = item.getAttr()
			tmpdata.append("level: %d" % level)
			tmpdata.append("hasChild: %d" % attr.hasChild)
			tmpdata.append("hasPrev: %d" % attr.hasPrev)
			tmpdata.append("hasNext: %d" % attr.hasNext)
			tmpdata.append("NOTE: %s" % item.note)
			f.write('\t' * level + desc + '\n')
			for line in tmpdata:
				f.write('\t' * (level + 1) + line + '\n')

	def write(self, file, db, tree):
		"""
		Write the db to filename.
		@since 0.1
		"""
		self.printTree(tree, file)

	#follow http://opml.scripting.com/spec
	def printTree(self, node, file=sys.stdout, indent=0):
		while node != None:
			if indent == 0:
				#xml prefix
				file.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
				#opml prefix
				file.write("<opml version=\"1.0\">\n<head>\n<title>%s</title>\n" %
					node.data.description)
				# <dateCreated> is a date-time, indicating when the document was created
				file.write("<dateCreated>xxx</dateCreated>\n")
				# <dateModified> is a date-time, indicating when the document was last modified.
				file.write("<dateModified>xxx</dateModified>\n")
				# <ownerName> is a string, the owner of the document.
				file.write("<ownerName>Pdesk</ownerName>\n")
				# <ownerEmail> is a string, the email address of the owner of the document.
				file.write("<ownerEmail></ownerEmail>\n")
				# The line numbers in the list tell you which headlines to expand
				# I am not sure what this means
				file.write("<expansionState></expansionState>\n")
				#file.write("<vertScrollState>1</vertScrollState>\n") (no use here)
				#<windowTop>317</windowTop>
				#<windowLeft>252</windowLeft>
				#<windowBottom>514</windowBottom>
				#<windowRight>634</windowRight>
				#head footer, A <body> contains one or more <outline> elements.
				file.write("</head>\n<body>\n")
				
			elif indent > 0:
				mixstring = node.data.description
				#separate the paragraphs & change mixed char <,>,& 
				mixstring = mixstring.replace("&", "&amp;")
				mixstring = mixstring.replace("<", "&lt;")
				mixstring = mixstring.replace(">", "&gt;")
				mixstring = mixstring.replace("\"", "&quot;")
				file.write("\t<outline text=\"%s\" " % mixstring)
				# get indent
				file.write("Indent=\"%s\" "%	indent)
				 
				# get type
				file.write("Type=\"%s\" "%
							node.data.getType())

				# show priority
				if node.data.hasPriority()== 1:
					file.write("Priority=\"%s\" "%
							node.data.getPriority())
				
				#show progress
				if node.data.getProgress()!=0:
					file.write("Progress=\"%s\" "%
							node.data.getProgress())

				#show Duedate
				if node.data.hasDueDate()==1:
					file.write("DueDate=\"%s\" "%
							 node.data.dueDate)

				#show note
				if node.data.hasNote()== 1:
					string = node.data.note
					#separate the paragraphs & change mixed char <,>,&. 
					string = string.replace("&", "&amp;")
					string = string.replace("<", "&lt;")
					string = string.replace(">", "&gt;")
					string = string.replace("\"", "&quot;")
					#string = string.replace("\n", "</para><para>")
					file.write("Note=\"%s\" "%
								string)
					
				if node.data.hasChild()== 1:
					child = 1
					file.write(">\n")
				else:
					child = 0
					file.write("/>\n")

				
			self.printTree(node.child, file, indent+1)
			node = node.next
			
			if indent == 0:
				#change the foot message here
				file.write("</body>\n</opml>")

			elif indent > 0 :
				if child == 1:
					file.write("\t</outline>\n")

class dummy:
	def printTree(self, node, file=sys.stdout, indent=0):
		""" DOESN'T WORK YET
		
		Print this node and it's children to file.

		@param TreePlusNode node : node to print
		@param File file : where to print
		@param int indent : actual indent level
		@since 1.0
		"""
		while node != None:
			data = node.data
			if data.getProgress() == 10 and not self.__exportDone:
				node = node.next
				continue

			line = ("\t" * indent)
			line += node.data.description

			if self.__exportProgress:
				if data.getType() == ItemType.actionType:
					if data.getProgress() == 0:
						line += " [ ]"
					else:
						line += " [*]"
				elif data.getType() == ItemType.progressType or \
					 data.getType() == ItemType.numericType:

					line += " [%d%%]" % (data.getProgress() * 10)

				elif data.getType() == ItemType.informativeType:
					pass

			if self.__exportPriority:
				prio = data.getPriority()
				if prio != priority.NO:
					line += " <%d>" % (prio)

			if self.__exportDate and data.hasDueDate():
				line += " (%s)" % (str(data.dueDate))

			line += "\n"

			if self.__exportNote and data.hasNote():
				for l in data.note.split("\n"):
					line += ("\t" * (indent + 1)) + l + "\n"

			file.write(line)
			self.printTree(node.child, file, indent+1)
			node = node.next

	def write(self, file, db, tree):
		"""
		Write the db to filename.

		@param File file : where to write
		@param Db db : the database to export
		@param TreePlusNode tree : root of the tree
		@since 1.0
		"""
		self.printTree(tree.child, file)


class OPML:
	def __init__(self):
		self.outline = []
		self.places = []
		
	def read(self, f):
		flatflag = 0
		raw = f.read()
		findBody = re.compile(r'<body>(.*)</body>',re.DOTALL)
		body = findBody.findall(raw)[0]
		
		self.outline = self.body2tree(body)
		#pprint(self.outline)
		
	def body2tree(self, body, level = 1):
		'''if the level is set to 1, then will return a "flat" list
		with level indicators
		'''
		
		#get all outline tags
		outline = re.compile(r'(<outline (.*?)>)|(</outline>)',re.DOTALL)
		found = outline.findall(body)
		#pprint (found)
		
		tree = []
		
		for item in found:
			isClosed = 0
			if item[2] != '':
				level = level -1
				continue
			
			attrs = item[1]
			if attrs[-1] == '/':
				isClosed = 1
				attrs = attrs[:-1]
			
			node = self.getAttributes(attrs)
			
			node['level'] = level
			tree.append(node)
			
			if isClosed == 0:
				level = level + 1
				
		return tree
			
	def getAttributes(self,attributes):
		retVal = {}
		find_attributes = re.compile(r'(.*?)="([^"]*|"")"',re.DOTALL)
		attrs = find_attributes.findall(attributes)
		for item in attrs:
			retVal[item[0].strip()] = self.unxmlify(item[1].strip())
		return retVal


	def _print(self,node,level=0):
		print "%s%s" % ("\t"*level, node.name)
		for key, value in node.attrs.iteritems():
			print "%s%s:%s" % ("\t"*level, key[1], value)
		
		for item in node.children:
			self._print(item,level+1)
		
	def write(self, f):
		towrite = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n'
		towrite = towrite + '<life-balance-exchange xmlns="http://www.llamagraphics.com/life-balance-exchange" xmlns:xcal="http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt">\n\n'
	
	def fixUnicode(self,string):
		try:
			return string.encode('ASCII')
		except UnicodeEncodeError:
			s = ''
			for char in string:
				try:
					s = s + char.encode('ASCII')
				except UnicodeEncodeError:
					s = s + '--'
			return s
		except:
			return string
			
	def unxmlify(self,text):
		mapping = [
			('&#10;','&amp;','&lt;','&gt;','&quot;','&apos'),
			('\n','&','<','>','"',"'") ]
		for i in range(len(mapping[0])):
			text = text.replace(mapping[0][i],mapping[1][i])
		return text


class oldOPML:
	def __init__(self):
		self.outline = []
		self.places = []
		
	def read(self, f):
		raw = f.read()
		findBody = re.compile(r'<body>(.*)</body>',re.DOTALL)
		body = findBody.findall(raw)[0]
		
		self.outline = self.body2tree(body)
		
	def body2tree(self, body, level = 1):
		'''if the level is set to 1, then will return a "flat" list
		with level indicators
		'''
		
		# RETURNS A LIST OF NODES / DIRECTORIES
		#print body
		if body == '':
			if level == 0:
				return []
			else:
				return

		tree = []

		outline = re.compile(r'<outline ([^>]*?)/>|<outline (.*?)>(.*)</outline>',re.DOTALL)
		found = outline.findall(body)
		
		for item in found:
			#node = XMLNode()
			
			closedTagAttributes = item[0]
			openTagAttributes = item[1]
			openTagBody = item[2]
		
			if closedTagAttributes:
				attrs = closedTagAttributes

			else:
				attrs = openTagAttributes
			
			node = self.getAttributes(attrs)
			if level == 0:
				node['children'] = self.body2tree(openTagBody)
				tree.append(node)
				
			else:
				node['level'] = level
				tree.append(node)
				
				childrenData = self.body2tree(openTagBody, level + 1)
				if childrenData:
					tree.extend(childrenData)
		return tree
			
	def getAttributes(self,attributes):
		retVal = {}
		find_attributes = re.compile(r'(.*?)="([^"]*|"")"',re.DOTALL)
		attrs = find_attributes.findall(attributes)
		for item in attrs:
			retVal[item[0]] = item[1]
		return retVal


	def _print(self,node,level=0):
		print "%s%s" % ("\t"*level, node.name)
		for key, value in node.attrs.iteritems():
			print "%s%s:%s" % ("\t"*level, key[1], value)
		
		for item in node.children:
			self._print(item,level+1)
		
	def write(self, f):
		towrite = '<?xml version="1.0" encoding="UTF-8" standalone="no" ?>\n'
		towrite = towrite + '<life-balance-exchange xmlns="http://www.llamagraphics.com/life-balance-exchange" xmlns:xcal="http://www.ietf.org/internet-drafts/draft-ietf-calsch-many-xcal-01.txt">\n\n'
		
	
	def fixUnicode(self,string):
		try:
			return string.encode('ASCII')
		except UnicodeEncodeError:
			s = ''
			for char in string:
				try:
					s = s + char.encode('ASCII')
				except UnicodeEncodeError:
					s = s + '--'
			return s
		except:
			return string

  ----------

#
# qp_xml: Quick Parsing for XML
#
# Written by Greg Stein. Public Domain.
# No Copyright, no Rights Reserved, and no Warranties.
#
# This module is maintained by Greg and is available as part of the XML-SIG
# distribution. This module and its changelog can be fetched at:
#    http://www.lyra.org/cgi-bin/viewcvs.cgi/xml/xml/utils/qp_xml.py
#
# Additional information can be found on Greg's Python page at:
#    http://www.lyra.org/greg/python/
#
# This module was added to the XML-SIG distribution on February 14, 2000.
# As part of that distribution, it falls under the XML distribution license.
#

import string

#try:
#  import pyexpat
#except ImportError:
#  from xml.parsers import pyexpat
#except ImportError:

from xml.parsers import xmlproc
pyexpat = xmlproc

error = __name__ + '.error'


#
# The parsing class. Instantiate and pass a string/file to .parse()
#
class Parser:
  def __init__(self):
    self.reset()

  def reset(self):
    self.root = None
    self.cur_elem = None

  def find_prefix(self, prefix):
    elem = self.cur_elem
    while elem:
      if elem.ns_scope.has_key(prefix):
        return elem.ns_scope[prefix]
      elem = elem.parent

    if prefix == '':
      return ''		# empty URL for "no namespace"

    return None

  def process_prefix(self, name, use_default):
    idx = string.find(name, ':')
    if idx == -1:
      if use_default:
        return self.find_prefix(''), name
      return '', name	# no namespace

    if string.lower(name[:3]) == 'xml':
      return '', name	# name is reserved by XML. don't break out a NS.

    ns = self.find_prefix(name[:idx])
    if ns is None:
      raise error, 'namespace prefix not found'

    return ns, name[idx+1:]

  def start(self, name, attrs):
    elem = _element(name=name, lang=None, parent=None,
                    children=[], ns_scope={}, attrs={},
                    first_cdata='', following_cdata='')

    if self.cur_elem:
      elem.parent = self.cur_elem
      elem.parent.children.append(elem)
      self.cur_elem = elem
    else:
      self.cur_elem = self.root = elem

    work_attrs = [ ]

    # scan for namespace declarations (and xml:lang while we're at it)
    for name, value in attrs.items():
      if name == 'xmlns':
        elem.ns_scope[''] = value
      elif name[:6] == 'xmlns:':
        elem.ns_scope[name[6:]] = value
      elif name == 'xml:lang':
        elem.lang = value
      else:
        work_attrs.append((name, value))

    # inherit xml:lang from parent
    if elem.lang is None and elem.parent:
      elem.lang = elem.parent.lang

    # process prefix of the element name
    elem.ns, elem.name = self.process_prefix(elem.name, 1)

    # process attributes' namespace prefixes
    for name, value in work_attrs:
      elem.attrs[self.process_prefix(name, 0)] = value

  def end(self, name):
    parent = self.cur_elem.parent

    del self.cur_elem.ns_scope
    del self.cur_elem.parent

    self.cur_elem = parent

  def cdata(self, data):
    elem = self.cur_elem
    if elem.children:
      last = elem.children[-1]
      last.following_cdata = last.following_cdata + data
    else:
      elem.first_cdata = elem.first_cdata + data

  def parse(self, input):
    self.reset()

    p = pyexpat.ParserCreate()
    p.StartElementHandler = self.start
    p.EndElementHandler = self.end
    p.CharacterDataHandler = self.cdata

    try:
      if type(input) == type(''):
        p.Parse(input, 1)
      else:
        while 1:
          s = input.read(_BLOCKSIZE)
          if not s:
            p.Parse('', 1)
            break

          p.Parse(s, 0)

    finally:
      if self.root:
        _clean_tree(self.root)

    return self.root


#
# handy function for dumping a tree that is returned by Parser
#
def dump(f, root):
  f.write('<?xml version="1.0"?>\n')
  namespaces = _collect_ns(root)
  _dump_recurse(f, root, namespaces, dump_ns=1)
  f.write('\n')


#
# This function returns the element's CDATA. Note: this is not recursive --
# it only returns the CDATA immediately within the element, excluding the
# CDATA in child elements.
#
def textof(elem):
  return elem.textof()


#########################################################################
#
# private stuff for qp_xml
#

_BLOCKSIZE = 16384	# chunk size for parsing input

class _element:
  def __init__(self, **kw):
    self.__dict__.update(kw)

  def textof(self):
    '''Return the CDATA of this element.

    Note: this is not recursive -- it only returns the CDATA immediately
    within the element, excluding the CDATA in child elements.
    '''
    s = self.first_cdata
    for child in self.children:
      s = s + child.following_cdata
    return s

  def find(self, name, ns=''):
    for elem in self.children:
      if elem.name == name and elem.ns == ns:
        return elem
    return None


def _clean_tree(elem):
  elem.parent = None
  del elem.parent
  map(_clean_tree, elem.children)


def _collect_recurse(elem, dict):
  dict[elem.ns] = None
  for ns, name in elem.attrs.keys():
    dict[ns] = None
  for child in elem.children:
    _collect_recurse(child, dict)

def _collect_ns(elem):
  "Collect all namespaces into a NAMESPACE -> PREFIX mapping."
  d = { '' : None }
  _collect_recurse(elem, d)
  del d['']	# make sure we don't pick up no-namespace entries
  keys = d.keys()
  for i in range(len(keys)):
    d[keys[i]] = i
  return d

def _dump_recurse(f, elem, namespaces, lang=None, dump_ns=0):
  if elem.ns:
    f.write('<ns%d:%s' % (namespaces[elem.ns], elem.name))
  else:
    f.write('<' + elem.name)
  for (ns, name), value in elem.attrs.items():
    if ns:
      f.write(' ns%d:%s="%s"' % (namespaces[ns], name, value))
    else:
      f.write(' %s="%s"' % (name, value))
  if dump_ns:
    for ns, id in namespaces.items():
      f.write(' xmlns:ns%d="%s"' % (id, ns))
  if elem.lang != lang:
    f.write(' xml:lang="%s"' % elem.lang)
  if elem.children or elem.first_cdata:
    f.write('>' + elem.first_cdata)
    for child in elem.children:
      _dump_recurse(f, child, namespaces, elem.lang)
      f.write(child.following_cdata)
    if elem.ns:
      f.write('</ns%d:%s>' % (namespaces[elem.ns], elem.name))
    else:
      f.write('</%s>' % elem.name)
  else:
    f.write('/>')


[Non-text portions of this message have been removed]




Remember to visit Polls, Files and Bookmarks sections at http://groups.yahoo.com/group/progect. You are welcome to vote, upload your files and submit bookmarks. 
Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/progect/

<*> To unsubscribe from this group, send an email to:
    [email protected]

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/