def extractTreeType(sectElem) :
		def parseChild(member) :
			text = lib.textValue(member)
			tokens = text.split(" ")
			child = {}
			
			#count (e.g. *)
			if tokens[0] in ["*", "+", "?"] :
				child["count"] = tokens.pop(0)
			else :
				child["count"] = "1"
			
			#typename (e.g. "alpha-beta-gamma")
			child["typename"] = tokens.pop(0)
			
			#label (e.g. "alpha beta gamma")
			if len(tokens) > 0 :
				child["label"] = " ".join(tokens)
	
			return child
		
		layoutElem = filter(
			lambda x: x.getAttribute("role") == "layout",
			lib.childElements(sectElem) )[0]
		members = layoutElem.getElementsByTagName("member")
		
		return {
			"category" : "tree",
			"typename" : getTitle(sectElem),
			"layout" : map(parseChild, members)
		}
		def findTypes() :
			listElem = filter(
				lambda x: x.getAttribute("role") == "family-members",
				lib.childElements(sectElem) )[0]
			def getTypes(memberElem) :
				#defines a node, and is not defined within the section of another node
				def isTopNode(elem) :
					return definesNode(elem) and not lib.hasAncestorElement(elem.parentNode, definesNode)
				assert memberElem.tagName == "member"
				if memberElem.hasAttribute("linkend") and \
				memberElem.getAttribute("linkend").find("node.") != 0 :
					id = memberElem.getAttribute("linkend")
					sect = memberElem.ownerDocument.getElementById(id)
					if sect == None :
						raise Exception("no element with id '%s'" % id)
					return map(getTitle, filter(isTopNode, lib.descendantElements(sect)))
				return [lib.textValue(memberElem)]
			rv = []
			for member in lib.childElements(listElem) :
				rv += getTypes(member)
			return rv
def parseNodeTypes(filePath) :	
	def parseFamily(elem) :
		assert elem.tagName == "family"
		return {
			"category" : "family",
			"typename" : lib.textValue(lib.selectChild(elem, "typename")),
			"members" : map(lib.textValue, lib.selectChildren(lib.selectChild(elem, "members"), "typename"))
		}
	
	def parseTree(elem) :
		def parseEntry(entryElem) :
			child = {
				"count" : lib.textValue(lib.selectChild(entryElem, "count")),
				"typename" : lib.textValue(lib.selectChild(entryElem, "typename"))
			}
			if len(lib.selectChildren(entryElem, "label")) > 0 :
				child["label"] = lib.textValue(lib.selectChild(entryElem, "label"))
			return child
		assert elem.tagName == "tree"
		return {
			"category" : "tree",
			"typename" : lib.textValue(lib.selectChild(elem, "typename")),
			"layout" : map(parseEntry, lib.selectChildren(elem, "entry"))
		}
	
	def parseTerminal(elem) :
		assert elem.tagName == "terminal"
		return {
			"category" : "terminal",
			"typename" : lib.textValue(lib.selectChild(elem, "typename"))
		}

	def parseNode(elem) :
		tag = elem.tagName
		if tag == "family" :
			return parseFamily(elem)
		elif tag == "tree" :
			return parseTree(elem)
		else :
			assert tag == "terminal"
			return parseTerminal(elem)

	return map(parseNode, lib.childElements(DOM.parse(filePath).documentElement))
	def isTree(elem) :
		for child in lib.childElements(elem) :
			if child.getAttribute("role") == "layout" :
				return True
		return False