> Can someone help me do this? I have grossly hacked up code from the archive
> that nested strings which I can do, but translating that to dictionaries is
> beyond me. The deal is that there is a main dictionary of arbitrarily
> nested dictionaries. The program will not know how deep. Dictionary example
> is available but probably unnecessary. Innermost dictionary is contains
> many elements. Actually I'd prefer the innermost to be a tuple, but I
> thought it would be easier with an innermost dictionary to not mix types.
> The code I have so far is below. As is obvious, I don't quite understand
> the underlying philosophy. I'm sure that once I see it it will make sense.
> For one, there's a tuple returning Thank you.

I did something similar a few weeks ago. I had nested dictionaries representing
a tree structure which I wanted to store in XML files (and display as a CTree).

It seems to me, that your problem is the unknown depth of the tree, right?
A possible solution to this problem would be recursion.

I will attach my tree data type. Maybe studying the code can help you. Creating a CTree
from this is no big problem.


Bye, Martin Grimme --- http://www.pycage.de



from xml import sax
import urllib

SEPARATOR = ":"



class DataTree:

    __INDEX_TYPE = 0
    __INDEX_VALUE = 1
    __INDEX_INFO = 2
    


    #
    # Creates a new DataTree object.
    #
    def __init__(self):

        self.__tree = {}



    #
    # Returns the node at the given path.
    #
    def __get_node(self, path):

        if (path):
            parts = path.split(SEPARATOR)
        else:
            parts = []

        node = self.__tree
        for i in parts:
            node = node[i]

        return node




    #
    # Converts types.
    #
    def __convert_type(self, value, to_type):

        if (value == ""): return ""

        if (to_type == "string"):
            out = str(value)
        elif (to_type == "int"):
            out = int(value)
        elif (to_type == "float"):
            out = float(value)
        elif (to_type == "bool"):
            out = int(value)
        else:
            out = value

        return out



    #
    # Creates a new folder node.
    #
    def new_folder(self, path, name):

        node = self.__get_node(path)

        if (not node.has_key(name)):
            node[name] = {}




    #
    # Creates a new entry node.
    #
    def new_entry(self, path, name, type):

        node = self.__get_node(path)
        node[name] = [type, "", ""]




    #
    # Returns the value stored at the given path.
    #
    def get(self, path):

        try:
            node = self.__get_node(path)
            if (type(node) == type([])):
                typ = node[self.__INDEX_TYPE]
                value = self.__convert_type(node[self.__INDEX_VALUE], typ)
            else:
                value = None
        except:
            value = None

        return value



    #
    # Sets the value for the given path.
    #
    def set(self, path, value):

        node = self.__get_node(path)

        if (type(node) == type([])):
            node[self.__INDEX_VALUE] = self.__convert_type(value, "string")



    #
    # Returns an info stored stored at the given path.
    #
    def get_info(self, path):

        node = self.__get_node(path)
        info = node[self.__INDEX_INFO]

        return info



    #
    # Sets the info string of the given path.
    #
    def set_info(self, path, info):

        node = self.__get_node(path)
        node[self.__INDEX_INFO] = info



    #
    # Lists all children of the node at the given path.
    #
    def list(self, path):

        try:
            node = self.__get_node(path)
        except:
            node = []
            
        if (type(node) == type([])):
            return []
        else:
            return node.keys()



    #
    # Removes the node at the given path (folder or entry).
    #
    def remove(self, path):

        parts = path.split(SEPARATOR)
        path = SEPARATOR.join(parts[:-1])
        name = parts[-1]
        node = self.__get_node(path)

        del node[name]




    #
    # Converts the tree to XML.
    #
    def to_xml(self, node = None, indent = 0):

        out = ""

        if (node == None):
            out += "<datatree>\n"
            out += self.to_xml(self.__tree, indent + 2)
            out += "</datatree>\n"

        else:
            children = node.keys()
            for name in children:
                child = node[name]
                namestring = urllib.quote(name)

                if (type(child) == type([])):
                    value = urllib.quote(child[self.__INDEX_VALUE])
                    dtype = urllib.quote(child[self.__INDEX_TYPE])
                    info = urllib.quote(child[self.__INDEX_INFO])
                    out += " " * indent
                    out += "<entry name=\"" + namestring +"\" " \
                           + "value=\"" + value + "\" " \
                           + "type=\"" + dtype + "\" "\
                           + "info=\"" + info + "\"/>\n"

                else:
                    out += " " * indent
                    out += "<folder name=\"" + namestring + "\">\n"
                    out += self.to_xml(child, indent + 2)
                    out += " " * indent
                    out += "</folder>\n"
                #end if
            #end for
        #end if

        return out



    #
    # Creates a tree from XML.
    #
    def from_xml(self, xmldata):

        handler = _TreeBuilder(self)
        parser = sax.make_parser()
        parser.setContentHandler(handler)
        
        parser.feed(xmldata)
        parser.close()




#
# This class parses XML data and creates a tree.
#
class _TreeBuilder(sax.handler.ContentHandler):

    def __init__(self, tree):

        self.__tree = tree
        self.__path = ""



    def startElement(self, ename, attrs):

        if (ename == "folder"):
            name = urllib.unquote(attrs["name"]).encode("LATIN-1")
            self.__tree.new_folder(self.__path, name)

            if (self.__path):
                self.__path = self.__path + SEPARATOR + name
            else:
                self.__path = name

        elif (ename == "entry"):
            name = urllib.unquote(attrs["name"]).encode("LATIN-1")
            dtype = urllib.unquote(attrs["type"]).encode("LATIN-1")
            value = urllib.unquote(attrs["value"]).encode("LATIN-1")
            info = urllib.unquote(attrs["info"]).encode("LATIN-1")
            self.__tree.new_entry(self.__path, name, dtype)

            if (self.__path):
                self.__path = self.__path + SEPARATOR + name
            else:
                self.__path = name

            self.__tree.set(self.__path, value)
            self.__tree.set_info(self.__path, info)




    def endElement(self, ename):

        parts = self.__path.split(SEPARATOR)
        self.__path = SEPARATOR.join(parts[:-1])







#
# Example usage for this datatype.
#
if (__name__ == "__main__"):

    # build a tree
    tree = DataTree()
    tree.new_folder("", "files")
    tree.new_folder("", "mimetypes")
    tree.new_folder("mimetypes", "text/html")
    tree.new_folder("mimetypes:text/html", "icons")
    tree.new_folder("mimetypes:text/html", "actions")
    tree.new_entry("mimetypes:text/html:actions", "open", "string")
    tree.set("mimetypes:text/html:actions:open", "galeon %s")
    tree.set_info("mimetypes:text/html:actions:open",
                  "The action for opening HTML files.")

    # convert to XML
    d = tree.to_xml()

    # build a new tree and load the XML data of the old tree
    newtree = DataTree()
    newtree.from_xml(d)

    # test the tree
    print "Open: " + newtree.get("mimetypes:text/html:actions:open")
    print 

    # convert to XML again... is should still be the same XML text
    print newtree.to_xml()

Reply via email to