Statistics
| Branch: | Revision:

root / include / cxmlelement.h @ master

History | View | Annotate | Download (12.5 KB)

1
//==========================================================================
2
//  CXMLELEMENT.H - part of
3
//                     OMNeT++/OMNEST
4
//            Discrete System Simulation in C++
5
//
6
// Contents:
7
//   class cXMLElement
8
//
9
//==========================================================================
10

    
11
/*--------------------------------------------------------------*
12
  Copyright (C) 2002-2008 Andras Varga
13
  Copyright (C) 2006-2008 OpenSim Ltd.
14

15
  This file is distributed WITHOUT ANY WARRANTY. See the file
16
  `license' for details on this and other legal matters.
17
*--------------------------------------------------------------*/
18

    
19
#ifndef __CXMLELEMENT_H
20
#define __CXMLELEMENT_H
21

    
22
#include <string>
23
#include <map>
24
#include <vector>
25
#include "simkerneldefs.h"
26
#include "cenvir.h"
27

    
28
NAMESPACE_BEGIN
29

    
30
class cXMLElement;
31
class cModule;
32

    
33
/**
34
 * A list of XML elements. Used with cXMLElement.
35
 */
36
typedef std::vector<cXMLElement*> cXMLElementList;
37

    
38
/**
39
 * Attributes of an XML element. Used with cXMLElement.
40
 */
41
typedef std::map<std::string,std::string> cXMLAttributeMap;
42

    
43

    
44
/**
45
 * Represents an XML element in an XML configuration file. XML-typed
46
 * NED parameters are accessible as cXMLElement via the cPar::xmlValue() const
47
 * method.
48
 *
49
 * cXMLElement provides read only access to the XML, with functionality that
50
 * resembles DOM. (A full-featured DOM implementation would have
51
 * been too bloated for the purpose of accessing readonly
52
 * configuration files).
53
 *
54
 * Features: only readonly (getter) methods; represents only elements
55
 * and text (entities, processing instructions, comments are ignored);
56
 * attributes are presented as part of an element getNode(not as separate
57
 * attribute nodes as in DOM); mixed content model not supported
58
 * (element body cannot mix text with further elements);
59
 * text is represented as a property of its enclosing element (and not
60
 * as separate node as in DOM); CDATA sections are also represented as
61
 * text (with the above restrictions); strings are presented in UTF-8 format
62
 * (which is normal ASCII string if only characters 0x01-0x7F are used;
63
 * encoding of the XML file itself may use arbitrary encoding provided it's
64
 * supported by the underlying XML parser); no namespace support.
65
 *
66
 * Supports XPath-like addressing via the getElementByPath() member function.
67
 *
68
 * File inclusion via limited support of the XInclude 1.0 spec.
69
 * An element \<xi:include href="doc.xml"/\> gets replaced with
70
 * the content of the corresponding document. The "href" and "parse"
71
 * attributes from the XInclude spec are supported.
72
 *
73
 * @ingroup SimSupport
74
 */
