Mantid
Loading...
Searching...
No Matches
ISISJournal.cpp
Go to the documentation of this file.
1// Mantid Repository : https://github.com/mantidproject/mantid
2//
3// Copyright © 2020 ISIS Rutherford Appleton Laboratory UKRI,
4// NScD Oak Ridge National Laboratory, European Spallation Source,
5// Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6// SPDX - License - Identifier: GPL - 3.0 +
7// Includes
10
11#include "Poco/SAX/SAXException.h"
12#include <Poco/DOM/DOMParser.h>
13#include <Poco/DOM/Document.h>
14#include <Poco/DOM/NodeFilter.h>
15#include <Poco/DOM/TreeWalker.h>
16#include <Poco/Net/HTTPResponse.h>
17
18#include <boost/algorithm/string.hpp>
19#include <boost/regex.hpp>
20#include <sstream>
21
22namespace Mantid::DataHandling {
23
24using Kernel::InternetHelper;
25using Poco::XML::Document;
26using Poco::XML::DOMParser;
27using Poco::XML::Element;
28using Poco::XML::Node;
29using Poco::XML::NodeFilter;
30using Poco::XML::TreeWalker;
31
32namespace {
33static constexpr const char *URL_PREFIX = "http://data.isis.rl.ac.uk/journals/ndx";
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";
41
50std::string constructURL(std::string instrument, std::string const &name) {
51 boost::algorithm::to_lower(instrument);
52 std::ostringstream url;
53 url << URL_PREFIX << instrument << JOURNAL_PREFIX << name << JOURNAL_EXT;
54 return url.str();
55}
56
62Poco::AutoPtr<Document> parse(std::string const &xmlString) {
63 DOMParser domParser;
64 Poco::AutoPtr<Document> xmldoc;
65 try {
66 xmldoc = domParser.parseString(xmlString);
67 } catch (Poco::XML::SAXParseException const &ex) {
68 std::ostringstream msg;
69 msg << "ISISJournal: Error parsing file: " << ex.what();
70 throw std::runtime_error(msg.str());
71 }
72 return xmldoc;
73}
74
79void throwIfNotValid(Element *element, const char *expectedName) {
80 if (!element) {
81 std::ostringstream msg;
82 msg << "ISISJournal::throwIfNotValid() - invalid element for '" << expectedName << "'\n";
83 throw std::invalid_argument(msg.str());
84 }
85
86 if (element->nodeName() != expectedName) {
87 std::ostringstream msg;
88 msg << "ISISJournal::throwIfNotValid() - Element name does not match '" << expectedName << "'. Found "
89 << element->nodeName() << "\n";
90 throw std::invalid_argument(msg.str());
91 }
92}
93
99std::string getTextValue(Node *node) {
100 if (!node)
101 return std::string();
102
103 auto child = node->firstChild();
104 if (child && child->nodeName() == "#text") {
105 auto value = child->nodeValue();
106 boost::algorithm::trim(value);
107 return value;
108 }
109
110 return std::string();
111}
112
119bool matchesAllFilters(Element *element, ISISJournal::RunData const &filters) {
120 for (auto const &filterKvp : filters) {
121 auto const childElement = element->getChildElement(filterKvp.first);
122 if (getTextValue(childElement) != filterKvp.second)
123 return false;
124 }
125 return true;
126}
127
134ISISJournal::RunData createRunDataForElement(Element *element) {
135 return ISISJournal::RunData{{"name", element->getAttribute("name")}};
136}
137
145void addValuesForElement(Element *element, std::vector<std::string> const &valuesToLookup,
146 ISISJournal::RunData &result) {
147 for (auto &name : valuesToLookup)
148 result[name] = getTextValue(element->getChildElement(name));
149}
150
161std::vector<ISISJournal::RunData> getValuesForAllElements(Element *parentElement,
162 std::vector<std::string> const &valuesToLookup,
163 ISISJournal::RunData const &filters) {
164 auto results = std::vector<ISISJournal::RunData>{};
165
166 auto nodeIter = TreeWalker(parentElement, NodeFilter::SHOW_ELEMENT);
167 for (auto node = nodeIter.nextNode(); node; node = nodeIter.nextSibling()) {
168 auto element = dynamic_cast<Element *>(node);
169 throwIfNotValid(element, NXENTRY_TAG);
170
171 if (matchesAllFilters(element, filters)) {
172 auto result = createRunDataForElement(element);
173 addValuesForElement(element, valuesToLookup, result);
174 results.emplace_back(std::move(result));
175 }
176 }
177
178 return results;
179}
180
187std::vector<std::string> getAttributeForAllChildElements(Element *parentElement, const char *childElementName,
188 const char *attributeName) {
189 auto results = std::vector<std::string>{};
190
191 auto nodeIter = TreeWalker(parentElement, NodeFilter::SHOW_ELEMENT);
192 for (auto node = nodeIter.nextNode(); node; node = nodeIter.nextSibling()) {
193 auto element = dynamic_cast<Element *>(node);
194 throwIfNotValid(element, childElementName);
195 results.emplace_back(element->getAttribute(attributeName));
196 }
197
198 return results;
199}
200
206std::string convertFilenameToCycleName(std::string const &filename) {
207 boost::regex pattern("[0-9]+_[0-9]+");
208 boost::smatch matches;
209 boost::regex_search(filename, matches, pattern);
210
211 if (matches.size() == 1)
212 return matches[0];
213
214 return std::string();
215}
216
223std::vector<std::string> convertFilenamesToCycleNames(std::vector<std::string> const &filenames) {
224 auto cycles = std::vector<std::string>();
225 cycles.reserve(filenames.size());
226 for (const auto &filename : filenames) {
227 auto cycle = convertFilenameToCycleName(filename);
228 if (!cycle.empty())
229 cycles.emplace_back(std::move(cycle));
230 }
231 return cycles;
232}
233} // namespace
234
241ISISJournal::ISISJournal(std::string const &instrument, std::string const &cycle,
242 std::unique_ptr<InternetHelper> internetHelper)
243 : m_internetHelper(std::move(internetHelper)), m_runsFileURL(constructURL(instrument, cycle)),
244 m_indexFileURL(constructURL(instrument, INDEX_FILE_NAME)) {}
245
246ISISJournal::~ISISJournal() = default;
247
249
251
257std::vector<std::string> ISISJournal::getCycleNames() {
258 if (!m_indexDocument) {
259 auto xmlString = getURLContents(m_indexFileURL);
260 m_indexDocument = parse(xmlString);
261 }
262 auto rootElement = m_indexDocument->documentElement();
263 throwIfNotValid(rootElement, JOURNAL_TAG);
264 auto filenames = getAttributeForAllChildElements(rootElement, FILE_TAG, "name");
265 return convertFilenamesToCycleNames(filenames);
266}
267
276std::vector<ISISJournal::RunData> ISISJournal::getRuns(std::vector<std::string> const &valuesToLookup,
277 ISISJournal::RunData const &filters) {
278 if (!m_runsDocument) {
279 auto xmlString = getURLContents(m_runsFileURL);
280 m_runsDocument = parse(xmlString);
281 }
282 auto rootElement = m_runsDocument->documentElement();
283 throwIfNotValid(rootElement, NXROOT_TAG);
284 return getValuesForAllElements(rootElement, valuesToLookup, filters);
285}
286
292std::string ISISJournal::getURLContents(std::string const &url) {
293 std::ostringstream serverReply;
295 try {
296 statusCode = m_internetHelper->sendRequest(url, serverReply);
297 } catch (Kernel::Exception::InternetError const &) {
298 std::ostringstream msg;
299 msg << "Failed to access file " << url << "\nCheck that the cycle name is valid.";
300 throw Kernel::Exception::InternetError(msg.str());
301 }
302
303 if (statusCode != InternetHelper::HTTPStatus::OK) {
304 std::ostringstream msg;
305 msg << "Failed to access file " << url << "\nHTTP Code: " << static_cast<int>(statusCode)
306 << "\nCheck that the cycle name is valid.";
307 throw Kernel::Exception::InternetError(msg.str());
308 }
309 return serverReply.str();
310}
311} // namespace Mantid::DataHandling
const std::vector< double > & rhs
double value
The value of the point.
Definition: FitMW.cpp:51
std::map< std::string, std::string > RunData
Definition: IJournal.h:21
ISISJournal: Helper class to aid in fetching ISIS specific run information from journal files.
Definition: ISISJournal.h:31
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
Definition: ISISJournal.h:49
Poco::AutoPtr< Poco::XML::Document > m_indexDocument
Definition: ISISJournal.h:53
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
Definition: ISISJournal.h:52
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.
Definition: Exception.h:321
STL namespace.