Statistics
| Branch: | Tag: | Revision:

one / include / ObjectXML.h @ 5f28a7bf

History | View | Annotate | Download (10.7 KB)

1
/* -------------------------------------------------------------------------- */
2
/* Copyright 2002-2017, OpenNebula Project, OpenNebula Systems                */
3
/*                                                                            */
4
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
5
/* not use this file except in compliance with the License. You may obtain    */
6
/* a copy of the License at                                                   */
7
/*                                                                            */
8
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
9
/*                                                                            */
10
/* Unless required by applicable law or agreed to in writing, software        */
11
/* distributed under the License is distributed on an "AS IS" BASIS,          */
12
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
13
/* See the License for the specific language governing permissions and        */
14
/* limitations under the License.                                             */
15
/* -------------------------------------------------------------------------- */
16

    
17

    
18
#ifndef OBJECT_XML_H_
19
#define OBJECT_XML_H_
20

    
21
#include <string>
22
#include <vector>
23
#include <sstream>
24

    
25
#include <libxml/tree.h>
26
#include <libxml/parser.h>
27
#include <libxml/xpath.h>
28
#include <libxml/xpathInternals.h>
29

    
30
/**
31
 *  This class represents a generic Object supported by a xml document.
32
 *  The class provides basic methods to query attributes, and get xml nodes
33
 */
