2010-05-14 01:05:28 +04:00
/* -------------------------------------------------------------------------- */
2020-04-30 16:00:02 +03:00
/* Copyright 2002-2020, OpenNebula Project, OpenNebula Systems */
2010-05-14 01:05:28 +04:00
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
# ifndef OBJECT_XML_H_
# define OBJECT_XML_H_
# include <string>
# include <vector>
2016-01-08 03:06:26 +03:00
# include <sstream>
2010-05-14 01:05:28 +04:00
# include <libxml/tree.h>
# include <libxml/parser.h>
# include <libxml/xpath.h>
# include <libxml/xpathInternals.h>
/**
* This class represents a generic Object supported by a xml document .
* The class provides basic methods to query attributes , and get xml nodes
*/
class ObjectXML
{
public :
// ---------------------- Constructors ------------------------------------
2019-09-03 17:31:51 +03:00
ObjectXML ( ) : xml ( 0 ) , ctx ( 0 ) { }
2010-05-14 01:05:28 +04:00
/**
* Constructs an object using a XML document
*/
2016-01-08 03:06:26 +03:00
ObjectXML ( const std : : string & xml_doc ) ;
2010-05-14 01:05:28 +04:00
/**
* Constructs an object using a XML Node . The node is copied to the new
* object
*/
ObjectXML ( const xmlNodePtr node ) ;
virtual ~ ObjectXML ( ) ;
/**
2016-02-05 02:55:24 +03:00
* Gets elements by xpath .
* @ param values vector with the element values .
* @ param expr of the xml element
2010-05-14 01:05:28 +04:00
*/
2016-02-05 02:55:24 +03:00
template < typename T >
void xpaths ( std : : vector < T > & values , const char * expr )
2016-01-08 03:06:26 +03:00
{
2016-02-05 02:55:24 +03:00
xmlXPathObjectPtr obj ;
2011-02-25 15:54:39 +03:00
2016-02-05 02:55:24 +03:00
xmlNodePtr cur ;
xmlChar * str_ptr ;
2019-09-03 17:31:51 +03:00
obj = xmlXPathEvalExpression ( reinterpret_cast < const xmlChar * > ( expr ) , ctx ) ;
2016-02-05 02:55:24 +03:00
if ( obj = = 0 )
{
return ;
}
switch ( obj - > type )
{
case XPATH_NUMBER :
values . push_back ( static_cast < T > ( obj - > floatval ) ) ;
break ;
case XPATH_NODESET :
2020-04-16 16:48:41 +03:00
if ( obj - > nodesetval = = 0 )
{
return ;
}
2019-09-03 17:31:51 +03:00
for ( int i = 0 ; i < obj - > nodesetval - > nodeNr ; + + i )
2016-02-05 02:55:24 +03:00
{
cur = obj - > nodesetval - > nodeTab [ i ] ;
if ( cur = = 0 | | cur - > type ! = XML_ELEMENT_NODE )
{
continue ;
}
str_ptr = xmlNodeGetContent ( cur ) ;
if ( str_ptr ! = 0 )
{
std : : istringstream iss ( reinterpret_cast < char * > ( str_ptr ) ) ;
T val ;
iss > > std : : dec > > val ;
if ( ! iss . fail ( ) )
{
values . push_back ( val ) ;
}
xmlFree ( str_ptr ) ;
}
}
break ;
default :
break ;
}
xmlXPathFreeObject ( obj ) ;
2016-01-08 03:06:26 +03:00
} ;
2011-02-25 15:54:39 +03:00
2016-02-05 02:55:24 +03:00
void xpaths ( std : : vector < std : : string > & values , const char * xpath_expr ) ;
2014-10-30 19:21:27 +03:00
/**
2016-02-05 02:55:24 +03:00
* Gets a xpath attribute , if the attribute is not found a default is used .
* This function only returns the first element
* @ param value of the element
2014-10-30 19:21:27 +03:00
* @ param xpath_expr of the xml element
* @ param def default value if the element is not found
*
* @ return - 1 if default was set
*/
2016-02-05 02:55:24 +03:00
template < typename T >
int xpath ( T & value , const char * xpath_expr , const T & def )
2016-01-08 03:06:26 +03:00
{
2016-02-05 02:55:24 +03:00
std : : vector < std : : string > values ;
2011-03-03 20:53:41 +03:00
2016-02-05 02:55:24 +03:00
xpaths ( values , xpath_expr ) ;
2012-12-04 16:35:45 +04:00
2016-02-05 02:55:24 +03:00
if ( values . empty ( ) = = true )
{
value = def ;
return - 1 ;
}
2012-12-04 16:35:45 +04:00
2016-02-05 02:55:24 +03:00
std : : istringstream iss ( values [ 0 ] ) ;
2016-01-08 03:06:26 +03:00
2016-02-05 02:55:24 +03:00
iss > > std : : dec > > value ;
2016-01-08 03:06:26 +03:00
2016-02-05 02:55:24 +03:00
if ( iss . fail ( ) = = true )
{
value = def ;
return - 1 ;
}
return 0 ;
2016-01-08 03:06:26 +03:00
}
2011-02-25 17:23:46 +03:00
2016-02-05 02:55:24 +03:00
int xpath ( std : : string & value , const char * xpath_expr , const char * def ) ;
2011-02-25 16:17:41 +03:00
/**
* Gets the value of an element from an xml string
* @ param value the value of the element
* @ param xml the xml string
* @ param xpath the xpath of the target element
2013-08-06 19:25:21 +04:00
*
2011-02-25 16:17:41 +03:00
* @ return - 1 if the element was not found
*/
2016-01-08 03:06:26 +03:00
static int xpath_value ( std : : string & value , const char * xml , const char * xpath ) ;
2011-02-25 16:17:41 +03:00
2013-08-06 19:25:21 +04:00
/**
* Search the Object for a given attribute in a set of object specific
* routes .
* @ param name of the attribute
* @ param value of the attribute
*
* @ return - 1 if the element was not found
*/
2016-03-03 17:39:41 +03:00
virtual int search ( const char * name , std : : string & value )
{
return __search ( name , value ) ;
}
2013-08-06 19:25:21 +04:00
2016-03-03 17:39:41 +03:00
virtual int search ( const char * name , int & value )
{
return __search ( name , value ) ;
}
2013-08-06 19:25:21 +04:00
2016-03-03 17:39:41 +03:00
virtual int search ( const char * name , float & value )
{
return __search ( name , value ) ;
}
2013-08-06 19:25:21 +04:00
2016-07-19 13:20:13 +03:00
/**
* Search the Object for a given attribute in a set of object specific
* routes .
* @ param name of the attribute
* @ results vector of attributes that matches the query
*/
template < typename T >
void search ( const char * name , std : : vector < T > & results )
{
if ( name [ 0 ] = = ' / ' )
{
xpaths ( results , name ) ;
}
else if ( num_paths = = 0 )
{
results . clear ( ) ;
}
else
{
std : : ostringstream xpath ;
xpath < < paths [ 0 ] < < name ;
for ( int i = 1 ; i < num_paths ; i + + )
{
xpath < < ' | ' < < paths [ i ] < < name ;
}
xpaths ( results , xpath . str ( ) . c_str ( ) ) ;
}
}
2010-05-14 01:05:28 +04:00
/**
* Get xml nodes by Xpath
* @ param xpath_expr the Xpath for the elements
* @ param content nodes for the given Xpath expression . The nodes are
2016-03-10 18:28:33 +03:00
* returned as pointers to the object nodes .
* @ return the number of nodes found
*/
int get_nodes ( const std : : string & xpath_expr ,
std : : vector < xmlNodePtr > & content ) const ;
2010-05-14 01:05:28 +04:00
2013-01-22 17:14:56 +04:00
/**
* Adds a copy of the node as a child of the node in the xpath expression .
* The source node must be cleaned by the caller .
*
* @ param xpath_expr Path of the parent node
* @ param node Node copy and add
* @ param new_name New name for the node copy
*
* @ return 0 on success , - 1 otherwise
*/
int add_node ( const char * xpath_expr , xmlNodePtr node , const char * new_name ) ;
2020-05-28 17:49:00 +03:00
/**
* Removes nodes from the object by xPath
*
* @ param xpath_expr Path of the parent node
*
* @ return number of elements removed
*/
int remove_nodes ( const char * xpath_expr ) ;
2010-05-14 01:05:28 +04:00
/**
2011-07-03 03:57:39 +04:00
* Frees a vector of XMLNodes , as returned by the get_nodes function
* @ param content the vector of xmlNodePtr
*/
2016-03-10 18:28:33 +03:00
void free_nodes ( std : : vector < xmlNodePtr > & content ) const
2011-07-03 03:57:39 +04:00
{
2016-01-08 03:06:26 +03:00
std : : vector < xmlNodePtr > : : iterator it ;
2011-07-03 03:57:39 +04:00
for ( it = content . begin ( ) ; it < content . end ( ) ; it + + )
{
xmlFreeNode ( * it ) ;
}
} ;
/**
2010-05-14 01:05:28 +04:00
* Updates the object representation with a new XML document . Previous
* XML resources are freed
* @ param xml_doc the new xml document
*/
2016-01-08 03:06:26 +03:00
int update_from_str ( const std : : string & xml_doc ) ;
2010-05-14 01:05:28 +04:00
/**
* Updates the object representation with a new XML document . Previous
* XML resources are freed
* @ param xml_doc the new xml document
*/
2011-02-24 20:12:26 +03:00
int update_from_node ( const xmlNodePtr node ) ;
2010-05-14 01:05:28 +04:00
2011-12-19 20:07:32 +04:00
/**
* Validates the xml string
*
* @ param xml_doc string to parse
* @ return 0 if the xml validates
*/
2016-01-08 03:06:26 +03:00
static int validate_xml ( const std : : string & xml_doc ) ;
2011-12-19 20:07:32 +04:00
2020-05-18 03:23:29 +03:00
/**
* Validates the XML doc against a RelaxNG schema
*
* @ param xml_doc string containing the XML document
* @ param schema_path path to RelaxNG schema file
* @ return 0 if the xml validates
*/
static int validate_rng ( const std : : string & xml_doc ,
const std : : string & schema_path ) ;
2013-01-30 20:49:24 +04:00
/**
* Renames the nodes given in the xpath expression
* @ param xpath_expr xpath expression to find the nodes to rename
* @ param new_name new name for the xml elements
*
* @ return the number of nodes renamed
*/
int rename_nodes ( const char * xpath_expr , const char * new_name ) ;
2010-05-14 05:32:42 +04:00
// ---------------------------------------------------------
// Lex & bison parser for requirements and rank expressions
// ---------------------------------------------------------
/**
* Evaluates a requirement expression on the given host .
* @ param requirements string
* @ param result true if the host matches the requirements
* @ param errmsg string describing the error , must be freed by the
* calling function
* @ return 0 on success
*/
2016-01-08 03:06:26 +03:00
int eval_bool ( const std : : string & expr , bool & result , char * * errmsg ) ;
2010-05-14 05:32:42 +04:00
/**
* Evaluates a rank expression on the given host .
* @ param rank string
* @ param result of the rank evaluation
* @ param errmsg string describing the error , must be freed by the
* calling function
* @ return 0 on success
*/
2016-01-08 03:06:26 +03:00
int eval_arith ( const std : : string & expr , int & result , char * * errmsg ) ;
2010-05-14 05:32:42 +04:00
2010-05-14 21:15:20 +04:00
/**
* Function to write the Object in an output stream
*/
2016-01-08 03:06:26 +03:00
friend std : : ostream & operator < < ( std : : ostream & os , ObjectXML & oxml )
2010-05-14 21:15:20 +04:00
{
2017-07-18 19:19:30 +03:00
xmlNodePtr root_node = xmlDocGetRootElement ( oxml . xml ) ;
2010-05-14 21:15:20 +04:00
2017-07-18 19:19:30 +03:00
if ( root_node = = 0 )
{
return os ;
}
xmlBufferPtr buffer = xmlBufferCreate ( ) ;
xmlNodeDump ( buffer , oxml . xml , root_node , 0 , 0 ) ;
2010-05-14 21:15:20 +04:00
2017-07-18 19:19:30 +03:00
std : : string str ( reinterpret_cast < char * > ( buffer - > content ) ) ;
2010-05-14 21:15:20 +04:00
os < < str ;
2017-07-18 19:19:30 +03:00
xmlBufferFree ( buffer ) ;
2010-05-14 21:15:20 +04:00
return os ;
} ;
2013-08-06 19:25:21 +04:00
protected :
/**
* Array of paths to look for attributes in search methods
*/
const char * * paths ;
/**
* Number of elements in paths array
*/
int num_paths ;
2010-05-14 01:05:28 +04:00
private :
/**
* XML representation of the Object
*/
xmlDocPtr xml ;
/**
* XPath Context to access Object elements
*/
xmlXPathContextPtr ctx ;
/**
* Parse a XML documents and initializes XPath contexts
*/
2016-01-08 03:06:26 +03:00
void xml_parse ( const std : : string & xml_doc ) ;
2013-08-06 19:25:21 +04:00
2016-03-03 17:39:41 +03:00
/**
* Search the Object for a given attribute in a set of object specific
* routes .
* @ param name of the attribute
* @ param value of the attribute
*
* @ return - 1 if the element was not found
*/
template < typename T >
int __search ( const char * name , T & value )
{
std : : vector < T > results ;
2016-07-19 13:20:13 +03:00
search ( name , results ) ;
2016-03-03 17:39:41 +03:00
if ( results . size ( ) ! = 0 )
{
value = results [ 0 ] ;
return 0 ;
}
return - 1 ;
} ;
2010-05-14 01:05:28 +04:00
} ;
# endif /*OBJECT_XML_H_*/