12#include "Poco/SAX/SAXException.h"
13#include <Poco/DOM/DOMParser.h>
14#include <Poco/DOM/Document.h>
15#include <Poco/DOM/NodeFilter.h>
16#include <Poco/DOM/TreeWalker.h>
17#include <Poco/Net/HTTPResponse.h>
19#include <boost/algorithm/string.hpp>
20#include <boost/regex.hpp>
25using Kernel::InternetHelper;
26using Poco::XML::Document;
27using Poco::XML::DOMParser;
28using Poco::XML::Element;
30using Poco::XML::NodeFilter;
31using Poco::XML::TreeWalker;
34static constexpr const char *INDEX_FILE_NAME =
"main";
35static constexpr const char *JOURNAL_PREFIX =
"/journal_";
36static constexpr const char *JOURNAL_EXT =
".xml";
37static constexpr const char *NXROOT_TAG =
"NXroot";
38static constexpr const char *NXENTRY_TAG =
"NXentry";
39static constexpr const char *JOURNAL_TAG =
"journal";
40static constexpr const char *FILE_TAG =
"file";
50std::string constructURL(std::string instrument, std::string
const &
name) {
51 boost::algorithm::to_lower(instrument);
52 std::ostringstream url;
53 url << Mantid::Kernel::ConfigService::Instance().getString(
"isisjournal.url_prefix") << instrument << JOURNAL_PREFIX
54 <<
name << JOURNAL_EXT;
63Poco::AutoPtr<Document> parse(std::string
const &xmlString) {
65 Poco::AutoPtr<Document> xmldoc;
67 xmldoc = domParser.parseString(xmlString);
68 }
catch (Poco::XML::SAXParseException
const &ex) {
69 std::ostringstream msg;
70 msg <<
"ISISJournal: Error parsing file: " << ex.what();
71 throw std::runtime_error(msg.str());
80void throwIfNotValid(Element *element,
const char *expectedName) {
82 std::ostringstream msg;
83 msg <<
"ISISJournal::throwIfNotValid() - invalid element for '" << expectedName <<
"'\n";
84 throw std::invalid_argument(msg.str());
87 if (element->nodeName() != expectedName) {
88 std::ostringstream msg;
89 msg <<
"ISISJournal::throwIfNotValid() - Element name does not match '" << expectedName <<
"'. Found "
90 << element->nodeName() <<
"\n";
91 throw std::invalid_argument(msg.str());
100std::string getTextValue(Node *node) {
102 return std::string();
104 auto child = node->firstChild();
105 if (child && child->nodeName() ==
"#text") {
106 auto value = child->nodeValue();
107 boost::algorithm::trim(
value);
111 return std::string();
121 for (
auto const &filterKvp : filters) {
122 auto const childElement = element->getChildElement(filterKvp.first);
123 if (getTextValue(childElement) != filterKvp.second)
146void addValuesForElement(Element *element, std::vector<std::string>
const &valuesToLookup,
148 for (
auto &
name : valuesToLookup)
149 result[
name] = getTextValue(element->getChildElement(
name));
162std::vector<ISISJournal::RunData> getValuesForAllElements(Element *parentElement,
163 std::vector<std::string>
const &valuesToLookup,
165 auto results = std::vector<ISISJournal::RunData>{};
167 auto nodeIter = TreeWalker(parentElement, NodeFilter::SHOW_ELEMENT);
168 for (
auto node = nodeIter.nextNode(); node; node = nodeIter.nextSibling()) {
169 auto element =
dynamic_cast<Element *
>(node);
170 throwIfNotValid(element, NXENTRY_TAG);
172 if (matchesAllFilters(element, filters)) {
173 auto result = createRunDataForElement(element);
174 addValuesForElement(element, valuesToLookup, result);
175 results.emplace_back(std::move(result));
188std::vector<std::string> getAttributeForAllChildElements(Element *parentElement,
const char *childElementName,
189 const char *attributeName) {
190 auto results = std::vector<std::string>{};
192 auto nodeIter = TreeWalker(parentElement, NodeFilter::SHOW_ELEMENT);
193 for (
auto node = nodeIter.nextNode(); node; node = nodeIter.nextSibling()) {
194 auto element =
dynamic_cast<Element *
>(node);
195 throwIfNotValid(element, childElementName);
196 results.emplace_back(element->getAttribute(attributeName));
207std::string convertFilenameToCycleName(std::string
const &filename) {
208 boost::regex pattern(
"[0-9]+_[0-9]+");
209 boost::smatch matches;
210 boost::regex_search(filename, matches, pattern);
212 if (matches.size() == 1)
215 return std::string();
224std::vector<std::string> convertFilenamesToCycleNames(std::vector<std::string>
const &filenames) {
225 auto cycles = std::vector<std::string>();
226 cycles.reserve(filenames.size());
227 for (
const auto &filename : filenames) {
228 auto cycle = convertFilenameToCycleName(filename);
230 cycles.emplace_back(std::move(cycle));
243 std::unique_ptr<InternetHelper> internetHelper)
244 : m_internetHelper(
std::move(internetHelper)), m_runsFileURL(constructURL(instrument, cycle)),
245 m_indexFileURL(constructURL(instrument, INDEX_FILE_NAME)) {}
262 throwIfNotValid(rootElement, JOURNAL_TAG);
263 auto filenames = getAttributeForAllChildElements(rootElement, FILE_TAG,
"name");
264 return convertFilenamesToCycleNames(filenames);
282 throwIfNotValid(rootElement, NXROOT_TAG);
283 return getValuesForAllElements(rootElement, valuesToLookup, filters);
292 std::ostringstream serverReply;
297 std::ostringstream msg;
298 msg <<
"Failed to access file " << url <<
"\nCheck that the cycle name is valid.";
303 std::ostringstream msg;
304 msg <<
"Failed to access file " << url <<
"\nHTTP Code: " <<
static_cast<int>(statusCode)
305 <<
"\nCheck that the cycle name is valid.";
308 return serverReply.str();
const std::vector< double > & rhs
double value
The value of the point.
std::map< std::string, std::string > RunData
ISISJournal: Helper class to aid in fetching ISIS specific run information from journal files.
std::string getURLContents(std::string const &url)
Get the contents of a file at a given URL.
std::vector< std::string > getCycleNames() override
Get the list of cycle names.
std::unique_ptr< Kernel::InternetHelper > m_internetHelper
std::string m_runsFileURL
Poco::AutoPtr< Poco::XML::Document > m_indexDocument
ISISJournal const & operator=(ISISJournal const &rhs)=delete
ISISJournal(std::string const &instrument, std::string const &cycle, std::unique_ptr< Kernel::InternetHelper > internetHelper=std::make_unique< Kernel::InternetHelper >())
Construct the journal class for a specific instrument and cycle.
Poco::AutoPtr< Poco::XML::Document > m_runsDocument
std::string m_indexFileURL
std::vector< RunData > getRuns(std::vector< std::string > const &valuesToLookup={}, RunData const &filters=RunData()) override
Get data for runs that match the given filters.
Exception thrown when error occurs accessing an internet resource.