In case anyone has the same issue, I gave up in the end and wrote a custom module since I find views a pain in the ass.
My module uses nested queries which is embarassing, but it's still fast to run (unless you have a massive list of taxononomy terms) so it doesn't matter too much for this purposes.
The module outputs a Drupal block, the content of which comes from this function:
function list_of_resource_tags(){ // Retrieve the logged in user global $user; // Select all "Metadata" terms for the nodes the logged in user // has permission to see $sql_terms = ' SELECT DISTINCT(term_data.tid) AS term_id, term_data.name, term_hierarchy.parent, term_data.weight FROM node_access INNER JOIN node ON node_access.nid = node.nid INNER JOIN term_node ON node.nid = term_node.nid INNER JOIN term_data ON term_node.tid = term_data.tid INNER JOIN term_hierarchy ON term_data.tid = term_hierarchy.tid WHERE node_access.grant_view = 1 AND node.status = 1 /* Published nodes */ AND term_data.vid = 9 /* Taxonomy terms of "Metadata" vocabulary only */ AND node_access.gid IN (SELECT rid AS roles FROM users_roles WHERE uid = %d) /* Logged-in user is granted permission to these nodes */ ORDER BY term_data.weight'; $result_terms = db_query($sql_terms, $user->uid); $displayed_terms = array(); $output = ''; while ($row = db_fetch_object($result_terms)) { // If tag is top-level, just display and put in array if ($row->parent == 0 && in_array($row->term_id, $displayed_terms) == FALSE){ $output .= '<div class="views-row"><a href="taxonomy/term/'.$row->term_id.'">'.$row->name.'</a></div>'; $displayed_terms[] = $row->term_id; } // Test if we've already displayed the tags parent, if not, retrieve it else if (in_array($row->parent, $displayed_terms) == FALSE){ $sql_parent = ' SELECT * FROM term_data WHERE tid = %d'; $result_parent = db_query($sql_parent, $row->parent); $row_parent = db_fetch_object($result_parent); $output .= '<div class="views-row"><a href="taxonomy/term/'.$row_parent->tid.'">'.$row_parent->name.'</div>'; $displayed_terms[] = $row_parent->tid; } } return $output; }