pythondictionaryturbogears2ordereddictionarygenshi

hierarchical unordered list from 'flat' dictionary of folder structure


On the backend, i am getting a folder structure from an API. I recursively iterate over this structure to get all folders. These are then all stored in a 'flat' ordered dictionary. Each folder is stored with some properties to define the structure, the id of the parent folder, the amount of subfolders it has and if itself is a subnode or not.

Now from this ordered dict I am trying to make a nice hierarchical view with Genshi, but the furthest I've gotten so far is the template below. This results in only 2 levels, the root level, and one level below. Any folder even deeper will be displayed at the second level.

I am trying to do this without having to resort to doing a lot of relation checking on the initial parsing of the data to get the level a folder is at and stuff. Does anyone have any clever ideas?

<body>
  <div class="main_content">
    <h1>Catalogue Tree</h1>
    <ul>
      <li py:for="nodeId, nodeProps in nodes.iteritems()">
        <a py:if="nodeProps['SubNode'] == False" href="${tg.url('/node/' + nodeId)}">${nodeProps['Name']}</a>
        <py:if test="nodeProps['SubNode'] == True">
          <ul>
            <a href="${tg.url('/node/' + nodeId)}">${nodeProps['Name']}</a>
          </ul>
        </py:if>
      </li>
    </ul>
  </div>
</body>

Solution

  • As I commented, you can solve your issue with a recursive macro created with the py:def directive. Here's my attempt at a solution (note, I don't have genshi installed on my system, so this is untested):

    <ul py:def="display_nodes(node_ids)">
        <li py:for="node_id in node_ids">
            <a href="${tg.url('/node/' + node_id)}">${nodes[node_id]['Name']}</a>
            <py:if test="nodes[node_id]['SubNodes']">
                 ${display_nodes(nodes[node_id]['SubNodes'])}
            </py:if>
        </li>
    </ul>
    ${display_nodes(root_nodes)}
    

    This part of the template expects two parameters to be passed, a nodes dictionary that has all the nodes in it, and a root_nodes sequence that includes the IDs of all the top level nodes. The structure this creates is a little different than what the code you've linked to does, as it includes the list of child nodes in the <li> tag of their parent. I'm not sure if that makes any difference or not in the rendering, but it seemed most correct to me to do it that way.