[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 | {
|
---|
[16046] | 183 | selected_grouping_node_OID = output_grouping_nodes (classifier_options, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[16114] | 184 | classifier_node_OID = args["dcn"]; // args["dcn"] may have been modified by output_grouping_nodes()
|
---|
[16046] | 185 | }
|
---|
[16057] | 186 |
|
---|
[16114] | 187 | // Next, optionally display an hlist level
|
---|
| 188 | text_t selected_hlist_node_OID = "";
|
---|
| 189 | if (classifier_options["-use_hlist_at_top"] == "1")
|
---|
| 190 | {
|
---|
| 191 | text_t parent_classifier_node_OID = selected_grouping_node_OID;
|
---|
| 192 | text_t classifier_node_metadata_value = selected_grouping_node_OID;
|
---|
| 193 | text_t metadata_value_filter = selected_grouping_node_OID + "*";
|
---|
| 194 | selected_hlist_node_OID = output_hlist_classifier_nodes (parent_classifier_node_OID, classifier_node_metadata_value, metadata_value_filter, classifier_options, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
| 195 | classifier_node_OID = args["dcn"]; // args["dcn"] may have been modified by output_hlist_classifier_nodes()
|
---|
| 196 | }
|
---|
| 197 |
|
---|
[16057] | 198 | // Simple case at the top level: just output the child classifier nodes
|
---|
[16061] | 199 | if (classifier_node_OID == selected_grouping_node_OID)
|
---|
[16046] | 200 | {
|
---|
[16061] | 201 | text_t metadata_value_filter = selected_grouping_node_OID + "*";
|
---|
| 202 | output_child_classifier_nodes (classifier_node_OID, "", metadata_value_filter, classifier_node_indent, classifier_options, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[15795] | 203 | }
|
---|
[16057] | 204 |
|
---|
| 205 | // More complex case below the top level
|
---|
[15949] | 206 | else
|
---|
| 207 | {
|
---|
[16061] | 208 | // This is the classifier node OID without any grouping information
|
---|
| 209 | text_t classifier_node_OID_sans_grouping = classifier_node_OID;
|
---|
| 210 | if (starts_with (classifier_node_OID, selected_grouping_node_OID + "|"))
|
---|
| 211 | {
|
---|
| 212 | classifier_node_OID_sans_grouping = substr (classifier_node_OID.begin() + (selected_grouping_node_OID + "|").size(), classifier_node_OID.end());
|
---|
| 213 | }
|
---|
[16057] | 214 |
|
---|
[16114] | 215 | // This is the classifier node OID without any hlist nodes
|
---|
| 216 | text_t classifier_node_OID_sans_hlists = classifier_node_OID;
|
---|
| 217 | if (classifier_node_OID == selected_hlist_node_OID)
|
---|
| 218 | {
|
---|
| 219 | classifier_node_OID_sans_hlists = "";
|
---|
| 220 | }
|
---|
| 221 | else if (starts_with (classifier_node_OID, selected_hlist_node_OID + "|"))
|
---|
| 222 | {
|
---|
| 223 | classifier_node_OID_sans_hlists = substr (classifier_node_OID.begin() + (selected_hlist_node_OID + "|").size(), classifier_node_OID.end());
|
---|
| 224 | }
|
---|
| 225 |
|
---|
[16061] | 226 | // Determine the parent classifier node labels
|
---|
| 227 | text_tlist parent_classifier_node_labels;
|
---|
[16114] | 228 | splitchar(classifier_node_OID_sans_hlists.begin(), classifier_node_OID_sans_hlists.end(), '|', parent_classifier_node_labels);
|
---|
[16057] | 229 |
|
---|
[16061] | 230 | // Output the parent classifier nodes and the current classifier node
|
---|
[16114] | 231 | 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] | 232 |
|
---|
[16057] | 233 | // Output the child classifier nodes
|
---|
[16061] | 234 | text_t classifier_node_metadata_value = classifier_node_OID_sans_grouping;
|
---|
| 235 | text_t metadata_value_filter = classifier_node_OID_sans_grouping + "|*";
|
---|
| 236 | 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] | 237 |
|
---|
| 238 | // Get the document nodes at this level
|
---|
| 239 | text_t metadata_element_name = classifier_options["metadata_element_name"];
|
---|
| 240 | text_t sort_documents_by = classifier_options["-sort_documents_by"];
|
---|
| 241 | FilterResponse_t documents_response;
|
---|
| 242 | get_documents_with_metadata_value (metadata_element_name, classifier_node_metadata_value, sort_documents_by, args["c"], collectproto, documents_response, logout);
|
---|
| 243 |
|
---|
| 244 | // Display the document nodes
|
---|
| 245 | display_document_nodes (documents_response, classifier_node_indent, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[15949] | 246 | }
|
---|
[15795] | 247 |
|
---|
[15993] | 248 | // Output the "<ID>Footer" format statement if there is one
|
---|
| 249 | text_t classifier_footer_format_statement = "";
|
---|
[15999] | 250 | get_formatstring (arg_dcl + "Footer", cinfo->format, classifier_footer_format_statement);
|
---|
[15993] | 251 | textout << outconvert << disp << classifier_footer_format_statement << "\n";
|
---|
| 252 |
|
---|
[15988] | 253 | textout << outconvert << disp << "_dynamicclassifier:footer_\n";
|
---|
[15949] | 254 | return true;
|
---|
| 255 | }
|
---|
| 256 |
|
---|
| 257 |
|
---|
[16032] | 258 | text_tmap dynamicclassifieraction::parse_classifier_options (text_t classifier_specification, cgiargsclass &args)
|
---|
| 259 | {
|
---|
| 260 | text_tmap classifier_options;
|
---|
| 261 |
|
---|
[16033] | 262 | // Split the classifier specification string by spaces
|
---|
| 263 | text_tlist classifier_specification_parts;
|
---|
| 264 | splitchar (classifier_specification.begin(), classifier_specification.end(), ' ', classifier_specification_parts);
|
---|
| 265 |
|
---|
| 266 | // The metadata element to classify by should be the first value
|
---|
| 267 | classifier_options["metadata_element_name"] = classifier_specification_parts.front();
|
---|
| 268 | classifier_specification_parts.pop_front();
|
---|
| 269 |
|
---|
| 270 | // Parse options from the remainder of the classifier specification
|
---|
| 271 | while (!classifier_specification_parts.empty())
|
---|
| 272 | {
|
---|
| 273 | // Parse the option name
|
---|
| 274 | text_t classifier_option_name = classifier_specification_parts.front();
|
---|
| 275 | classifier_specification_parts.pop_front();
|
---|
| 276 |
|
---|
| 277 | // Check if the option has a value (it may just be a flag, in which case we use "1" as the value)
|
---|
| 278 | text_t classifier_option_value = "1";
|
---|
| 279 | if (!classifier_specification_parts.empty() && !starts_with(classifier_specification_parts.front(), "-"))
|
---|
| 280 | {
|
---|
| 281 | classifier_option_value = classifier_specification_parts.front();
|
---|
| 282 | classifier_specification_parts.pop_front();
|
---|
| 283 | }
|
---|
| 284 |
|
---|
| 285 | // Record the option
|
---|
| 286 | classifier_options[classifier_option_name] = classifier_option_value;
|
---|
| 287 | }
|
---|
| 288 |
|
---|
[16032] | 289 | return classifier_options;
|
---|
| 290 | }
|
---|
| 291 |
|
---|
| 292 |
|
---|
[16046] | 293 | text_t dynamicclassifieraction::output_grouping_nodes (text_tmap classifier_options, cgiargsclass &args,
|
---|
| 294 | recptproto *collectproto, browsermapclass *browsers,
|
---|
| 295 | displayclass &disp, outconvertclass &outconvert,
|
---|
| 296 | ostream &textout, ostream &logout)
|
---|
| 297 | {
|
---|
| 298 | // Get all the metadata values for the specified element, and group them according to the "-group_using" value
|
---|
| 299 | text_t metadata_element_name = classifier_options["metadata_element_name"];
|
---|
| 300 | text_t metadata_value_grouping_expression = classifier_options["-group_using"];
|
---|
| 301 | FilterResponse_t grouping_nodes_response;
|
---|
| 302 | bool request_success = get_metadata_values (metadata_element_name, "", metadata_value_grouping_expression, args["c"], collectproto, grouping_nodes_response, logout);
|
---|
| 303 |
|
---|
| 304 | // If the request failed then it's probably because the collection isn't using an SQL infodbtype
|
---|
| 305 | if (request_success == false)
|
---|
| 306 | {
|
---|
| 307 | 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";
|
---|
| 308 | return "";
|
---|
| 309 | }
|
---|
| 310 |
|
---|
| 311 | // Check some grouping nodes were returned
|
---|
| 312 | if (grouping_nodes_response.docInfo.empty())
|
---|
| 313 | {
|
---|
| 314 | return "";
|
---|
| 315 | }
|
---|
| 316 |
|
---|
| 317 | // If no classifier node has been specified automatically go to the first grouping node
|
---|
| 318 | if (args["dcn"] == "")
|
---|
| 319 | {
|
---|
| 320 | args["dcn"] = grouping_nodes_response.docInfo.front().OID;
|
---|
| 321 | }
|
---|
| 322 |
|
---|
[16112] | 323 | // Add the necessary metadata to the grouping nodes
|
---|
[16046] | 324 | text_t selected_grouping_node_OID = "";
|
---|
| 325 | ResultDocInfo_tarray::iterator grouping_node_iterator = grouping_nodes_response.docInfo.begin();
|
---|
| 326 | while (grouping_node_iterator != grouping_nodes_response.docInfo.end())
|
---|
| 327 | {
|
---|
| 328 | // Is this the grouping node that is currently selected?
|
---|
[16061] | 329 | if (starts_with (args["dcn"], (*grouping_node_iterator).OID))
|
---|
[16046] | 330 | {
|
---|
| 331 | selected_grouping_node_OID = (*grouping_node_iterator).OID;
|
---|
| 332 | }
|
---|
| 333 |
|
---|
| 334 | // Add the necessary metadata required to display the grouping nodes correctly
|
---|
| 335 | (*grouping_node_iterator).metadata["doctype"].values.push_back ("classify");
|
---|
| 336 | (*grouping_node_iterator).metadata["haschildren"].values.push_back ("1");
|
---|
| 337 | (*grouping_node_iterator).metadata["numleafdocs"].values.push_back ("?"); // We can't determine this without more database requests
|
---|
| 338 | (*grouping_node_iterator).metadata["Title"].values.push_back ((*grouping_node_iterator).OID);
|
---|
| 339 | grouping_node_iterator++;
|
---|
| 340 | }
|
---|
| 341 |
|
---|
| 342 | // Display the grouping nodes
|
---|
[16112] | 343 | display_classifier_nodes (grouping_nodes_response, "HList", 0, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[16046] | 344 |
|
---|
| 345 | return selected_grouping_node_OID;
|
---|
| 346 | }
|
---|
| 347 |
|
---|
| 348 |
|
---|
[16114] | 349 | text_t dynamicclassifieraction::output_hlist_classifier_nodes (text_t parent_classifier_node_OID,
|
---|
| 350 | text_t classifier_node_metadata_value,
|
---|
| 351 | text_t metadata_value_filter,
|
---|
| 352 | text_tmap classifier_options, cgiargsclass &args,
|
---|
| 353 | recptproto *collectproto, browsermapclass *browsers,
|
---|
| 354 | displayclass &disp, outconvertclass &outconvert,
|
---|
| 355 | ostream &textout, ostream &logout)
|
---|
| 356 | {
|
---|
| 357 | // Get all the metadata values for the specified element that match the filter
|
---|
| 358 | text_t metadata_element_name = classifier_options["metadata_element_name"];
|
---|
| 359 | FilterResponse_t metadata_values_response;
|
---|
| 360 | bool request_success = get_metadata_values (metadata_element_name, metadata_value_filter, "", args["c"], collectproto, metadata_values_response, logout);
|
---|
| 361 |
|
---|
| 362 | // If the request failed then it's probably because the collection isn't using an SQL infodbtype
|
---|
| 363 | if (request_success == false)
|
---|
| 364 | {
|
---|
| 365 | 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";
|
---|
| 366 | return "";
|
---|
| 367 | }
|
---|
| 368 |
|
---|
| 369 | // Check some metadata values were returned
|
---|
| 370 | if (metadata_values_response.docInfo.empty())
|
---|
| 371 | {
|
---|
| 372 | return "";
|
---|
| 373 | }
|
---|
| 374 |
|
---|
| 375 | // After processing any hierarchical metadata values we're left with the hlist classifer nodes
|
---|
| 376 | map<text_t, int, lttext_t> hlist_classifier_nodes;
|
---|
| 377 | ResultDocInfo_tarray::iterator metadata_value_iterator = metadata_values_response.docInfo.begin();
|
---|
| 378 | while (metadata_value_iterator != metadata_values_response.docInfo.end())
|
---|
| 379 | {
|
---|
| 380 | text_t metadata_value = (*metadata_value_iterator).OID;
|
---|
| 381 |
|
---|
| 382 | // If we're not at the top-level we need to remove the current position from the metadata values
|
---|
| 383 | if (starts_with(metadata_value, classifier_node_metadata_value + "|"))
|
---|
| 384 | {
|
---|
| 385 | metadata_value = substr(metadata_value.begin() + (classifier_node_metadata_value + "|").size(), metadata_value.end());
|
---|
| 386 | }
|
---|
| 387 |
|
---|
| 388 | // Is this metadata value hierarchical?
|
---|
| 389 | text_t::iterator hierarchy_split_position = findchar(metadata_value.begin(), metadata_value.end(), '|');
|
---|
| 390 | if (hierarchy_split_position != metadata_value.end())
|
---|
| 391 | {
|
---|
| 392 | // Yes, so use the first part of the hierarchy only
|
---|
| 393 | metadata_value = substr(metadata_value.begin(), hierarchy_split_position);
|
---|
| 394 | }
|
---|
| 395 |
|
---|
| 396 | // Create a node for this metadata value if we haven't seen it before
|
---|
| 397 | if (hlist_classifier_nodes.find(metadata_value) == hlist_classifier_nodes.end())
|
---|
| 398 | {
|
---|
| 399 | hlist_classifier_nodes[metadata_value] = 0;
|
---|
| 400 | }
|
---|
| 401 |
|
---|
| 402 | // Increment the occurrence count
|
---|
| 403 | hlist_classifier_nodes[metadata_value] += (*metadata_value_iterator).result_num;
|
---|
| 404 |
|
---|
| 405 | metadata_value_iterator++;
|
---|
| 406 | }
|
---|
| 407 |
|
---|
| 408 | // If no classifier node has been specified automatically go to the first hlist node
|
---|
| 409 | if (args["dcn"] == parent_classifier_node_OID)
|
---|
| 410 | {
|
---|
| 411 | args["dcn"] = (*hlist_classifier_nodes.begin()).first;
|
---|
| 412 | }
|
---|
| 413 |
|
---|
| 414 | // Add the necessary metadata to the hlist classifier nodes
|
---|
| 415 | text_t selected_hlist_node_OID = "";
|
---|
| 416 | FilterResponse_t hlist_classifier_nodes_response;
|
---|
| 417 | map<text_t, int, lttext_t>::iterator hlist_classifier_nodes_iterator = hlist_classifier_nodes.begin();
|
---|
| 418 | while (hlist_classifier_nodes_iterator != hlist_classifier_nodes.end())
|
---|
| 419 | {
|
---|
| 420 | text_t hlist_classifier_node_OID = (*hlist_classifier_nodes_iterator).first;
|
---|
| 421 |
|
---|
| 422 | // Is this the hlist node that is currently selected?
|
---|
| 423 | if (starts_with (args["dcn"], hlist_classifier_node_OID))
|
---|
| 424 | {
|
---|
| 425 | selected_hlist_node_OID = hlist_classifier_node_OID;
|
---|
| 426 | }
|
---|
| 427 |
|
---|
| 428 | // Add the necessary metadata required to display the hlist nodes correctly
|
---|
| 429 | ResultDocInfo_t hlist_classifier_node;
|
---|
| 430 | hlist_classifier_node.OID = hlist_classifier_node_OID;
|
---|
| 431 | hlist_classifier_node.metadata["doctype"].values.push_back ("classify");
|
---|
| 432 | hlist_classifier_node.metadata["haschildren"].values.push_back ("1");
|
---|
| 433 | hlist_classifier_node.metadata["numleafdocs"].values.push_back ("?"); // We can't determine this without more database requests
|
---|
| 434 | hlist_classifier_node.metadata["Title"].values.push_back (hlist_classifier_node_OID);
|
---|
| 435 | hlist_classifier_nodes_response.docInfo.push_back (hlist_classifier_node);
|
---|
| 436 |
|
---|
| 437 | hlist_classifier_nodes_iterator++;
|
---|
| 438 | }
|
---|
| 439 |
|
---|
| 440 | // Display the hlist nodes
|
---|
| 441 | display_classifier_nodes (hlist_classifier_nodes_response, "HList", 0, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
| 442 |
|
---|
| 443 | return selected_hlist_node_OID;
|
---|
| 444 | }
|
---|
| 445 |
|
---|
| 446 |
|
---|
[16061] | 447 | void dynamicclassifieraction::output_upper_classifier_nodes (text_t root_classifier_node_OID,
|
---|
[16095] | 448 | text_tlist upper_classifier_node_labels,
|
---|
[16061] | 449 | int& classifier_node_indent,
|
---|
| 450 | text_tmap classifier_options, cgiargsclass &args,
|
---|
| 451 | recptproto *collectproto, browsermapclass *browsers,
|
---|
| 452 | displayclass &disp, outconvertclass &outconvert,
|
---|
| 453 | ostream &textout, ostream &logout)
|
---|
[15949] | 454 | {
|
---|
[16095] | 455 | // Display the upper classifier nodes
|
---|
| 456 | text_t upper_classifier_node_OID = root_classifier_node_OID;
|
---|
| 457 | text_tlist::iterator upper_classifier_node_labels_iterator = upper_classifier_node_labels.begin();
|
---|
| 458 | while (upper_classifier_node_labels_iterator != upper_classifier_node_labels.end())
|
---|
[15768] | 459 | {
|
---|
[16095] | 460 | upper_classifier_node_OID += (upper_classifier_node_OID != "" ? "|" : "");
|
---|
| 461 | upper_classifier_node_OID += *upper_classifier_node_labels_iterator;
|
---|
[16096] | 462 |
|
---|
| 463 | ResultDocInfo_t upper_classifier_node;
|
---|
| 464 | upper_classifier_node.OID = upper_classifier_node_OID;
|
---|
| 465 | upper_classifier_node.metadata["doctype"].values.push_back ("classify");
|
---|
| 466 | upper_classifier_node.metadata["haschildren"].values.push_back ("1");
|
---|
| 467 | upper_classifier_node.metadata["numleafdocs"].values.push_back ("?"); // We can't determine this without more database requests
|
---|
| 468 | upper_classifier_node.metadata["Title"].values.push_back (*upper_classifier_node_labels_iterator);
|
---|
| 469 |
|
---|
| 470 | FilterResponse_t upper_classifier_node_response;
|
---|
| 471 | upper_classifier_node_response.docInfo.push_back(upper_classifier_node);
|
---|
[16107] | 472 | display_classifier_nodes (upper_classifier_node_response, "VList", classifier_node_indent, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[16055] | 473 | classifier_node_indent++;
|
---|
[15807] | 474 |
|
---|
[16095] | 475 | upper_classifier_node_labels_iterator++;
|
---|
[15949] | 476 | }
|
---|
[16057] | 477 | }
|
---|
[15949] | 478 |
|
---|
[15953] | 479 |
|
---|
[16057] | 480 | void dynamicclassifieraction::output_child_classifier_nodes (text_t classifier_node_OID,
|
---|
[16061] | 481 | text_t classifier_node_metadata_value,
|
---|
[16057] | 482 | text_t metadata_value_filter,
|
---|
| 483 | int& classifier_node_indent,
|
---|
| 484 | text_tmap classifier_options, cgiargsclass &args,
|
---|
| 485 | recptproto *collectproto, browsermapclass *browsers,
|
---|
| 486 | displayclass &disp, outconvertclass &outconvert,
|
---|
| 487 | ostream &textout, ostream &logout)
|
---|
| 488 | {
|
---|
| 489 | // Get all the metadata values for the specified element that match the filter
|
---|
| 490 | text_t metadata_element_name = classifier_options["metadata_element_name"];
|
---|
| 491 | FilterResponse_t metadata_values_response;
|
---|
| 492 | bool request_success = get_metadata_values (metadata_element_name, metadata_value_filter, "", args["c"], collectproto, metadata_values_response, logout);
|
---|
| 493 |
|
---|
| 494 | // If the request failed then it's probably because the collection isn't using an SQL infodbtype
|
---|
| 495 | if (request_success == false)
|
---|
| 496 | {
|
---|
| 497 | 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";
|
---|
| 498 | return;
|
---|
| 499 | }
|
---|
| 500 |
|
---|
[16058] | 501 | // After processing any hierarchical metadata values we're left with the child classifer nodes
|
---|
| 502 | map<text_t, int, lttext_t> child_classifier_nodes;
|
---|
| 503 | ResultDocInfo_tarray::iterator metadata_value_iterator = metadata_values_response.docInfo.begin();
|
---|
| 504 | while (metadata_value_iterator != metadata_values_response.docInfo.end())
|
---|
[15949] | 505 | {
|
---|
[16004] | 506 | text_t metadata_value = (*metadata_value_iterator).OID;
|
---|
| 507 |
|
---|
| 508 | // If we're not at the top-level we need to remove the current position from the metadata values
|
---|
[16061] | 509 | if (starts_with(metadata_value, classifier_node_metadata_value + "|"))
|
---|
[16004] | 510 | {
|
---|
[16061] | 511 | metadata_value = substr(metadata_value.begin() + (classifier_node_metadata_value + "|").size(), metadata_value.end());
|
---|
[16004] | 512 | }
|
---|
| 513 |
|
---|
| 514 | // Is this metadata value hierarchical?
|
---|
| 515 | text_t::iterator hierarchy_split_position = findchar(metadata_value.begin(), metadata_value.end(), '|');
|
---|
| 516 | if (hierarchy_split_position != metadata_value.end())
|
---|
| 517 | {
|
---|
| 518 | // Yes, so use the first part of the hierarchy only
|
---|
| 519 | metadata_value = substr(metadata_value.begin(), hierarchy_split_position);
|
---|
| 520 | }
|
---|
| 521 |
|
---|
| 522 | // Create a node for this metadata value if we haven't seen it before
|
---|
[16058] | 523 | if (child_classifier_nodes.find(metadata_value) == child_classifier_nodes.end())
|
---|
[16004] | 524 | {
|
---|
[16058] | 525 | child_classifier_nodes[metadata_value] = 0;
|
---|
[16004] | 526 | }
|
---|
| 527 |
|
---|
| 528 | // Increment the occurrence count
|
---|
[16058] | 529 | child_classifier_nodes[metadata_value] += (*metadata_value_iterator).result_num;
|
---|
[16004] | 530 |
|
---|
| 531 | metadata_value_iterator++;
|
---|
| 532 | }
|
---|
| 533 |
|
---|
[16112] | 534 | // Add the necessary metadata to the child classifier nodes
|
---|
[16097] | 535 | FilterResponse_t child_classifier_nodes_response;
|
---|
[16058] | 536 | map<text_t, int, lttext_t>::iterator child_classifier_nodes_iterator = child_classifier_nodes.begin();
|
---|
| 537 | while (child_classifier_nodes_iterator != child_classifier_nodes.end())
|
---|
| 538 | {
|
---|
| 539 | text_t child_classifier_node_OID = (*child_classifier_nodes_iterator).first;
|
---|
| 540 | if (classifier_node_OID != "")
|
---|
| 541 | {
|
---|
| 542 | child_classifier_node_OID = classifier_node_OID + "|" + child_classifier_node_OID;
|
---|
| 543 | }
|
---|
[16004] | 544 |
|
---|
[16097] | 545 | ResultDocInfo_t child_classifier_node;
|
---|
| 546 | child_classifier_node.OID = child_classifier_node_OID;
|
---|
| 547 | child_classifier_node.metadata["doctype"].values.push_back ("classify");
|
---|
| 548 | child_classifier_node.metadata["haschildren"].values.push_back ("1");
|
---|
| 549 | child_classifier_node.metadata["numleafdocs"].values.push_back ((*child_classifier_nodes_iterator).second);
|
---|
| 550 | child_classifier_node.metadata["Title"].values.push_back ((*child_classifier_nodes_iterator).first);
|
---|
| 551 | child_classifier_nodes_response.docInfo.push_back (child_classifier_node);
|
---|
[16004] | 552 |
|
---|
[16097] | 553 | child_classifier_nodes_iterator++;
|
---|
[15949] | 554 | }
|
---|
| 555 |
|
---|
[16112] | 556 | // Display the child classifier nodes
|
---|
[16107] | 557 | display_classifier_nodes (child_classifier_nodes_response, "VList", classifier_node_indent, args, collectproto, browsers, disp, outconvert, textout, logout);
|
---|
[15949] | 558 | }
|
---|
| 559 |
|
---|
| 560 |
|
---|
[16096] | 561 | void dynamicclassifieraction::display_classifier_nodes (FilterResponse_t classifier_nodes_response,
|
---|
[16107] | 562 | text_t classifier_nodes_type,
|
---|
| 563 | int classifier_nodes_indent,
|
---|
[16096] | 564 | cgiargsclass &args, recptproto *collectproto,
|
---|
| 565 | browsermapclass *browsers, displayclass &disp,
|
---|
| 566 | outconvertclass &outconvert, ostream &textout,
|
---|
| 567 | ostream &logout)
|
---|
| 568 | {
|
---|
[16097] | 569 | // Check there are some classifier nodes to display
|
---|
| 570 | if (classifier_nodes_response.docInfo.empty()) return;
|
---|
| 571 |
|
---|
[16096] | 572 | // Get the format statement for this classifier if there is one, or use the browser's default otherwise
|
---|
| 573 | text_t formatstring;
|
---|
[16107] | 574 | browserclass *bptr = browsers->getbrowser (classifier_nodes_type);
|
---|
[16096] | 575 | ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
|
---|
[16107] | 576 | if (!get_formatstring (args["dcl"], classifier_nodes_type, cinfo->format, formatstring))
|
---|
[16096] | 577 | {
|
---|
| 578 | formatstring = bptr->get_default_formatstring();
|
---|
| 579 | }
|
---|
| 580 | format_t *formatlistptr = new format_t();
|
---|
| 581 | text_tset metadata;
|
---|
| 582 | bool getParents = false;
|
---|
| 583 | parse_formatstring (formatstring, formatlistptr, metadata, getParents);
|
---|
| 584 | bool use_table = is_table_content (formatlistptr);
|
---|
| 585 |
|
---|
| 586 | // Display the classifier nodes
|
---|
[16107] | 587 | bptr->output_section_group (classifier_nodes_response, args, args["c"], classifier_nodes_indent, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout);
|
---|
[16096] | 588 | }
|
---|
| 589 |
|
---|
| 590 |
|
---|
[16107] | 591 | void dynamicclassifieraction::display_document_nodes (FilterResponse_t documents_response,
|
---|
| 592 | int document_nodes_indent,
|
---|
[16056] | 593 | cgiargsclass &args, recptproto *collectproto,
|
---|
| 594 | browsermapclass *browsers, displayclass &disp,
|
---|
| 595 | outconvertclass &outconvert, ostream &textout,
|
---|
| 596 | ostream &logout)
|
---|
[15949] | 597 | {
|
---|
[16097] | 598 | // Check there are some documents to display
|
---|
| 599 | if (documents_response.docInfo.empty()) return;
|
---|
| 600 |
|
---|
[16108] | 601 | // Get the format statement for the document nodes if there is one, or use the browser's default otherwise
|
---|
[15949] | 602 | text_t formatstring;
|
---|
[16108] | 603 | browserclass *bptr = browsers->getbrowser ("VList");
|
---|
[15949] | 604 | ColInfoResponse_t *cinfo = recpt->get_collectinfo_ptr (collectproto, args["c"], logout);
|
---|
[16108] | 605 | if (!get_formatstring (args["dcl"], "DocumentNodes", cinfo->format, formatstring))
|
---|
[15949] | 606 | {
|
---|
| 607 | formatstring = bptr->get_default_formatstring();
|
---|
| 608 | }
|
---|
| 609 | format_t *formatlistptr = new format_t();
|
---|
| 610 | text_tset metadata;
|
---|
| 611 | bool getParents = false;
|
---|
| 612 | parse_formatstring (formatstring, formatlistptr, metadata, getParents);
|
---|
| 613 | bool use_table = is_table_content (formatlistptr);
|
---|
| 614 |
|
---|
[16007] | 615 | // Request the necessary metadata for displaying the documents
|
---|
| 616 | text_tarray document_OIDs;
|
---|
| 617 | ResultDocInfo_tarray::iterator document_iterator = documents_response.docInfo.begin();
|
---|
| 618 | while (document_iterator != documents_response.docInfo.end())
|
---|
| 619 | {
|
---|
| 620 | document_OIDs.push_back ((*document_iterator).OID);
|
---|
| 621 | document_iterator++;
|
---|
| 622 | }
|
---|
| 623 | FilterResponse_t document_nodes_response;
|
---|
| 624 | get_info (document_OIDs, args["c"], args["l"], metadata, getParents, collectproto, document_nodes_response, logout);
|
---|
[15949] | 625 |
|
---|
| 626 | // Display the document nodes
|
---|
[16007] | 627 | bptr->output_section_group (document_nodes_response, args, args["c"], document_nodes_indent, formatlistptr, use_table, metadata, getParents, collectproto, disp, outconvert, textout, logout);
|
---|
[15949] | 628 | }
|
---|