1 #include <framework/gearbox/Gearbox.h>
2 #include <framework/gearbox/GearDir.h>
3 #include <framework/core/MRUCache.h>
4 #include <framework/logging/Logger.h>
5 #include <framework/utilities/Stream.h>
7 #include <libxml/parser.h>
8 #include <libxml/xinclude.h>
9 #include <libxml/xmlIO.h>
11 #include <boost/algorithm/string.hpp>
25 static int matchXmlUri(
const char* uri)
30 if (boost::starts_with(uri,
"file:/"))
return 0;
35 void* openXmlUri(
const char* uri)
37 B2DEBUG(200,
"Request to open " << uri);
38 InputContext* context = Gearbox::getInstance().openXmlUri(uri);
39 return (
void*) context;
43 static int readXmlData(
void* context,
char* buffer,
int buffsize)
46 auto* gearContext =
static_cast<InputContext*
>(context);
47 return gearContext->readXmlData(buffer, buffsize);
51 static int closeXmlContext(
void* context)
53 B2DEBUG(200,
"Closing context");
54 auto* gearContext =
static_cast<InputContext*
>(context);
60 Gearbox::Gearbox(): m_xmlDocument(nullptr), m_xpathContext(nullptr),
86 if (context)
return context;
88 B2ERROR(
"Could not find data for uri '" << uri <<
"'");
95 for (
const string& backend : backends) {
96 B2DEBUG(300,
"Adding InputHandler for '" << backend <<
"'");
99 string prefix(
"file");
100 string accessinfo(backend);
101 size_t colon = backend.find(
':');
102 if (colon != string::npos) {
103 prefix = backend.substr(0, colon);
104 accessinfo = backend.substr(colon + 1);
108 B2ERROR(
"Could not find input handler to handle '" << backend <<
"', ignoring");
115 B2ERROR(
"Problem creating input handler to handle '" << backend <<
"', ignoring");
132 B2FATAL(
"No backends defined, please use Gearbox::setBackends() first to specify how to access XML files.");
136 gearbox::readXmlData, gearbox::closeXmlContext);
144 xmlPopInputCallbacks();
146 if (!
m_xmlDocument) B2FATAL(
"Could not connect gearbox to " << name);
179 if (
m_xpathContext ==
nullptr) B2FATAL(
"Gearbox is not connected");
183 B2INFO(
"Override '" << poverride.
path <<
"' with '" << poverride.
value
184 <<
"' (unit: '" << poverride.
unit <<
"')");
185 xmlXPathObjectPtr result = xmlXPathEvalExpression((xmlChar*) query.c_str(),
m_xpathContext);
186 if (result !=
nullptr && result->type == XPATH_NODESET && !xmlXPathNodeSetIsEmpty(result->nodesetval)) {
188 int numNodes = xmlXPathNodeSetGetLength(result->nodesetval);
189 if (!poverride.
multiple && numNodes > 1) {
190 B2ERROR(
"Cannot override '" << poverride.
path <<
"': more than one node found");
193 B2DEBUG(200,
"Found " << numNodes <<
" nodes, overriding them all");
195 for (
int i = numNodes - 1; i >= 0; --i) {
196 xmlNodePtr node = result->nodesetval->nodeTab[i];
199 for (xmlNodePtr child = node->children; child; child = child->next) {
200 textOnly &= child->type == XML_TEXT_NODE;
201 if (!textOnly)
break;
204 B2ERROR(
"Cannot override '" << poverride.
path <<
"': not just text content");
207 xmlNodeSetContent(node, BAD_CAST poverride.
value.c_str());
210 if (node->type != XML_ELEMENT_NODE) {
211 if (!poverride.
unit.empty())
212 B2WARNING(
"Cannot set unit '" << poverride.
unit <<
"' on '"
213 << poverride.
path <<
"': not an element");
215 xmlSetProp(node, BAD_CAST
"unit", BAD_CAST poverride.
unit.c_str());
231 if (node->type != XML_NAMESPACE_DECL)
232 result->nodesetval->nodeTab[i] =
nullptr;
235 B2ERROR(
"Cannot override '" << poverride.
path <<
"': not found");
237 xmlXPathFreeObject(result);
243 if (
m_xpathContext ==
nullptr) B2FATAL(
"Gearbox is not connected");
250 B2DEBUG(1000,
"Gearbox XPath query: " << query);
251 xmlXPathObjectPtr result = xmlXPathEvalExpression((xmlChar*) query.c_str(),
m_xpathContext);
252 if (result !=
nullptr && result->type == XPATH_NODESET && !xmlXPathNodeSetIsEmpty(result->nodesetval)) {
253 value.numNodes = xmlXPathNodeSetGetLength(result->nodesetval);
254 xmlNodePtr node = result->nodesetval->nodeTab[0];
260 if (node->children && (
long)node->children->content > 0) {
261 xmlChar* valueString = xmlNodeListGetString(
m_xmlDocument, node->children, 1);
262 value.value = (
char*)valueString;
263 xmlFree(valueString);
266 xmlAttrPtr attribute = node->properties;
268 B2DEBUG(1001,
"Checking attribute " << attribute->name);
269 if (!strcmp((
char*)attribute->name,
"unit")) {
270 B2DEBUG(1001,
"found Unit " << attribute->children->content);
271 value.unit = (
char*)attribute->children->content;
274 attribute = attribute->next;
277 boost::trim(value.value);
278 boost::trim(value.unit);
282 B2DEBUG(1000,
"Gearbox XPath result: " << value.numNodes <<
", " << value.value <<
", " << value.unit);
284 xmlXPathFreeObject(result);
291 auto it = m_ownedObjects.find(path);
292 if (it != m_ownedObjects.end())
295 const string& value = getString(path);
299 throw gearbox::TObjectConversionError() << path;
301 m_ownedObjects[path] = object;
309 return GearDir(
"/Detector/DetectorComponent[@name='" + component +
"']/Content");