0

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>
Sartsj
  • 3
  • 1
  • Do your data nodes have parent->child links, or only child->parent? With the former, you could define a recursive template function to expand them, but if you don't have an easy way to get all of a parent's children, it will be harder. – Blckknght May 18 '14 at 22:46
  • In the original api the xml structure is actually nested so I can easily add the parent>child links. But I'm not sure how proceed after that. Can you elaborate? – Sartsj May 19 '14 at 06:39
  • I'd use `py:def` to define a "macro" that outputs the link to an node and then, if the node has children, creates a nested list and recursively calls itself to render each child node. I don't have `genshi` on my system, so I can't really make an answer that I know will work, but hopefully the suggestion is enough to get you on the right path. – Blckknght May 19 '14 at 14:32
  • Your suggestion was indeed the way to go! I actually split up the root nodes from all the other nodes first (not sure now if that was necessary though), so I pass on 2 dicts to the template. Then in the template I indeed used `py:def` to generate a macro that also calls on itself to iterate over the subnodes. This is great! Thanks! See the code at http://pastie.org/9190171 Maybe you can post this as an answer so I can upvote it for you, since you did come up with the whole idea after all! – Sartsj May 19 '14 at 17:15

1 Answers1

0

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.

Blckknght
  • 100,903
  • 11
  • 120
  • 169
  • Awesome, thanks! That's even better, a lot more efficient, it displays more nicely and it also made me clean up my code better on the backend :) There's just one small typo in your solution, you're declaring `node_ids` in the `py:def` but using `nodes_ids` in the `for` loop. – Sartsj May 19 '14 at 22:15
  • I'm glad it helped. I've fixed the `nodes_ids` typo (a holdover from calling the argument `nodes` in an earlier draft of the code). – Blckknght May 19 '14 at 22:49