75
class SIM_API cXMLElement
76
{
77
  public:
78
    /**
79
     * Base class for classes that resolve parameters ($PARAM) that occur in
80
     * in XPath expressions to their values.
81
     */
82
    class SIM_API ParamResolver
83
    {
84
      public:
85
        /**
86
         * To be redefined in subclasses. If paramname is recognized, the method
87
         * should store the value in the 'value' argument and return true;
88
         * otherwise it should return false.
89
         */
90
        virtual bool resolve(const char *paramname, std::string& value) = 0;
91
        virtual ~ParamResolver() {}
92
    };
93

    
94
  private:
95
    std::string ename;
96
    std::string srcloc;
97
    std::string value;
98
    cXMLAttributeMap attrs;
99
    cXMLElement *parent;
100
    cXMLElement *firstchild;
101
    cXMLElement *lastchild;
102
    cXMLElement *prevsibling;
103
    cXMLElement *nextsibling;
104

    
105
  private:
106
     void doGetElementsByTagName(const char *tagname, cXMLElementList& list) const;
107

    
108
  public:
109
    // internal: Constructor
110
    cXMLElement(const char *tagname, const char *srcloc, cXMLElement *parent);
111

    
112
    // internal: sets text node within element
113
    virtual void setNodeValue(const char *s, int len);
114

    
115
    // internal: appends to text node within element
116
    virtual void appendNodeValue(const char *s, int len);
117

    
118
    // internal: Destructor. Destroys children too.
119
    virtual ~cXMLElement();
120

    
121
    // internal: Sets the value of the attribute with the given name.
122
    virtual void setAttribute(const char *attr, const char *value);
123

    
124
    // internal: Appends the given element at the end of the child element list.
125
    virtual void appendChild(cXMLElement *node);
126

    
127
    // internal: Inserts the given element just before the specified child element
128
    // in the child element list. The where element must be a child of this element.
129
    virtual void insertChildBefore(cXMLElement *where, cXMLElement *newnode);
130

    
131
    // internal: Removes the given element from the child element list.
132
    // The pointer passed should be a child of this element.
133
    virtual cXMLElement *removeChild(cXMLElement *node);
134

    
135
    // internal: matches from root element
136
    static cXMLElement *getDocumentElementByPath(cXMLElement *documentnode, const char *pathexpr, ParamResolver *resolver=NULL);
137

    
138
    // internal
139
    std::string tostr(int level) const;
140

    
141
    /** @name Common properties */
142
    //@{
143

    
144
    /**
145
     * Returns the element name.
146
     */
147
    virtual const char *getTagName() const;
148

    
149
    /**
150
     * Returns a string containing a file/line position showing where this
151
     * element originally came from.
152
     */
153
    virtual const char *getSourceLocation() const;
154

    
155
    /**
156
     * Returns text node in the element, or NULL otherwise.
157
     * (Mixing text and child elements is not supported.)
158
     */
159
    virtual const char *getNodeValue() const;
160

    
161
    /**
162
     * Returns the value of the attribute with the given name.
163
     * It returns NULL if the given attribute is not found.
164
     */
165
    virtual const char *getAttribute(const char *attr) const;
166

    
167
    /**
168
     * Returns true if the node has attributes
169
     */
170
    virtual bool hasAttributes() const;
171

    
172
    /**
173
     * Returns attributes as a const (immutable) std::map.
174
     */
175
    virtual const cXMLAttributeMap& getAttributes() const;
176
    //@}
177

    
178
    /** @name Generic access to children and siblings */
179
    //@{
180
    /**
181
     * Returns the parent element, or NULL if this element has no parent.
182
     */
183
    virtual cXMLElement *getParentNode() const;
184

    
185
    /**
186
     * Returns true if the node has children.
187
     */
188
    virtual bool hasChildren() const;
189

    
190
    /**
191
     * Returns pointer to the first child element, or NULL if this element
192
     * has no children.
193
     */
194
    virtual cXMLElement *getFirstChild() const;
195

    
196
    /**
197
     * Returns pointer to the last child element, or NULL if this element
198
     * has no children.
199
     */
200
    virtual cXMLElement *getLastChild() const;
201

    
202
    /**
203
     * Returns pointer to the next sibling of this element (i.e. the next child
204
     * in the parent element). Returns NULL if there're no subsequent elements.
205
     *
206
     * getFirstChild() and getNextSibling() can be used to loop through
207
     * the child list:
208
     *
209
     * <pre>
210
     * for (cXMLElement *child=node->getFirstChild(); child; child = child->getNextSibling())
211
     * {
212
     *    ...
213
     * }
214
     * </pre>
215
     *
216
     */
217
    virtual cXMLElement *getNextSibling() const;
218

    
219
    /**
220
     * Returns pointer to the previous sibling of this element (i.e. the
221
     * previous child in the parent element). Returns NULL if there're no
222
     * elements before this one.
223
     */
224
    virtual cXMLElement *getPreviousSibling() const;
225

    
226
    /**
227
     * Returns pointer to the first child element with the given tag name,
228
     * or NULL if this element has no such children.
229
     */
230
    virtual cXMLElement *getFirstChildWithTag(const char *tagname) const;
231

    
232
    /**
233
     * Returns pointer to the next sibling of this element with the given
234
     * tag name. Return NULL if there're no such subsequent elements.
235
     *
236
     * getFirstChildWithTag() and getNextSiblingWithTag() are a convient way
237
     * to loop through elements with a certain tag name in the child list:
238
     *
239
     * <pre>
240
     * for (cXMLElement *child=node->getFirstChildWithTag("foo"); child; child = child->getNextSiblingWithTag("foo"))
241
     * {
242
     *     ...
243
     * }
244
     * </pre>
245
     */
246
    virtual cXMLElement *getNextSiblingWithTag(const char *tagname) const;
247

    
248
    /**
249
     * Returns list of child elements.
250
     */
251
    virtual cXMLElementList getChildren() const;
252

    
253
    /**
254
     * Returns list of child elements with the given tag name.
255
     */
256
    virtual cXMLElementList getChildrenByTagName(const char *tagname) const;
257

    
258
    /**
259
     * Returns list of contained elements with the given tag name, in preorder
260
     * traversal order.
261
     */
262
    virtual cXMLElementList getElementsByTagName(const char *tagname) const;
263
    //@}
264

    
265
    /** @name Utility functions */
266
    //@{
267
    /**
268
     * Returns find first child element with the given tagname and the given
269
     * attribute present, and (optionally) having the given value.
270
     * tagname might be NULL -- then any element with the given attribute
271
     * will be accepted. Returns NULL if not found.
272
     */
273
    cXMLElement *getFirstChildWithAttribute(const char *tagname, const char *attr, const char *attrvalue=NULL) const;
274

    
275
    /**
276
     * Returns the first element which has an "id" attribute with the given
277
     * value. ("id" attributes are supposed to be unique in an XML document.)
278
     * Returns NULL if not found.
279
     */
280
    cXMLElement *getElementById(const char *idattrvalue) const;
281

    
282
    /**
283
     * Returns the first element designated by the given path expression.
284
     * ("First" in the sense of preorder depth-first traversal.)
285
     * Path expressions must be given in an XPath-like notation:
286
     * they consist of path components (or "steps") separated by "/" or "//".
287
     * A path component can be an element tag name, "*", "." or "..";
288
     * tag name and "*" can have an optional predicate in the form "[position]"
289
     * or "[@attribute='value']". "/" means child element; "//" means a element
290
     * any levels under the current one; ".", ".." and "*" mean what you
291
     * expect them to: current element, parent element, element with any tag name.
292
     *
293
     * Examples:
294
     *  - <tt>.</tt> -- this element
295
     *  - <tt>./foo</tt> -- first "foo" child of this node
296
     *  - <tt>foo</tt> -- same as <tt>./foo</tt> (initial <tt>./</tt> can be omitted)
297
     *  - <tt>./foo</tt> -- first "foo" child of this node
298
     *  - <tt>./foo/bar</tt> -- first "bar" child of first "foo" child of this node
299
     *  - <tt>.//bar</tt> -- first "bar" anywhere under this getNode(depth-first search!)
300
     *  - <tt>./ * /bar</tt> -- first "bar" child two levels below this getNode(omit spaces)
301
     *  - <tt>./foo[0]</tt> -- first "foo" child of this node
302
     *  - <tt>./foo[1]</tt> -- second "foo" child of this node
303
     *  - <tt>./foo[\@color='green']</tt> -- first "foo" child which has attribute "color" with value "green"
304
     *  - <tt>.//bar[1]</tt> -- a "bar" anywhere under this node which is the second "bar" among its siblings
305
     *  - <tt>.// * [\@color='yellow']</tt> -- an element anywhere under this node with attribute color="yellow" (omit spaces)
306
     *  - <tt>.// * [\@color='yellow']/foo/bar</tt> -- first "bar" child of first "foo" child of a "yellow-colored" getNode(omit spaces)
307
     *
308
     * The method throws an exception if the path expression is invalid,
309
     * and returns NULL if the element is not found.
310
     */
311
    cXMLElement *getElementByPath(const char *pathexpression, cXMLElement *root=NULL, ParamResolver *resolver=NULL) const;
312

    
313
    /**
314
     * Prints detailedInfo() on ev.
315
     */
316
    void debugDump() const;
317

    
318
    /**
319
     * Returns tree contents in an XML-like format. This method is only
320
     * useful for debugging, because it does not perform necessary escaping
321
     * in text nodes and attribute values, so the output is not necessarily
322
     * well-formed XML.
323
     */
324
    virtual std::string detailedInfo() const;
325
    //@}
326
};
327

    
328
/**
329
 * A parameter resolver class for cXMLElement (more precisely, for
330
 * cXMLElement::getElementByPath()) that, given a cModule pointer, resolves
331
 * the following parameters: $MODULE_FULLPATH, $MODULE_FULLNAME, $MODULE_NAME,
332
 * $MODULE_INDEX, $MODULE_ID; $PARENTMODULE_FULLPATH etc;
333
 * $GRANDPARENTMODULE_FULLPATH etc.
334
 */
335
class SIM_API ModNameParamResolver : public cXMLElement::ParamResolver
336
{
337
  protected:
338
    cModule *mod;
339
  public:
340
    ModNameParamResolver(cModule *mod)  {this->mod = mod;}
341
    virtual bool resolve(const char *paramname, std::string& value);
342
};
343

    
344
/**
345
 * A parameter resolver class for cXMLElement (more precisely, for
346
 * cXMLElement::getElementByPath()), which resolves parameters from
347
 * a string map that contains (parametername, value) pairs.
348
 */
349
class SIM_API StringMapParamResolver : public cXMLElement::ParamResolver
350
{
351
  public:
352
    typedef std::map<std::string,std::string> StringMap;
353
  protected:
354
    StringMap params;
355
  public:
356
    StringMapParamResolver(const StringMap& m)  {params = m;}
357
    virtual bool resolve(const char *paramname, std::string& value);
358
};
359

    
360
NAMESPACE_END
361

    
362

    
363
#endif
364