diff --git a/src/framework/Libxml2Adapter.cpp b/src/framework/Libxml2Adapter.cpp index d30a890a93cc58ce2e8be73cfbb05a0369aa4d19..ac5416a17ad66323c94cd44e53d21c682f834a75 100644 --- a/src/framework/Libxml2Adapter.cpp +++ b/src/framework/Libxml2Adapter.cpp @@ -20,15 +20,71 @@ #include "Libxml2Adapter.h" +#include <iostream> +#include <sstream> + +#include <libxml/xpath.h> + Libxml2Adapter::Libxml2Adapter() { + m_xmlDocument = NULL; } Libxml2Adapter::~Libxml2Adapter() { } -string Libxml2Adapter::getAttributeBySingleElementXPath(const string xml, const string xpath) +void Libxml2Adapter::setXmlDocument(const string xml, const string url) { - //TODO + xmlDocPtr doc = xmlReadMemory(xml.c_str(), xml.size(), url.c_str(), NULL, 0); + if(doc) { + m_xmlDocument = doc; + } + else { + cerr << "Document couldn't be parsed!" << endl; + } } + +string Libxml2Adapter::getSingleNodeContentByXPath(const string xpath) +{ + // no document available! + if(!m_xmlDocument) return(""); + + // prepare xpath search + stringstream buffer; + xmlXPathContextPtr xpathCtx = xmlXPathNewContext(m_xmlDocument); + xmlChar* xpathExpr = xmlCharStrdup(xpath.c_str()); + + // run xpath query + xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression(xpathExpr, xpathCtx); + xmlNodeSetPtr nodes = xpathObj->nodesetval; + + // how many nodes did we find? + int size = (nodes) ? nodes->nodeNr : 0; + + if(size == 0) { + cerr << "No node found using XPath expression: " << xpath << endl; + return(""); + } + else if(size < 1) { + cerr << "More than node found using XPath expression: " << xpath << endl; + return(""); + } + + // convert xml contents + buffer << xmlNodeListGetString(m_xmlDocument, nodes->nodeTab[0]->xmlChildrenNode, 1); + + // clean up + xmlXPathFreeObject(xpathObj); + xmlXPathFreeContext(xpathCtx); + + return(buffer.str()); +} + +string Libxml2Adapter::getSingleNodeContentByXPath(const string xml, const string url, const string xpath) +{ + setXmlDocument(xml, url); + return(getSingleNodeContentByXPath(xpath)); +} + + diff --git a/src/framework/Libxml2Adapter.h b/src/framework/Libxml2Adapter.h index a07f673cb2f8fe17039108ff3e9c635a29eca049..92ca84b026b3cc94198d423e511953f6d63817b7 100644 --- a/src/framework/Libxml2Adapter.h +++ b/src/framework/Libxml2Adapter.h @@ -25,6 +25,8 @@ #include "XMLProcessorInterface.h" +#include <libxml/parser.h> + using namespace std; /** @@ -33,14 +35,14 @@ using namespace std; */ /** - * \brief This class implements XMLProcessorInterface providing an adapter to libxml2 - * + * \brief This class implements XMLProcessorInterface providing an adapter to libxml2 + * * For the time being libxml2 is considered to be the only interesting XML processing * library because of its rich feature set that comprises DOM, SAX, XPath, XSLT as well * as validation based on DTD and XML Schema. - * + * * \see XMLProcessorInterface - * + * * \author Oliver Bock\n * Max-Planck-Institute for Gravitational Physics\n * Hannover, Germany @@ -53,21 +55,48 @@ public: /// Destructor virtual ~Libxml2Adapter(); - + + /** + * \brief Sets the XML document to be processed + * + * \param xml The XML document to be used for processing + * \param url The base URL of the document + */ + void setXmlDocument(const string xml, const string url); + /** - * \brief Retrieves a single element's attribute value - * + * \brief Retrieves a single node's (element or attribute) content + * * This method takes a XPath expression that properly defines how to search - * for a specific attribute of a single element. If the XPath search results - * in more than one element or if the attribute can't be found the return - * value is NULL. - * + * for a specific node (element or attribute). If the XPath search results + * in more than one instance or if the node (or its content) can't be found + * the return value is NULL. + * + * \param xpath The XPath expression to be used for seaching + * + * \return The node's content or NULL in case of an error + */ + string getSingleNodeContentByXPath(const string xpath); + + /** + * \brief Retrieves a single node's (element or attribute) content + * + * This method takes a XPath expression that properly defines how to search + * for a specific node (element or attribute). If the XPath search results + * in more than one instance or if the node (or its content) can't be found + * the return value is NULL. + * * \param xml The XML document to be used for processing + * \param url The base URL of the document * \param xpath The XPath expression to be used for seaching - * - * \return The attribute value or NULL in case of an error + * + * \return The node's content or NULL in case of an error */ - string getAttributeBySingleElementXPath(const string xml, const string xpath); + string getSingleNodeContentByXPath(const string xml, const string url, const string xpath); + +private: + /// The current XML document instance + xmlDocPtr m_xmlDocument; }; /** diff --git a/src/framework/Makefile b/src/framework/Makefile index 57a06f1d2f947d1d454691cc161add44725d8da8..8a8ace7110f39510e81e225ff88be1ee8f1224f9 100644 --- a/src/framework/Makefile +++ b/src/framework/Makefile @@ -28,6 +28,7 @@ CXX?=g++ # variables CPPFLAGS = $(shell $(FRAMEWORK_INSTALL)/bin/sdl-config --cflags) CPPFLAGS += $(shell $(FRAMEWORK_INSTALL)/bin/freetype-config --cflags) +CPPFLAGS += $(shell $(FRAMEWORK_INSTALL)/bin/xml2-config --cflags) CPPFLAGS += -I$(FRAMEWORK_INSTALL)/include/BOINC -I/usr/include DEPS = Makefile diff --git a/src/framework/XMLProcessorInterface.h b/src/framework/XMLProcessorInterface.h index d799eac94b3bebbdbf56387dc44cf3c1f28d4d2c..8daa7079cf83d46e36bb7efea72b9c0b3ddae0bf 100644 --- a/src/framework/XMLProcessorInterface.h +++ b/src/framework/XMLProcessorInterface.h @@ -33,12 +33,12 @@ using namespace std; /** * \brief This interface declares all mandatory public methods to be provied by any * given XML Processor. - * + * * All classes implementing this interface have to provide at least the set of methods - * declared here. - * + * declared here. + * * \see Libxml2Adapter - * + * * \author Oliver Bock\n * Max-Planck-Institute for Gravitational Physics\n * Hannover, Germany @@ -46,24 +46,47 @@ using namespace std; class XMLProcessorInterface { public: - + /// Empty Destructor virtual ~XMLProcessorInterface() {}; - + + /** + * \brief Sets the XML document to be processed + * + * \param xml The XML document to be used for processing + * \param url The base URL of the document + */ + virtual void setXmlDocument(const string xml, const string url) = 0; + + /** + * \brief Retrieves a single node's (element or attribute) content + * + * This method takes a XPath expression that properly defines how to search + * for a specific node (element or attribute). If the XPath search results + * in more than one instance or if the node (or its content) can't be found + * the return value is NULL. + * + * \param xpath The XPath expression to be used for seaching + * + * \return The node's content or NULL in case of an error + */ + virtual string getSingleNodeContentByXPath(const string xpath) = 0; + /** - * \brief Retrieves a single element's attribute value - * + * \brief Retrieves a single node's (element or attribute) content + * * This method takes a XPath expression that properly defines how to search - * for a specific attribute of a single element. If the XPath search results - * in more than one element or if the attribute can't be found the return - * value is NULL. - * + * for a specific node (element or attribute). If the XPath search results + * in more than one instance or if the node (or its content) can't be found + * the return value is NULL. + * * \param xml The XML document to be used for processing + * \param url The base URL of the document * \param xpath The XPath expression to be used for seaching - * - * \return The attribute value or NULL in case of an error + * + * \return The node's content or NULL in case of an error */ - virtual string getAttributeBySingleElementXPath(const string xml, const string xpath) = 0; + virtual string getSingleNodeContentByXPath(const string xml, const string url, const string xpath) = 0; }; /** diff --git a/src/starsphere/EinsteinRadioAdapter.cpp b/src/starsphere/EinsteinRadioAdapter.cpp index 21e86b094d387e5186db1453d194f591c3f9e450..9877367da4d05893c2a539cc735c7ce4fb4a8268 100644 --- a/src/starsphere/EinsteinRadioAdapter.cpp +++ b/src/starsphere/EinsteinRadioAdapter.cpp @@ -19,6 +19,9 @@ ***************************************************************************/ #include "EinsteinRadioAdapter.h" +#include "Libxml2Adapter.h" + +#include <cstdlib> const string EinsteinRadioAdapter::SharedMemoryIdentifier = "EinsteinRadio"; @@ -26,6 +29,7 @@ EinsteinRadioAdapter::EinsteinRadioAdapter(BOINCClientAdapter *boincClient) : m_WUTemplatePowerSpectrum(POWERSPECTRUM_BINS, 0) { this->boincClient = boincClient; + m_xmlIFace = new Libxml2Adapter(); m_WUSkyPosRightAscension = 0.0; m_WUSkyPosDeclination = 0.0; @@ -35,6 +39,7 @@ EinsteinRadioAdapter::EinsteinRadioAdapter(BOINCClientAdapter *boincClient) : EinsteinRadioAdapter::~EinsteinRadioAdapter() { + if(m_xmlIFace) delete m_xmlIFace; } void EinsteinRadioAdapter::refresh() @@ -45,71 +50,67 @@ void EinsteinRadioAdapter::refresh() void EinsteinRadioAdapter::parseApplicationInformation() { - char spectrumArray[POWERSPECTRUM_BIN_BYTES + 1] = {0}; + string spectrumString; // get updated application information string info = boincClient->applicationInformation(); // do we have any data? if(info.length() > 0) { + string temp; // parse data into members - // TODO: this is soon going to be replaced by true XML parsing! - if(9 != sscanf(info.c_str(), - "<graphics_info>\n" - " <skypos_rac>%lf</skypos_rac>\n" - " <skypos_dec>%lf</skypos_dec>\n" - " <dispersion>%lf</dispersion>\n" - " <orb_radius>%lf</orb_radius>\n" - " <orb_period>%lf</orb_period\n" - " <orb_phase>%lf</orb_phase>\n" - " <power_spectrum>%80c</power_spectrum>\n" - " <fraction_done>%lf</fraction_done>\n" - " <cpu_time>%lf</cpu_time>\n", - &m_WUSkyPosRightAscension, - &m_WUSkyPosDeclination, - &m_WUDispersionMeasure, - &m_WUTemplateOrbitalRadius, - &m_WUTemplateOrbitalPeriod, - &m_WUTemplateOrbitalPhase, - spectrumArray, - &m_WUFractionDone, - &m_WUCPUTime)) - { - cerr << "Incompatible shared memory data encountered!" << endl; - } - else { - // convert radians to degrees - m_WUSkyPosRightAscension *= 180/PI; - m_WUSkyPosDeclination *= 180/PI; - - // deserialize power spectrum data - string spectrumString(spectrumArray); - if(spectrumString.length() == POWERSPECTRUM_BIN_BYTES) { - int spectrumBinValue; - // prepare hex to int conversion stream - istringstream spectrumBinStream; - spectrumBinStream.exceptions(ios_base::badbit | ios_base::failbit); - // iterate over all bins - for(int i = 0, j = 0; i < POWERSPECTRUM_BIN_BYTES; i += 2, ++j) { - try { - spectrumBinStream.str(spectrumString.substr(i, 2)); - // convert hex bin value to integer - spectrumBinStream >> hex >> spectrumBinValue; - // store bin power value - m_WUTemplatePowerSpectrum.at(j) = (unsigned char) spectrumBinValue; - spectrumBinStream.clear(); - } - catch(ios_base::failure) { - cerr << "Error processing power spectrum shared memory data!" << endl; - break; - } + m_xmlIFace->setXmlDocument(info, "http://einstein.phys.uwm.edu"); + temp = m_xmlIFace->getSingleNodeContentByXPath("/graphics_info/skypos_rac"); + m_WUSkyPosRightAscension = strtod(temp.c_str(), NULL); + temp = m_xmlIFace->getSingleNodeContentByXPath("/graphics_info/skypos_dec"); + m_WUSkyPosDeclination = strtod(temp.c_str(), NULL); + temp = m_xmlIFace->getSingleNodeContentByXPath("/graphics_info/dispersion"); + m_WUDispersionMeasure = strtod(temp.c_str(), NULL); + temp = m_xmlIFace->getSingleNodeContentByXPath("/graphics_info/orb_radius"); + m_WUTemplateOrbitalRadius = strtod(temp.c_str(), NULL); + temp = m_xmlIFace->getSingleNodeContentByXPath("/graphics_info/orb_period"); + m_WUTemplateOrbitalPeriod = strtod(temp.c_str(), NULL); + temp = m_xmlIFace->getSingleNodeContentByXPath("/graphics_info/orb_phase"); + m_WUTemplateOrbitalPhase = strtod(temp.c_str(), NULL); + spectrumString = m_xmlIFace->getSingleNodeContentByXPath("/graphics_info/power_spectrum"); + temp = m_xmlIFace->getSingleNodeContentByXPath("/graphics_info/fraction_done"); + m_WUFractionDone = strtod(temp.c_str(), NULL); + temp = m_xmlIFace->getSingleNodeContentByXPath("/graphics_info/cpu_time"); + m_WUCPUTime = strtod(temp.c_str(), NULL); + + // TODO: make sure parsing worked flawlessly (only spectrum is checked below!) + + // convert radians to degrees + m_WUSkyPosRightAscension *= 180/PI; + m_WUSkyPosDeclination *= 180/PI; + + // deserialize power spectrum data + if(spectrumString.length() == POWERSPECTRUM_BIN_BYTES) { + int spectrumBinValue; + // prepare hex to int conversion stream + istringstream spectrumBinStream; + spectrumBinStream.exceptions(ios_base::badbit | ios_base::failbit); + // iterate over all bins + for(int i = 0, j = 0; i < POWERSPECTRUM_BIN_BYTES; i += 2, ++j) { + try { + spectrumBinStream.str(spectrumString.substr(i, 2)); + // convert hex bin value to integer + spectrumBinStream >> hex >> spectrumBinValue; + // store bin power value + m_WUTemplatePowerSpectrum.at(j) = (unsigned char) spectrumBinValue; + spectrumBinStream.clear(); + } + catch(ios_base::failure) { + cerr << "Error processing power spectrum shared memory data!" << endl; + break; } } - else { - cerr << "Invalid power spectrum shared memory data encountered!" << endl; - } } + else { + cerr << "Invalid power spectrum shared memory data encountered!" << endl; + } + } } diff --git a/src/starsphere/EinsteinRadioAdapter.h b/src/starsphere/EinsteinRadioAdapter.h index 22469d370ab6255bb264643933e779d2c12d5b39..3970126380a7bd7181da0cf6c080cef4a1a7e830 100644 --- a/src/starsphere/EinsteinRadioAdapter.h +++ b/src/starsphere/EinsteinRadioAdapter.h @@ -26,6 +26,7 @@ #include <iomanip> #include "BOINCClientAdapter.h" +#include "XMLProcessorInterface.h" using namespace std; @@ -152,6 +153,9 @@ private: /// Pointer to the (parent) BOINC client adapter BOINCClientAdapter *boincClient; + /// Pointer to the XML processor + XMLProcessorInterface* m_xmlIFace; + /// Right ascension of the currently searched sky position (in degrees) double m_WUSkyPosRightAscension; diff --git a/src/starsphere/Makefile b/src/starsphere/Makefile index 4520abd004a1328eaac2dd9890dbba3974f94350..bf9530b21f295ecd666b3a6f43dc19d6107ab69a 100644 --- a/src/starsphere/Makefile +++ b/src/starsphere/Makefile @@ -28,12 +28,14 @@ CXX ?= g++ # variables LIBS = -Wl,-Bstatic -lframework -loglft -L$(STARSPHERE_INSTALL)/lib LIBS += $(shell $(STARSPHERE_INSTALL)/bin/freetype-config --libs) +LIBS += $(shell $(STARSPHERE_INSTALL)/bin/xml2-config --libs) LIBS += -lboinc_api -lboinc -L/usr/lib LIBS += -Wl,-Bdynamic $(shell $(STARSPHERE_INSTALL)/bin/sdl-config --static-libs) -lGL -lGLU CPPFLAGS = -I$(STARSPHERE_INSTALL)/include CPPFLAGS += $(shell $(STARSPHERE_INSTALL)/bin/sdl-config --cflags) CPPFLAGS += $(shell $(STARSPHERE_INSTALL)/bin/freetype-config --cflags) +CPPFLAGS += $(shell $(STARSPHERE_INSTALL)/bin/xml2-config --cflags) CPPFLAGS += -I$(STARSPHERE_INSTALL)/include/BOINC -I/usr/include DEPS = Makefile