#include "listsetsaction.h" #if defined(GSDL_USE_STL_H) #include #else #include #endif #include "recptprototools.h" #include "oaitools.h" bool listsetsaction::validateAction(recptproto *protocol, oaiargs ¶ms) { int params_size = params.getSize(); // Remove any parameters that aren't valid for this action text_tmap::const_iterator param_iterator = params.begin(); while (param_iterator != params.end()) { if (param_iterator->first != "verb" && param_iterator->first != "resumptionToken") { params.erase(param_iterator->first); } param_iterator++; } if (params_size != params.getSize()) { this->errorType = "badArgument"; return false; } if (params["resumptionToken"] != "") { ResumptionToken token(params["resumptionToken"]); // TO DO: Resumption token validation checking (the token.isValid() function is useless for ListSets) // if (!token.isValid()) { // this->errorType = "badResumptionToken"; // return false; // } } return true; } bool listsetsaction::output_content(ostream &output, recptproto *protocol, text_tset &collections, oaiargs ¶ms) { text_tset::iterator here = collections.begin(); text_tset::iterator end = collections.end(); while (here != end) { text_t collect = *here; this->output_content(output, protocol, params); ++here; } return true; } bool listsetsaction::output_content(ostream &output, recptproto *protocol, oaiargs ¶ms) { // output the total list of classifier points // variables required text_t browseOID = "browse"; FilterResponse_t response; comerror_t err; text_tarray & collections = this->configuration->getCollectionsList(); text_tset metadata; ofstream logout("oai.log", ios::app); // get a list of the collections available // protocol->get_collection_list(collections, err, output); if (collections.size() == 0) { logout << "Found *no* OAI collections - check main.cfg for oaicollection items and read the OAI documentation.\n"; } // check resumption token int startSet = 0; if (params["resumptionToken"] != "") { ResumptionToken token(params["resumptionToken"]); startSet = token.getPosition() - 1; // first document is said to be 1.. } this->replyToken = NULL; this->setNumber = 0; this->setsOutput = 0; for(int current_col = 0; current_col < collections.size(); ++current_col) { // output the collection as a set, first, then its children text_t gsdlCollect = collections[current_col]; if (this->setsOutput == this->configuration->resumeAfter()) { this->replyToken = new ResumptionToken("", "", ""); this->replyToken->setPosition("", this->setNumber+1); break; } if (this->setNumber >= startSet) { output << " " << endl; output << " " << gsdlCollect << "" << endl;; output << " " << gsdlCollect << "" << endl; output << " " << endl; this->setsOutput++; } setNumber++; // get all the children of the (relevant) classifier data structures get_children(browseOID, gsdlCollect, "", metadata, false, protocol, response, logout); // and send them to the "recurse_content" list for (int c = 0; c < response.numDocs; ++c) { this->recurse_content(output, protocol, gsdlCollect, response.docInfo[c].OID, gsdlCollect, startSet); } } // do a resumption token if required; errors cancel a token... if (this->replyToken != NULL && this->errorType == "") { // Don't add any whitespace around the resumption token as it can confuse harvesters/validators output << " " << this->replyToken->getToken() << "" << endl; } return true; } void listsetsaction::recurse_content(ostream &output, recptproto *protocol, text_t &collection, const text_t &classifier, text_t setHierarchy, int startSet) { // metadata for this call FilterResponse_t response; text_tset metadata; ofstream logout("oai.log", ios::app); if (this->setsOutput == this->configuration->resumeAfter()) { this->replyToken = new ResumptionToken("", "", ""); this->replyToken->setPosition("", this->setNumber+1); return; } metadata.insert("contains"); metadata.insert("Title"); metadata.insert("supportsmemberof"); // get the document information if (!get_info(classifier, collection, "", metadata, false, protocol, response, logout)) { //cerr << "recurse content: Bad identifier or protocol " << classifier << endl; return; } // check for top-level classifiers, check if the set name includes a '.'; if // not, it is a top-level classifier: check for memberof support. Those without // memberof support will not be supported on OAI if (findchar(classifier.begin(), classifier.end(), '.') == classifier.end()) { if (response.docInfo[0].metadata["supportsmemberof"].values.size() > 0) { text_t memberOf = response.docInfo[0].metadata["supportsmemberof"].values[0]; if (memberOf != "true") { return; } } else { return; } } MetadataInfo_tmap::iterator here = response.docInfo[0].metadata.begin(); MetadataInfo_tmap::iterator end = response.docInfo[0].metadata.end(); text_t title; while (here != end) { // Each set should only have one title - hence we only output one title here // (it is a set title, not a collection) if (here->first == "Title" && here->second.values.size() > 0) { title = here->second.values[0]; } ++here; } // output the xml for this set; use the classifier id for the name // if the title is blank // curSet holds the colon-separated sequence of parent sets of the current set text_t curSet; if (this->setNumber >= startSet) { output << " " << endl; text_t oai_classifier = classifier; oaiclassifier::toOAI(collection, oai_classifier); output << " " << oai_classifier << "" << endl; output << " "; if (!title.empty()) { curSet = setHierarchy + ":" + title; } else { curSet = classifier; // Pretty much never gets here (shouldn't, at least) } output << curSet; output << "" << endl; output << " " << endl; this->setsOutput++; } this->setNumber++; // get the children of this classifier and iterate them get_children(classifier, collection, "", metadata, false, protocol, response, logout); for (int c = 0; c < response.numDocs; ++c) { text_t child = response.docInfo[c].OID; if (child == classifier) continue; // check for non classifier items and exclude them text_t childHead; text_t::const_iterator start = child.begin(); text_t::const_iterator here = child.begin(); here += 2; childHead = substr(start, here); if (childHead != "CL") continue; // Recurse for "proper" classifier children. Pass curSet, the colon-separated list of // parent sets. curSet is pass-by-value, so that as we step out of recursion we remember // old set hierarchies. this->recurse_content(output, protocol, collection, child, curSet, startSet); } return; }