34
class ObjectXML
35
{
36
public:
37

    
38
    // ---------------------- Constructors ------------------------------------
39

    
40
    ObjectXML():xml(0),ctx(0){};
41

    
42
    /**
43
     *  Constructs an object using a XML document
44
     */
45
    ObjectXML(const std::string &xml_doc);
46

    
47
    /**
48
     *  Constructs an object using a XML Node. The node is copied to the new
49
     *  object
50
     */
51
    ObjectXML(const xmlNodePtr node);
52

    
53
    virtual ~ObjectXML();
54

    
55
    /**
56
     *  Gets elements by xpath.
57
     *    @param values vector with the element values.
58
     *    @param expr of the xml element
59
     */
60
    template<typename T>
61
    void xpaths(std::vector<T>& values, const char * expr)
62
    {
63
        xmlXPathObjectPtr obj;
64

    
65
        xmlNodePtr cur;
66
        xmlChar *  str_ptr;
67

    
68
        obj=xmlXPathEvalExpression(reinterpret_cast<const xmlChar *>(expr),ctx);
69

    
70
        if (obj == 0)
71
        {
72
            return;
73
        }
74

    
75
        switch (obj->type)
76
        {
77
            case XPATH_NUMBER:
78
                values.push_back(static_cast<T>(obj->floatval));
79
                break;
80

    
81
            case XPATH_NODESET:
82
                for(int i = 0; i < obj->nodesetval->nodeNr ; ++i)
83
                {
84
                    cur = obj->nodesetval->nodeTab[i];
85

    
86
                    if ( cur == 0 || cur->type != XML_ELEMENT_NODE )
87
                    {
88
                        continue;
89
                    }
90

    
91
                    str_ptr = xmlNodeGetContent(cur);
92

    
93
                    if (str_ptr != 0)
94
                    {
95
                        std::istringstream iss(reinterpret_cast<char *>(str_ptr));
96
                        T val;
97

    
98
                        iss >> std::dec >> val;
99

    
100
                        if (!iss.fail())
101
                        {
102
                            values.push_back(val);
103
                        }
104

    
105
                        xmlFree(str_ptr);
106
                    }
107
                }
108
                break;
109

    
110
            default:
111
                break;
112

    
113
        }
114

    
115
        xmlXPathFreeObject(obj);
116
    };
117

    
118
    void xpaths(std::vector<std::string>& values, const char * xpath_expr);
119

    
120
    /**
121
     *  Gets a xpath attribute, if the attribute is not found a default is used.
122
     *  This function only returns the first element
123
     *    @param value of the element
124
     *    @param xpath_expr of the xml element
125
     *    @param def default value if the element is not found
126
     *
127
     *    @return -1 if default was set
128
     */
129
    template<typename T>
130
    int xpath(T& value, const char * xpath_expr, const T& def)
131
    {
132
        std::vector<std::string> values;
133

    
134
        xpaths(values, xpath_expr);
135

    
136
        if (values.empty() == true)
137
        {
138
            value = def;
139
            return -1;
140
        }
141

    
142
        std::istringstream iss(values[0]);
143

    
144
        iss >> std::dec >> value;
145

    
146
        if (iss.fail() == true)
147
        {
148
            value = def;
149
            return -1;
150
        }
151

    
152
        return 0;
153
    }
154

    
155
    int xpath(std::string& value, const char * xpath_expr, const char * def);
156

    
157
    /**
158
     *  Gets the value of an element from an xml string
159
     *    @param value the value of the element
160
     *    @param xml the xml string
161
     *    @param xpath the xpath of the target element
162
     *
163
     *    @return -1 if the element was not found
164
     */
165
    static int xpath_value(std::string& value, const char *xml, const char *xpath);
166

    
167
    /**
168
     *  Search the Object for a given attribute in a set of object specific
169
     *  routes.
170
     *    @param name of the attribute
171
     *    @param value of the attribute
172
     *
173
     *    @return -1 if the element was not found
174
     */
175
    virtual int search(const char *name, std::string& value)
176
    {
177
        return __search(name, value);
178
    }
179

    
180
    virtual int search(const char *name, int& value)
181
    {
182
        return __search(name, value);
183
    }
184

    
185
    virtual int search(const char *name, float& value)
186
    {
187
        return __search(name, value);
188
    }
189

    
190
    /**
191
     *  Search the Object for a given attribute in a set of object specific
192
     *  routes.
193
     *  @param name of the attribute
194
     *  @results vector of attributes that matches the query
195
     */
196
    template<typename T>
197
    void search(const char* name, std::vector<T>& results)
198
    {
199

    
200
        if (name[0] == '/')
201
        {
202
            xpaths(results, name);
203
        }
204
        else if (num_paths == 0)
205
        {
206
            results.clear();
207
        }
208
        else
209
        {
210
            std::ostringstream  xpath;
211

    
212
            xpath << paths[0] << name;
213

    
214
            for (int i = 1; i < num_paths ; i++)
215
            {
216
                xpath << '|' << paths[i] << name;
217
            }
218

    
219
            xpaths(results, xpath.str().c_str());
220
        }
221
    }
222

    
223
    /**
224
     *  Get xml nodes by Xpath
225
     *    @param xpath_expr the Xpath for the elements
226
     *    @param content nodes for the given Xpath expression. The nodes are
227
     *    returned as pointers to the object nodes.
228
     *    @return the number of nodes found
229
     */
230
    int get_nodes(const std::string& xpath_expr,
231
                  std::vector<xmlNodePtr>& content) const;
232

    
233
    /**
234
     * Adds a copy of the node as a child of the node in the xpath expression.
235
     * The source node must be cleaned by the caller.
236
     *
237
     * @param xpath_expr Path of the parent node
238
     * @param node Node copy and add
239
     * @param new_name New name for the node copy
240
     *
241
     * @return 0 on success, -1 otherwise
242
     */
243
    int add_node(const char * xpath_expr, xmlNodePtr node, const char * new_name);
244

    
245
    /**
246
     *  Frees a vector of XMLNodes, as returned by the get_nodes function
247
     *    @param content the vector of xmlNodePtr
248
     */
249
    void free_nodes(std::vector<xmlNodePtr>& content) const
250
    {
251
        std::vector<xmlNodePtr>::iterator it;
252

    
253
        for (it = content.begin(); it < content.end(); it++)
254
        {
255
            xmlFreeNode(*it);
256
        }
257
    };
258

    
259
    /**
260
     *   Updates the object representation with a new XML document. Previous
261
     *   XML resources are freed
262
     *   @param xml_doc the new xml document
263
     */
264
    int update_from_str(const std::string &xml_doc);
265

    
266
    /**
267
     *   Updates the object representation with a new XML document. Previous
268
     *   XML resources are freed
269
     *   @param xml_doc the new xml document
270
     */
271
    int update_from_node(const xmlNodePtr node);
272

    
273
    /**
274
     *  Validates the xml string
275
     *
276
     *  @param xml_doc string to parse
277
     *  @return 0 if the xml validates
278
     */
279
    static int validate_xml(const std::string &xml_doc);
280

    
281
    /**
282
     * Renames the nodes given in the xpath expression
283
     * @param xpath_expr xpath expression to find the nodes to rename
284
     * @param new_name new name for the xml elements
285
     *
286
     * @return the number of nodes renamed
287
     */
288
    int rename_nodes(const char * xpath_expr, const char * new_name);
289

    
290
    // ---------------------------------------------------------
291
    //  Lex & bison parser for requirements and rank expressions
292
    // ---------------------------------------------------------
293

    
294
    /**
295
     *  Evaluates a requirement expression on the given host.
296
     *    @param requirements string
297
     *    @param result true if the host matches the requirements
298
     *    @param errmsg string describing the error, must be freed by the
299
     *    calling function
300
     *    @return 0 on success
301
     */
302
    int eval_bool(const std::string& expr, bool& result, char **errmsg);
303

    
304
    /**
305
     *  Evaluates a rank expression on the given host.
306
     *    @param rank string
307
     *    @param result of the rank evaluation
308
     *    @param errmsg string describing the error, must be freed by the
309
     *    calling function
310
     *    @return 0 on success
311
     */
312
    int eval_arith(const std::string& expr, int& result, char **errmsg);
313

    
314
    /**
315
     *  Function to write the Object in an output stream
316
     */
317
    friend std::ostream& operator<<(std::ostream& os, ObjectXML& oxml)
318
    {
319
        xmlNodePtr root_node = xmlDocGetRootElement(oxml.xml);
320

    
321
        if ( root_node == 0 )
322
        {
323
            return os;
324
        }
325

    
326
        xmlBufferPtr buffer = xmlBufferCreate();
327

    
328
        xmlNodeDump(buffer, oxml.xml, root_node, 0, 0);
329

    
330
        std::string str(reinterpret_cast<char *>(buffer->content));
331
        os << str;
332

    
333
        xmlBufferFree(buffer);
334

    
335
        return os;
336
    };
337

    
338
protected:
339
    /**
340
     *  Array of paths to look for attributes in search methods
341
     */
342
    const char **paths;
343

    
344
    /**
345
     *  Number of elements in paths array
346
     */
347
    int num_paths;
348

    
349
private:
350
    /**
351
     *  XML representation of the Object
352
     */
353
    xmlDocPtr   xml;
354

    
355
    /**
356
     *  XPath Context to access Object elements
357
     */
358
    xmlXPathContextPtr ctx;
359

    
360
    /**
361
     *  Parse a XML documents and initializes XPath contexts
362
     */
363
    void xml_parse(const std::string &xml_doc);
364

    
365
    /**
366
     *  Search the Object for a given attribute in a set of object specific
367
     *  routes.
368
     *    @param name of the attribute
369
     *    @param value of the attribute
370
     *
371
     *    @return -1 if the element was not found
372
     */
373
    template<typename T>
374
    int __search(const char *name, T& value)
375
    {
376
        std::vector<T> results;
377

    
378
        search(name, results);
379

    
380
        if (results.size() != 0)
381
        {
382
            value = results[0];
383

    
384
            return 0;
385
        }
386

    
387
        return -1;
388
    };
389
};
390

    
391
#endif /*OBJECT_XML_H_*/