[15744] | 1 | /**********************************************************************
|
---|
| 2 | *
|
---|
| 3 | * dynamicclassifieraction.cpp --
|
---|
| 4 | * Copyright (C) 2008 DL Consulting Ltd
|
---|
| 5 | *
|
---|
| 6 | * A component of the Greenstone digital library software
|
---|
| 7 | * from the New Zealand Digital Library Project at the
|
---|
| 8 | * University of Waikato, New Zealand.
|
---|
| 9 | *
|
---|
| 10 | * This program is free software; you can redistribute it and/or modify
|
---|
| 11 | * it under the terms of the GNU General Public License as published by
|
---|
| 12 | * the Free Software Foundation; either version 2 of the License, or
|
---|
| 13 | * (at your option) any later version.
|
---|
| 14 | *
|
---|
| 15 | * This program is distributed in the hope that it will be useful,
|
---|
| 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
---|
| 18 | * GNU General Public License for more details.
|
---|
| 19 | *
|
---|
| 20 | * You should have received a copy of the GNU General Public License
|
---|
| 21 | * along with this program; if not, write to the Free Software
|
---|
| 22 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
---|
| 23 | *
|
---|
| 24 | *********************************************************************/
|
---|
| 25 |
|
---|
| 26 | #include "dynamicclassifieraction.h"
|
---|
[15768] | 27 | #include "recptprototools.h"
|
---|
[15744] | 28 |
|
---|
| 29 |
|
---|
| 30 | dynamicclassifieraction::dynamicclassifieraction ()
|
---|
| 31 | {
|
---|
| 32 | recpt = NULL;
|
---|
[15772] | 33 |
|
---|
| 34 | cgiarginfo arg_ainfo;
|
---|
[15795] | 35 | arg_ainfo.shortname = "dcl";
|
---|
| 36 | arg_ainfo.longname = "dynamic classifier ID";
|
---|
[15772] | 37 | arg_ainfo.multiplechar = true;
|
---|
| 38 | arg_ainfo.defaultstatus = cgiarginfo::weak;
|
---|
| 39 | arg_ainfo.argdefault = "";
|
---|
| 40 | arg_ainfo.savedarginfo = cgiarginfo::must;
|
---|
| 41 | argsinfo.addarginfo (NULL, arg_ainfo);
|
---|
[15807] | 42 |
|
---|
| 43 | arg_ainfo.shortname = "dcn";
|
---|
| 44 | arg_ainfo.longname = "dynamic classifier node";
|
---|
| 45 | arg_ainfo.multiplechar = true;
|
---|
| 46 | arg_ainfo.defaultstatus = cgiarginfo::weak;
|
---|
| 47 | arg_ainfo.argdefault = "";
|
---|
| 48 | arg_ainfo.savedarginfo = cgiarginfo::must;
|
---|
| 49 | argsinfo.addarginfo (NULL, arg_ainfo);
|
---|
[15744] | 50 | }
|
---|
| 51 |
|
---|
| 52 |
|
---|
| 53 | dynamicclassifieraction::~dynamicclassifieraction()
|
---|
| 54 | {
|
---|
| 55 | }
|
---|
| 56 |
|
---|
| 57 |
|
---|
| 58 | bool dynamicclassifieraction::check_cgiargs (cgiargsinfoclass &argsinfo, cgiargsclass &args,
|
---|
| 59 | recptprotolistclass *protos, ostream &logout)
|
---|
| 60 | {
|
---|
| 61 | return true;
|
---|
| 62 | }
|
---|
| 63 |
|
---|
| 64 |
|
---|
| 65 | void dynamicclassifieraction::get_cgihead_info (cgiargsclass &args, recptprotolistclass *protos,
|
---|
| 66 | response_t &response,text_t &response_data,
|
---|
| 67 | ostream &logout)
|
---|
| 68 | {
|
---|
| 69 | response = content;
|
---|
| 70 | response_data = "text/html";
|
---|
| 71 | }
|
---|
| 72 |
|
---|
| 73 |
|
---|
[15847] | 74 | // define all the macros which might be used by other actions to produce pages.
|
---|
[15744] | 75 | void dynamicclassifieraction::define_external_macros (displayclass &disp, cgiargsclass &args,
|
---|
| 76 | recptprotolistclass *protos, ostream &logout)
|
---|
| 77 | {
|
---|
[15847] | 78 | // A valid collection server is vital
|
---|
| 79 | recptproto *collectproto = protos->getrecptproto (args["c"], logout);
|
---|
| 80 | if (collectproto == NULL)
|
---|
| 81 | {
|
---|
| 82 | logout << "dynamicclassifieraction::define_external_macros called with NULL collectproto\n";
|
---|
| 83 | return;
|
---|
| 84 | }
|
---|
| 85 |
|
---|
| 86 | // Define _dynamicclassifiernavbarentries_ to add buttons to the navigation bar for the dynamic classifiers
|
---|
| 87 | text_t navigation_bar_entries = "";
|
---|
| 88 | ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
|
---|
| 89 | text_tmap::iterator dynamic_classifier_iterator = cinfo->dynamic_classifiers.begin();
|
---|
| 90 | while (dynamic_classifier_iterator != cinfo->dynamic_classifiers.end())
|
---|
| 91 | {
|
---|
| 92 | text_t dynamic_classifier_id = (*dynamic_classifier_iterator).first;
|
---|
| 93 | navigation_bar_entries += "_navbarspacer_";
|
---|
| 94 | navigation_bar_entries += "_navtab_(_gwcgi_?c=" + args["c"] + "&a=dc&dcl=" + dynamic_classifier_id + "," + dynamic_classifier_id;
|
---|
| 95 | if (args["a"] == "dc" && args["dcl"] == dynamic_classifier_id)
|
---|
| 96 | {
|
---|
| 97 | navigation_bar_entries += ",selected";
|
---|
| 98 | }
|
---|
| 99 | navigation_bar_entries += ")";
|
---|
| 100 | dynamic_classifier_iterator++;
|
---|
| 101 | }
|
---|
| 102 |
|
---|
| 103 | disp.setmacro("dynamicclassifiernavbarentries", displayclass::defaultpackage, navigation_bar_entries);
|
---|
[15744] | 104 | }
|
---|
| 105 |
|
---|
| 106 |
|
---|
| 107 | // define all the macros which are related to pages generated
|
---|
| 108 | // by this action. we also load up the formatinfo structure
|
---|
| 109 | // here (it's used in do_action as well as here)
|
---|
| 110 | void dynamicclassifieraction::define_internal_macros (displayclass &disp, cgiargsclass &args,
|
---|
| 111 | recptprotolistclass *protos, ostream &logout)
|
---|
| 112 | {
|
---|
| 113 | // define_internal_macros sets the following macros:
|
---|
| 114 | }
|
---|
| 115 |
|
---|
| 116 |
|
---|
| 117 | bool dynamicclassifieraction::do_action(cgiargsclass &args, recptprotolistclass *protos,
|
---|
| 118 | browsermapclass *browsers, displayclass &disp,
|
---|
| 119 | outconvertclass &outconvert, ostream &textout,
|
---|
| 120 | ostream &logout)
|
---|
| 121 | {
|
---|
[15795] | 122 | // A valid collection server is vital
|
---|
[15744] | 123 | recptproto *collectproto = protos->getrecptproto (args["c"], logout);
|
---|
| 124 | if (collectproto == NULL)
|
---|
| 125 | {
|
---|
| 126 | logout << "dynamicclassifieraction::do_action called with NULL collectproto\n";
|
---|
| 127 | return false;
|
---|
| 128 | }
|
---|
| 129 |
|
---|
[15988] | 130 | textout << outconvert << disp << "_dynamicclassifier:header_\n";
|
---|
| 131 | textout << outconvert << disp << "_dynamicclassifier:content_\n";
|
---|
[15768] | 132 |
|
---|
[15795] | 133 | // Check a dynamic classifier ID has been specified
|
---|
| 134 | text_t arg_dcl = args["dcl"];
|
---|
| 135 | if (arg_dcl.empty())
|
---|
[15772] | 136 | {
|
---|
[15834] | 137 | textout << outconvert << disp << "Error: Missing dcl argument.\n";
|
---|
[15988] | 138 | textout << outconvert << disp << "_dynamicclassifier:footer_\n";
|
---|
[15795] | 139 | return true;
|
---|
[15772] | 140 | }
|
---|
| 141 |
|
---|
[15795] | 142 | // Check the dynamic classifier ID is valid (ie. there is an entry in the collect.cfg file for it)
|
---|
[15772] | 143 | ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
|
---|
[15795] | 144 | if (cinfo->dynamic_classifiers.find(arg_dcl) == cinfo->dynamic_classifiers.end())
|
---|
[15772] | 145 | {
|
---|
[15834] | 146 | textout << outconvert << disp << "Error: Invalid dcl value \"" << arg_dcl << "\".\n";
|
---|
[15988] | 147 | textout << outconvert << disp << "_dynamicclassifier:footer_\n";
|
---|
[15795] | 148 | return true;
|
---|
[15772] | 149 | }
|
---|
| 150 |
|
---|
[15999] | 151 | // Parse the classifier options from the specification
|
---|
| 152 | text_t classifier_specification = cinfo->dynamic_classifiers[arg_dcl];
|
---|
[16032] | 153 | text_tmap classifier_options = parse_classifier_options (classifier_specification, args);
|
---|
[15999] | 154 |
|
---|
[15993] | 155 | // Output the "<ID>Header" format statement if there is one
|
---|
| 156 | text_t classifier_header_format_statement = "";
|
---|
[15999] | 157 | get_formatstring (arg_dcl + "Header", cinfo->format, classifier_header_format_statement);
|
---|
[15993] | 158 | textout << outconvert << disp << classifier_header_format_statement << "\n";
|
---|
| 159 |
|
---|
[16065] | 160 | // Resolve any ".pr" bits at the end of the "dcn" argument
|
---|
| 161 | if (ends_with (args["dcn"], ".pr"))
|
---|
| 162 | {
|
---|
| 163 | // Change the "dcn" argument to be the OID of the parent of the specified classifier node
|
---|
| 164 | text_t::iterator parent_classifier_node_OID_end = findlastchar (args["dcn"].begin(), args["dcn"].end(), '|');
|
---|
| 165 | if (parent_classifier_node_OID_end != args["dcn"].end())
|
---|
| 166 | {
|
---|
| 167 | args["dcn"] = substr (args["dcn"].begin(), parent_classifier_node_OID_end);
|
---|
| 168 | }
|
---|
| 169 | else
|
---|
| 170 | {
|
---|
| 171 | args["dcn"] = "";
|
---|
| 172 | }
|
---|
| 173 | }
|
---|
| 174 |
|
---|
[16114] | 175 | // Prepare to output the dynamic classifier
|
---|
| 176 | text_t classifier_node_OID = args["dcn"];
|
---|
| 177 | int classifier_node_indent = 0;
|
---|
| 178 |
|
---|
| 179 | // Begin with the (optional) grouping nodes
|
---|
[16046] | 180 | text_t selected_grouping_node_OID = "";
|
---|
| 181 | if (!classifier_options["-group_using"].empty())
|
---|
[15795] | 182 | {
|
---|
[16115] | 183 | selected_grouping_node_OID = output_hlist_classifier_nodes ("", "", classifier_options["-group_using"], classifier_options, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
| 184 |
|
---|
[16114] | 185 | classifier_node_OID = args["dcn"]; // args["dcn"] may have been modified by output_grouping_nodes()
|
---|
[16046] | 186 | }
|
---|
[16057] | 187 |
|
---|
[16114] | 188 | // Next, optionally display an hlist level
|
---|
| 189 | text_t selected_hlist_node_OID = "";
|
---|
| 190 | if (classifier_options["-use_hlist_at_top"] == "1")
|
---|
| 191 | {
|
---|
| 192 | text_t parent_classifier_node_OID = selected_grouping_node_OID;
|
---|
| 193 | text_t classifier_node_metadata_value = selected_grouping_node_OID;
|
---|
| 194 | text_t metadata_value_filter = selected_grouping_node_OID + "*";
|
---|
[16115] | 195 | selected_hlist_node_OID = output_hlist_classifier_nodes (parent_classifier_node_OID, metadata_value_filter, "", classifier_options, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[16114] | 196 | classifier_node_OID = args["dcn"]; // args["dcn"] may have been modified by output_hlist_classifier_nodes()
|
---|
| 197 | }
|
---|
| 198 |
|
---|
[16057] | 199 | // Simple case at the top level: just output the child classifier nodes
|
---|
[16061] | 200 | if (classifier_node_OID == selected_grouping_node_OID)
|
---|
[16046] | 201 | {
|
---|
[16061] | 202 | text_t metadata_value_filter = selected_grouping_node_OID + "*";
|
---|
| 203 | output_child_classifier_nodes (classifier_node_OID, "", metadata_value_filter, classifier_node_indent, classifier_options, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[15795] | 204 | }
|
---|
[16057] | 205 |
|
---|
| 206 | // More complex case below the top level
|
---|
[15949] | 207 | else
|
---|
| 208 | {
|
---|
[16061] | 209 | // This is the classifier node OID without any grouping information
|
---|
| 210 | text_t classifier_node_OID_sans_grouping = classifier_node_OID;
|
---|
| 211 | if (starts_with (classifier_node_OID, selected_grouping_node_OID + "|"))
|
---|
| 212 | {
|
---|
| 213 | classifier_node_OID_sans_grouping = substr (classifier_node_OID.begin() + (selected_grouping_node_OID + "|").size(), classifier_node_OID.end());
|
---|
| 214 | }
|
---|
[16057] | 215 |
|
---|
[16114] | 216 | // This is the classifier node OID without any hlist nodes
|
---|
| 217 | text_t classifier_node_OID_sans_hlists = classifier_node_OID;
|
---|
| 218 | if (classifier_node_OID == selected_hlist_node_OID)
|
---|
| 219 | {
|
---|
| 220 | classifier_node_OID_sans_hlists = "";
|
---|
| 221 | }
|
---|
| 222 | else if (starts_with (classifier_node_OID, selected_hlist_node_OID + "|"))
|
---|
| 223 | {
|
---|
| 224 | classifier_node_OID_sans_hlists = substr (classifier_node_OID.begin() + (selected_hlist_node_OID + "|").size(), classifier_node_OID.end());
|
---|
| 225 | }
|
---|
| 226 |
|
---|
[16061] | 227 | // Determine the parent classifier node labels
|
---|
| 228 | text_tlist parent_classifier_node_labels;
|
---|
[16114] | 229 | splitchar(classifier_node_OID_sans_hlists.begin(), classifier_node_OID_sans_hlists.end(), '|', parent_classifier_node_labels);
|
---|
[16057] | 230 |
|
---|
[16061] | 231 | // Output the parent classifier nodes and the current classifier node
|
---|
[16114] | 232 | output_upper_classifier_nodes (selected_hlist_node_OID, parent_classifier_node_labels, classifier_node_indent, classifier_options, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[16061] | 233 |
|
---|
[16057] | 234 | // Output the child classifier nodes
|
---|
[16061] | 235 | text_t classifier_node_metadata_value = classifier_node_OID_sans_grouping;
|
---|
| 236 | text_t metadata_value_filter = classifier_node_OID_sans_grouping + "|*";
|
---|
| 237 | output_child_classifier_nodes (classifier_node_OID, classifier_node_metadata_value, metadata_value_filter, classifier_node_indent, classifier_options, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[16057] | 238 |
|
---|
| 239 | // Get the document nodes at this level
|
---|
| 240 | text_t metadata_element_name = classifier_options["metadata_element_name"];
|
---|
| 241 | text_t sort_documents_by = classifier_options["-sort_documents_by"];
|
---|
| 242 | FilterResponse_t documents_response;
|
---|
| 243 | get_documents_with_metadata_value (metadata_element_name, classifier_node_metadata_value, sort_documents_by, args["c"], collectproto, documents_response, logout);
|
---|
| 244 |
|
---|
| 245 | // Display the document nodes
|
---|
| 246 | display_document_nodes (documents_response, classifier_node_indent, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[15949] | 247 | }
|
---|
[15795] | 248 |
|
---|
[15993] | 249 | // Output the "<ID>Footer" format statement if there is one
|
---|
| 250 | text_t classifier_footer_format_statement = "";
|
---|
[15999] | 251 | get_formatstring (arg_dcl + "Footer", cinfo->format, classifier_footer_format_statement);
|
---|
[15993] | 252 | textout << outconvert << disp << classifier_footer_format_statement << "\n";
|
---|
| 253 |
|
---|
[15988] | 254 | textout << outconvert << disp << "_dynamicclassifier:footer_\n";
|
---|
[15949] | 255 | return true;
|
---|
| 256 | }
|
---|
| 257 |
|
---|
| 258 |
|
---|
[16032] | 259 | text_tmap dynamicclassifieraction::parse_classifier_options (text_t classifier_specification, cgiargsclass &args)
|
---|
| 260 | {
|
---|
| 261 | text_tmap classifier_options;
|
---|
| 262 |
|
---|
[16033] | 263 | // Split the classifier specification string by spaces
|
---|
| 264 | text_tlist classifier_specification_parts;
|
---|
| 265 | splitchar (classifier_specification.begin(), classifier_specification.end(), ' ', classifier_specification_parts);
|
---|
| 266 |
|
---|
| 267 | // The metadata element to classify by should be the first value
|
---|
| 268 | classifier_options["metadata_element_name"] = classifier_specification_parts.front();
|
---|
| 269 | classifier_specification_parts.pop_front();
|
---|
| 270 |
|
---|
| 271 | // Parse options from the remainder of the classifier specification
|
---|
| 272 | while (!classifier_specification_parts.empty())
|
---|
| 273 | {
|
---|
| 274 | // Parse the option name
|
---|
| 275 | text_t classifier_option_name = classifier_specification_parts.front();
|
---|
| 276 | classifier_specification_parts.pop_front();
|
---|
| 277 |
|
---|
| 278 | // Check if the option has a value (it may just be a flag, in which case we use "1" as the value)
|
---|
| 279 | text_t classifier_option_value = "1";
|
---|
| 280 | if (!classifier_specification_parts.empty() && !starts_with(classifier_specification_parts.front(), "-"))
|
---|
| 281 | {
|
---|
| 282 | classifier_option_value = classifier_specification_parts.front();
|
---|
| 283 | classifier_specification_parts.pop_front();
|
---|
| 284 | }
|
---|
| 285 |
|
---|
| 286 | // Record the option
|
---|
| 287 | classifier_options[classifier_option_name] = classifier_option_value;
|
---|
| 288 | }
|
---|
| 289 |
|
---|
[16032] | 290 | return classifier_options;
|
---|
| 291 | }
|
---|
| 292 |
|
---|
| 293 |
|
---|
[16114] | 294 | text_t dynamicclassifieraction::output_hlist_classifier_nodes (text_t parent_classifier_node_OID,
|
---|
| 295 | text_t metadata_value_filter,
|
---|
[16115] | 296 | text_t metadata_value_grouping_expression,
|
---|
[16114] | 297 | text_tmap classifier_options, cgiargsclass &args,
|
---|
| 298 | recptproto *collectproto, browsermapclass *browsers,
|
---|
| 299 | displayclass &disp, outconvertclass &outconvert,
|
---|
| 300 | ostream &textout, ostream &logout)
|
---|
| 301 | {
|
---|
| 302 | // Get all the metadata values for the specified element that match the filter
|
---|
| 303 | text_t metadata_element_name = classifier_options["metadata_element_name"];
|
---|
| 304 | FilterResponse_t metadata_values_response;
|
---|
[16115] | 305 | bool request_success = get_metadata_values (metadata_element_name, metadata_value_filter, metadata_value_grouping_expression, args["c"], collectproto, metadata_values_response, logout);
|
---|
[16114] | 306 |
|
---|
| 307 | // If the request failed then it's probably because the collection isn't using an SQL infodbtype
|
---|
| 308 | if (request_success == false)
|
---|
| 309 | {
|
---|
| 310 | textout << outconvert << disp << "Error: Dynamic classifier functionality is not available. Please check you are using an SQL infodbtype and the collection has been rebuilt.\n";
|
---|
| 311 | return "";
|
---|
| 312 | }
|
---|
| 313 |
|
---|
| 314 | // Check some metadata values were returned
|
---|
| 315 | if (metadata_values_response.docInfo.empty())
|
---|
| 316 | {
|
---|
| 317 | return "";
|
---|
| 318 | }
|
---|
| 319 |
|
---|
| 320 | // After processing any hierarchical metadata values we're left with the hlist classifer nodes
|
---|
| 321 | map<text_t, int, lttext_t> hlist_classifier_nodes;
|
---|
| 322 | ResultDocInfo_tarray::iterator metadata_value_iterator = metadata_values_response.docInfo.begin();
|
---|
| 323 | while (metadata_value_iterator != metadata_values_response.docInfo.end())
|
---|
| 324 | {
|
---|
| 325 | text_t metadata_value = (*metadata_value_iterator).OID;
|
---|
| 326 |
|
---|
| 327 | // Is this metadata value hierarchical?
|
---|
| 328 | text_t::iterator hierarchy_split_position = findchar(metadata_value.begin(), metadata_value.end(), '|');
|
---|
| 329 | if (hierarchy_split_position != metadata_value.end())
|
---|
| 330 | {
|
---|
| 331 | // Yes, so use the first part of the hierarchy only
|
---|
| 332 | metadata_value = substr(metadata_value.begin(), hierarchy_split_position);
|
---|
| 333 | }
|
---|
| 334 |
|
---|
| 335 | // Create a node for this metadata value if we haven't seen it before
|
---|
| 336 | if (hlist_classifier_nodes.find(metadata_value) == hlist_classifier_nodes.end())
|
---|
| 337 | {
|
---|
| 338 | hlist_classifier_nodes[metadata_value] = 0;
|
---|
| 339 | }
|
---|
| 340 |
|
---|
| 341 | // Increment the occurrence count
|
---|
| 342 | hlist_classifier_nodes[metadata_value] += (*metadata_value_iterator).result_num;
|
---|
| 343 |
|
---|
| 344 | metadata_value_iterator++;
|
---|
| 345 | }
|
---|
| 346 |
|
---|
| 347 | // If no classifier node has been specified automatically go to the first hlist node
|
---|
| 348 | if (args["dcn"] == parent_classifier_node_OID)
|
---|
| 349 | {
|
---|
| 350 | args["dcn"] = (*hlist_classifier_nodes.begin()).first;
|
---|
| 351 | }
|
---|
| 352 |
|
---|
| 353 | // Add the necessary metadata to the hlist classifier nodes
|
---|
| 354 | text_t selected_hlist_node_OID = "";
|
---|
| 355 | FilterResponse_t hlist_classifier_nodes_response;
|
---|
| 356 | map<text_t, int, lttext_t>::iterator hlist_classifier_nodes_iterator = hlist_classifier_nodes.begin();
|
---|
| 357 | while (hlist_classifier_nodes_iterator != hlist_classifier_nodes.end())
|
---|
| 358 | {
|
---|
| 359 | text_t hlist_classifier_node_OID = (*hlist_classifier_nodes_iterator).first;
|
---|
| 360 |
|
---|
| 361 | // Is this the hlist node that is currently selected?
|
---|
| 362 | if (starts_with (args["dcn"], hlist_classifier_node_OID))
|
---|
| 363 | {
|
---|
| 364 | selected_hlist_node_OID = hlist_classifier_node_OID;
|
---|
| 365 | }
|
---|
| 366 |
|
---|
| 367 | // Add the necessary metadata required to display the hlist nodes correctly
|
---|
| 368 | ResultDocInfo_t hlist_classifier_node;
|
---|
| 369 | hlist_classifier_node.OID = hlist_classifier_node_OID;
|
---|
| 370 | hlist_classifier_node.metadata["doctype"].values.push_back ("classify");
|
---|
| 371 | hlist_classifier_node.metadata["haschildren"].values.push_back ("1");
|
---|
| 372 | hlist_classifier_node.metadata["numleafdocs"].values.push_back ("?"); // We can't determine this without more database requests
|
---|
| 373 | hlist_classifier_node.metadata["Title"].values.push_back (hlist_classifier_node_OID);
|
---|
| 374 | hlist_classifier_nodes_response.docInfo.push_back (hlist_classifier_node);
|
---|
| 375 |
|
---|
| 376 | hlist_classifier_nodes_iterator++;
|
---|
| 377 | }
|
---|
| 378 |
|
---|
| 379 | // Display the hlist nodes
|
---|
| 380 | display_classifier_nodes (hlist_classifier_nodes_response, "HList", 0, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
| 381 |
|
---|
| 382 | return selected_hlist_node_OID;
|
---|
| 383 | }
|
---|
| 384 |
|
---|
| 385 |
|
---|
[16061] | 386 | void dynamicclassifieraction::output_upper_classifier_nodes (text_t root_classifier_node_OID,
|
---|
[16095] | 387 | text_tlist upper_classifier_node_labels,
|
---|
[16061] | 388 | int& classifier_node_indent,
|
---|
| 389 | text_tmap classifier_options, cgiargsclass &args,
|
---|
| 390 | recptproto *collectproto, browsermapclass *browsers,
|
---|
| 391 | displayclass &disp, outconvertclass &outconvert,
|
---|
| 392 | ostream &textout, ostream &logout)
|
---|
[15949] | 393 | {
|
---|
[16095] | 394 | // Display the upper classifier nodes
|
---|
| 395 | text_t upper_classifier_node_OID = root_classifier_node_OID;
|
---|
| 396 | text_tlist::iterator upper_classifier_node_labels_iterator = upper_classifier_node_labels.begin();
|
---|
| 397 | while (upper_classifier_node_labels_iterator != upper_classifier_node_labels.end())
|
---|
[15768] | 398 | {
|
---|
[16095] | 399 | upper_classifier_node_OID += (upper_classifier_node_OID != "" ? "|" : "");
|
---|
| 400 | upper_classifier_node_OID += *upper_classifier_node_labels_iterator;
|
---|
[16096] | 401 |
|
---|
| 402 | ResultDocInfo_t upper_classifier_node;
|
---|
| 403 | upper_classifier_node.OID = upper_classifier_node_OID;
|
---|
| 404 | upper_classifier_node.metadata["doctype"].values.push_back ("classify");
|
---|
| 405 | upper_classifier_node.metadata["haschildren"].values.push_back ("1");
|
---|
| 406 | upper_classifier_node.metadata["numleafdocs"].values.push_back ("?"); // We can't determine this without more database requests
|
---|
| 407 | upper_classifier_node.metadata["Title"].values.push_back (*upper_classifier_node_labels_iterator);
|
---|
| 408 |
|
---|
| 409 | FilterResponse_t upper_classifier_node_response;
|
---|
| 410 | upper_classifier_node_response.docInfo.push_back(upper_classifier_node);
|
---|
[16107] | 411 | display_classifier_nodes (upper_classifier_node_response, "VList", classifier_node_indent, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[16055] | 412 | classifier_node_indent++;
|
---|
[15807] | 413 |
|
---|
[16095] | 414 | upper_classifier_node_labels_iterator++;
|
---|
[15949] | 415 | }
|
---|
[16057] | 416 | }
|
---|
[15949] | 417 |
|
---|
[15953] | 418 |
|
---|
[16057] | 419 | void dynamicclassifieraction::output_child_classifier_nodes (text_t classifier_node_OID,
|
---|
[16061] | 420 | text_t classifier_node_metadata_value,
|
---|
[16057] | 421 | text_t metadata_value_filter,
|
---|
| 422 | int& classifier_node_indent,
|
---|
| 423 | text_tmap classifier_options, cgiargsclass &args,
|
---|
| 424 | recptproto *collectproto, browsermapclass *browsers,
|
---|
| 425 | displayclass &disp, outconvertclass &outconvert,
|
---|
| 426 | ostream &textout, ostream &logout)
|
---|
| 427 | {
|
---|
| 428 | // Get all the metadata values for the specified element that match the filter
|
---|
| 429 | text_t metadata_element_name = classifier_options["metadata_element_name"];
|
---|
| 430 | FilterResponse_t metadata_values_response;
|
---|
| 431 | bool request_success = get_metadata_values (metadata_element_name, metadata_value_filter, "", args["c"], collectproto, metadata_values_response, logout);
|
---|
| 432 |
|
---|
| 433 | // If the request failed then it's probably because the collection isn't using an SQL infodbtype
|
---|
| 434 | if (request_success == false)
|
---|
| 435 | {
|
---|
| 436 | textout << outconvert << disp << "Error: Dynamic classifier functionality is not available. Please check you are using an SQL infodbtype and the collection has been rebuilt.\n";
|
---|
| 437 | return;
|
---|
| 438 | }
|
---|
| 439 |
|
---|
[16058] | 440 | // After processing any hierarchical metadata values we're left with the child classifer nodes
|
---|
| 441 | map<text_t, int, lttext_t> child_classifier_nodes;
|
---|
| 442 | ResultDocInfo_tarray::iterator metadata_value_iterator = metadata_values_response.docInfo.begin();
|
---|
| 443 | while (metadata_value_iterator != metadata_values_response.docInfo.end())
|
---|
[15949] | 444 | {
|
---|
[16004] | 445 | text_t metadata_value = (*metadata_value_iterator).OID;
|
---|
| 446 |
|
---|
| 447 | // If we're not at the top-level we need to remove the current position from the metadata values
|
---|
[16061] | 448 | if (starts_with(metadata_value, classifier_node_metadata_value + "|"))
|
---|
[16004] | 449 | {
|
---|
[16061] | 450 | metadata_value = substr(metadata_value.begin() + (classifier_node_metadata_value + "|").size(), metadata_value.end());
|
---|
[16004] | 451 | }
|
---|
| 452 |
|
---|
| 453 | // Is this metadata value hierarchical?
|
---|
| 454 | text_t::iterator hierarchy_split_position = findchar(metadata_value.begin(), metadata_value.end(), '|');
|
---|
| 455 | if (hierarchy_split_position != metadata_value.end())
|
---|
| 456 | {
|
---|
| 457 | // Yes, so use the first part of the hierarchy only
|
---|
| 458 | metadata_value = substr(metadata_value.begin(), hierarchy_split_position);
|
---|
| 459 | }
|
---|
| 460 |
|
---|
| 461 | // Create a node for this metadata value if we haven't seen it before
|
---|
[16058] | 462 | if (child_classifier_nodes.find(metadata_value) == child_classifier_nodes.end())
|
---|
[16004] | 463 | {
|
---|
[16058] | 464 | child_classifier_nodes[metadata_value] = 0;
|
---|
[16004] | 465 | }
|
---|
| 466 |
|
---|
| 467 | // Increment the occurrence count
|
---|
[16058] | 468 | child_classifier_nodes[metadata_value] += (*metadata_value_iterator).result_num;
|
---|
[16004] | 469 |
|
---|
| 470 | metadata_value_iterator++;
|
---|
| 471 | }
|
---|
| 472 |
|
---|
[16112] | 473 | // Add the necessary metadata to the child classifier nodes
|
---|
[16097] | 474 | FilterResponse_t child_classifier_nodes_response;
|
---|
[16058] | 475 | map<text_t, int, lttext_t>::iterator child_classifier_nodes_iterator = child_classifier_nodes.begin();
|
---|
| 476 | while (child_classifier_nodes_iterator != child_classifier_nodes.end())
|
---|
| 477 | {
|
---|
| 478 | text_t child_classifier_node_OID = (*child_classifier_nodes_iterator).first;
|
---|
| 479 | if (classifier_node_OID != "")
|
---|
| 480 | {
|
---|
| 481 | child_classifier_node_OID = classifier_node_OID + "|" + child_classifier_node_OID;
|
---|
| 482 | }
|
---|
[16004] | 483 |
|
---|
[16097] | 484 | ResultDocInfo_t child_classifier_node;
|
---|
| 485 | child_classifier_node.OID = child_classifier_node_OID;
|
---|
| 486 | child_classifier_node.metadata["doctype"].values.push_back ("classify");
|
---|
| 487 | child_classifier_node.metadata["haschildren"].values.push_back ("1");
|
---|
| 488 | child_classifier_node.metadata["numleafdocs"].values.push_back ((*child_classifier_nodes_iterator).second);
|
---|
| 489 | child_classifier_node.metadata["Title"].values.push_back ((*child_classifier_nodes_iterator).first);
|
---|
| 490 | child_classifier_nodes_response.docInfo.push_back (child_classifier_node);
|
---|
[16004] | 491 |
|
---|
[16097] | 492 | child_classifier_nodes_iterator++;
|
---|
[15949] | 493 | }
|
---|
| 494 |
|
---|
[16112] | 495 | // Display the child classifier nodes
|
---|
[16107] | 496 | display_classifier_nodes (child_classifier_nodes_response, "VList", classifier_node_indent, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[15949] | 497 | }
|
---|
| 498 |
|
---|
| 499 |
|
---|
[16096] | 500 | void dynamicclassifieraction::display_classifier_nodes (FilterResponse_t classifier_nodes_response,
|
---|
[16107] | 501 | text_t classifier_nodes_type,
|
---|
| 502 | int classifier_nodes_indent,
|
---|
[16096] | 503 | cgiargsclass &args, recptproto *collectproto,
|
---|
| 504 | browsermapclass *browsers, displayclass &disp,
|
---|
| 505 | outconvertclass &outconvert, ostream &textout,
|
---|
| 506 | ostream &logout)
|
---|
| 507 | {
|
---|
[16097] | 508 | // Check there are some classifier nodes to display
|
---|
| 509 | if (classifier_nodes_response.docInfo.empty()) return;
|
---|
| 510 |
|
---|
[16096] | 511 | // Get the format statement for this classifier if there is one, or use the browser's default otherwise
|
---|
| 512 | text_t formatstring;
|
---|
[16107] | 513 | browserclass *bptr = browsers->getbrowser (classifier_nodes_type);
|
---|
[16096] | 514 | ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
|
---|
[16107] | 515 | if (!get_formatstring (args["dcl"], classifier_nodes_type, cinfo->format, formatstring))
|
---|
[16096] | 516 | {
|
---|
| 517 | formatstring = bptr->get_default_formatstring();
|
---|
| 518 | }
|
---|
| 519 | format_t *formatlistptr = new format_t();
|
---|
| 520 | text_tset metadata;
|
---|
| 521 | bool getParents = false;
|
---|
| 522 | parse_formatstring (formatstring, formatlistptr, metadata, getParents);
|
---|
| 523 | bool use_table = is_table_content (formatlistptr);
|
---|
| 524 |
|
---|
| 525 | // Display the classifier nodes
|
---|
[16107] | 526 | bptr->output_section_group (classifier_nodes_response, args, args["c"], classifier_nodes_indent, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout);
|
---|
[16096] | 527 | }
|
---|
| 528 |
|
---|
| 529 |
|
---|
[16107] | 530 | void dynamicclassifieraction::display_document_nodes (FilterResponse_t documents_response,
|
---|
| 531 | int document_nodes_indent,
|
---|
[16056] | 532 | cgiargsclass &args, recptproto *collectproto,
|
---|
| 533 | browsermapclass *browsers, displayclass &disp,
|
---|
| 534 | outconvertclass &outconvert, ostream &textout,
|
---|
| 535 | ostream &logout)
|
---|
[15949] | 536 | {
|
---|
[16097] | 537 | // Check there are some documents to display
|
---|
| 538 | if (documents_response.docInfo.empty()) return;
|
---|
| 539 |
|
---|
[16108] | 540 | // Get the format statement for the document nodes if there is one, or use the browser's default otherwise
|
---|
[15949] | 541 | text_t formatstring;
|
---|
[16108] | 542 | browserclass *bptr = browsers->getbrowser ("VList");
|
---|
[15949] | 543 | ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
|
---|
[16108] | 544 | if (!get_formatstring (args["dcl"], "DocumentNodes", cinfo->format, formatstring))
|
---|
[15949] | 545 | {
|
---|
| 546 | formatstring = bptr->get_default_formatstring();
|
---|
| 547 | }
|
---|
| 548 | format_t *formatlistptr = new format_t();
|
---|
| 549 | text_tset metadata;
|
---|
| 550 | bool getParents = false;
|
---|
| 551 | parse_formatstring (formatstring, formatlistptr, metadata, getParents);
|
---|
| 552 | bool use_table = is_table_content (formatlistptr);
|
---|
| 553 |
|
---|
[16007] | 554 | // Request the necessary metadata for displaying the documents
|
---|
| 555 | text_tarray document_OIDs;
|
---|
| 556 | ResultDocInfo_tarray::iterator document_iterator = documents_response.docInfo.begin();
|
---|
| 557 | while (document_iterator != documents_response.docInfo.end())
|
---|
| 558 | {
|
---|
| 559 | document_OIDs.push_back ((*document_iterator).OID);
|
---|
| 560 | document_iterator++;
|
---|
| 561 | }
|
---|
| 562 | FilterResponse_t document_nodes_response;
|
---|
| 563 | get_info (document_OIDs, args["c"], args["l"], metadata, getParents, collectproto, document_nodes_response, logout);
|
---|
[15949] | 564 |
|
---|
| 565 | // Display the document nodes
|
---|
[16007] | 566 | bptr->output_section_group (document_nodes_response, args, args["c"], document_nodes_indent, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout);
|
---|
[15949] | 567 | }
|
---|