VirtualBox

source: vbox/trunk/include/iprt/cpp/xml.h@ 54415

Last change on this file since 54415 was 49028, checked in by vboxsync, 11 years ago

iprt/cpp/xml: Fixed attribute lookup with namespace by doing the same way as for elements. Also renamed the two methods with namespace prefix and name in the 'logical' order so they can safely be changed to the order dictated C++ default parameter value handling (name first, then optionally ns-prefix), like the rest.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 34.5 KB
Line 
1/** @file
2 * IPRT - XML Helper APIs.
3 */
4
5/*
6 * Copyright (C) 2007-2012 Oracle Corporation
7 *
8 * This file is part of VirtualBox Open Source Edition (OSE), as
9 * available from http://www.virtualbox.org. This file is free software;
10 * you can redistribute it and/or modify it under the terms of the GNU
11 * General Public License (GPL) as published by the Free Software
12 * Foundation, in version 2 as it comes in the "COPYING" file of the
13 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
14 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
15 *
16 * The contents of this file may alternatively be used under the terms
17 * of the Common Development and Distribution License Version 1.0
18 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
19 * VirtualBox OSE distribution, in which case the provisions of the
20 * CDDL are applicable instead of those of the GPL.
21 *
22 * You may elect to license modified versions of this file under the
23 * terms and conditions of either the GPL or the CDDL or both.
24 */
25
26#ifndef ___iprt_xml_h
27#define ___iprt_xml_h
28
29#ifndef IN_RING3
30# error "There are no XML APIs available in Ring-0 Context!"
31#endif
32
33#include <iprt/list.h>
34#include <iprt/cpp/exception.h>
35#include <iprt/cpp/utils.h>
36
37#include <list>
38#include <memory>
39
40
41/** @defgroup grp_rt_cpp_xml C++ XML support
42 * @ingroup grp_rt_cpp
43 * @{
44 */
45
46/* Forwards */
47typedef struct _xmlParserInput xmlParserInput;
48typedef xmlParserInput *xmlParserInputPtr;
49typedef struct _xmlParserCtxt xmlParserCtxt;
50typedef xmlParserCtxt *xmlParserCtxtPtr;
51typedef struct _xmlError xmlError;
52typedef xmlError *xmlErrorPtr;
53
54typedef struct _xmlAttr xmlAttr;
55typedef struct _xmlNode xmlNode;
56
57/** @} */
58
59namespace xml
60{
61
62/**
63 * @addtogroup grp_rt_cpp_xml
64 * @{
65 */
66
67// Exceptions
68//////////////////////////////////////////////////////////////////////////////
69
70class RT_DECL_CLASS LogicError : public RTCError
71{
72public:
73
74 LogicError(const char *aMsg = NULL)
75 : RTCError(aMsg)
76 {}
77
78 LogicError(RT_SRC_POS_DECL);
79};
80
81class RT_DECL_CLASS RuntimeError : public RTCError
82{
83public:
84
85 RuntimeError(const char *aMsg = NULL)
86 : RTCError(aMsg)
87 {}
88};
89
90class RT_DECL_CLASS XmlError : public RuntimeError
91{
92public:
93 XmlError(xmlErrorPtr aErr);
94
95 static char* Format(xmlErrorPtr aErr);
96};
97
98// Logical errors
99//////////////////////////////////////////////////////////////////////////////
100
101class RT_DECL_CLASS ENotImplemented : public LogicError
102{
103public:
104 ENotImplemented(const char *aMsg = NULL) : LogicError(aMsg) {}
105 ENotImplemented(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
106};
107
108class RT_DECL_CLASS EInvalidArg : public LogicError
109{
110public:
111 EInvalidArg(const char *aMsg = NULL) : LogicError(aMsg) {}
112 EInvalidArg(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
113};
114
115class RT_DECL_CLASS EDocumentNotEmpty : public LogicError
116{
117public:
118 EDocumentNotEmpty(const char *aMsg = NULL) : LogicError(aMsg) {}
119 EDocumentNotEmpty(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
120};
121
122class RT_DECL_CLASS ENodeIsNotElement : public LogicError
123{
124public:
125 ENodeIsNotElement(const char *aMsg = NULL) : LogicError(aMsg) {}
126 ENodeIsNotElement(RT_SRC_POS_DECL) : LogicError(RT_SRC_POS_ARGS) {}
127};
128
129// Runtime errors
130//////////////////////////////////////////////////////////////////////////////
131
132class RT_DECL_CLASS EIPRTFailure : public RuntimeError
133{
134public:
135
136 EIPRTFailure(int aRC, const char *pcszContext, ...);
137
138 int rc() const
139 {
140 return mRC;
141 }
142
143private:
144 int mRC;
145};
146
147/**
148 * The Stream class is a base class for I/O streams.
149 */
150class RT_DECL_CLASS Stream
151{
152public:
153
154 virtual ~Stream() {}
155
156 virtual const char *uri() const = 0;
157
158 /**
159 * Returns the current read/write position in the stream. The returned
160 * position is a zero-based byte offset from the beginning of the file.
161 *
162 * Throws ENotImplemented if this operation is not implemented for the
163 * given stream.
164 */
165 virtual uint64_t pos() const = 0;
166
167 /**
168 * Sets the current read/write position in the stream.
169 *
170 * @param aPos Zero-based byte offset from the beginning of the stream.
171 *
172 * Throws ENotImplemented if this operation is not implemented for the
173 * given stream.
174 */
175 virtual void setPos (uint64_t aPos) = 0;
176};
177
178/**
179 * The Input class represents an input stream.
180 *
181 * This input stream is used to read the settings tree from.
182 * This is an abstract class that must be subclassed in order to fill it with
183 * useful functionality.
184 */
185class RT_DECL_CLASS Input : virtual public Stream
186{
187public:
188
189 /**
190 * Reads from the stream to the supplied buffer.
191 *
192 * @param aBuf Buffer to store read data to.
193 * @param aLen Buffer length.
194 *
195 * @return Number of bytes read.
196 */
197 virtual int read (char *aBuf, int aLen) = 0;
198};
199
200/**
201 *
202 */
203class RT_DECL_CLASS Output : virtual public Stream
204{
205public:
206
207 /**
208 * Writes to the stream from the supplied buffer.
209 *
210 * @param aBuf Buffer to write data from.
211 * @param aLen Buffer length.
212 *
213 * @return Number of bytes written.
214 */
215 virtual int write (const char *aBuf, int aLen) = 0;
216
217 /**
218 * Truncates the stream from the current position and upto the end.
219 * The new file size will become exactly #pos() bytes.
220 *
221 * Throws ENotImplemented if this operation is not implemented for the
222 * given stream.
223 */
224 virtual void truncate() = 0;
225};
226
227
228//////////////////////////////////////////////////////////////////////////////
229
230/**
231 * The File class is a stream implementation that reads from and writes to
232 * regular files.
233 *
234 * The File class uses IPRT File API for file operations. Note that IPRT File
235 * API is not thread-safe. This means that if you pass the same RTFILE handle to
236 * different File instances that may be simultaneously used on different
237 * threads, you should care about serialization; otherwise you will get garbage
238 * when reading from or writing to such File instances.
239 */
240class RT_DECL_CLASS File : public Input, public Output
241{
242public:
243
244 /**
245 * Possible file access modes.
246 */
247 enum Mode { Mode_Read, Mode_WriteCreate, Mode_Overwrite, Mode_ReadWrite };
248
249 /**
250 * Opens a file with the given name in the given mode. If @a aMode is Read
251 * or ReadWrite, the file must exist. If @a aMode is Write, the file must
252 * not exist. Otherwise, an EIPRTFailure excetion will be thrown.
253 *
254 * @param aMode File mode.
255 * @param aFileName File name.
256 * @param aFlushIt Whether to flush a writable file before closing it.
257 */
258 File(Mode aMode, const char *aFileName, bool aFlushIt = false);
259
260 /**
261 * Uses the given file handle to perform file operations. This file
262 * handle must be already open in necessary mode (read, or write, or mixed).
263 *
264 * The read/write position of the given handle will be reset to the
265 * beginning of the file on success.
266 *
267 * Note that the given file handle will not be automatically closed upon
268 * this object destruction.
269 *
270 * @note It you pass the same RTFILE handle to more than one File instance,
271 * please make sure you have provided serialization in case if these
272 * instasnces are to be simultaneously used by different threads.
273 * Otherwise you may get garbage when reading or writing.
274 *
275 * @param aHandle Open file handle.
276 * @param aFileName File name (for reference).
277 * @param aFlushIt Whether to flush a writable file before closing it.
278 */
279 File(RTFILE aHandle, const char *aFileName = NULL, bool aFlushIt = false);
280
281 /**
282 * Destroys the File object. If the object was created from a file name
283 * the corresponding file will be automatically closed. If the object was
284 * created from a file handle, it will remain open.
285 */
286 virtual ~File();
287
288 const char *uri() const;
289
290 uint64_t pos() const;
291 void setPos(uint64_t aPos);
292
293 /**
294 * See Input::read(). If this method is called in wrong file mode,
295 * LogicError will be thrown.
296 */
297 int read(char *aBuf, int aLen);
298
299 /**
300 * See Output::write(). If this method is called in wrong file mode,
301 * LogicError will be thrown.
302 */
303 int write(const char *aBuf, int aLen);
304
305 /**
306 * See Output::truncate(). If this method is called in wrong file mode,
307 * LogicError will be thrown.
308 */
309 void truncate();
310
311private:
312
313 /* Obscure class data */
314 struct Data;
315 Data *m;
316
317 /* auto_ptr data doesn't have proper copy semantics */
318 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP (File)
319};
320
321/**
322 * The MemoryBuf class represents a stream implementation that reads from the
323 * memory buffer.
324 */
325class RT_DECL_CLASS MemoryBuf : public Input
326{
327public:
328
329 MemoryBuf (const char *aBuf, size_t aLen, const char *aURI = NULL);
330
331 virtual ~MemoryBuf();
332
333 const char *uri() const;
334
335 int read(char *aBuf, int aLen);
336 uint64_t pos() const;
337 void setPos(uint64_t aPos);
338
339private:
340 /* Obscure class data */
341 struct Data;
342 Data *m;
343
344 /* auto_ptr data doesn't have proper copy semantics */
345 DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(MemoryBuf)
346};
347
348
349/*
350 * GlobalLock
351 *
352 *
353 */
354
355typedef xmlParserInput* FNEXTERNALENTITYLOADER(const char *aURI,
356 const char *aID,
357 xmlParserCtxt *aCtxt);
358typedef FNEXTERNALENTITYLOADER *PFNEXTERNALENTITYLOADER;
359
360class RT_DECL_CLASS GlobalLock
361{
362public:
363 GlobalLock();
364 ~GlobalLock();
365
366 void setExternalEntityLoader(PFNEXTERNALENTITYLOADER pFunc);
367
368 static xmlParserInput* callDefaultLoader(const char *aURI,
369 const char *aID,
370 xmlParserCtxt *aCtxt);
371
372private:
373 /* Obscure class data. */
374 struct Data;
375 struct Data *m;
376};
377
378class ElementNode;
379typedef std::list<const ElementNode*> ElementNodesList;
380
381class AttributeNode;
382
383class ContentNode;
384
385/**
386 * Node base class.
387 *
388 * Cannot be used directly, but ElementNode, ContentNode and AttributeNode
389 * derive from this. This does implement useful public methods though.
390 *
391 *
392 */
393class RT_DECL_CLASS Node
394{
395public:
396 virtual ~Node();
397
398 const char *getName() const;
399 const char *getPrefix() const;
400 const char *getNamespaceURI() const;
401 bool nameEqualsNS(const char *pcszNamespace, const char *pcsz) const;
402 bool nameEquals(const char *pcsz) const
403 {
404 return nameEqualsNS(NULL, pcsz);
405 }
406 bool nameEqualsN(const char *pcsz, size_t cchMax, const char *pcszNamespace = NULL) const;
407
408 const char *getValue() const;
409 bool copyValue(int32_t &i) const;
410 bool copyValue(uint32_t &i) const;
411 bool copyValue(int64_t &i) const;
412 bool copyValue(uint64_t &i) const;
413
414 /** @name Introspection.
415 * @{ */
416 /** Is this an ElementNode instance.
417 * @returns true / false */
418 bool isElement() const
419 {
420 return m_Type == IsElement;
421 }
422
423 /** Is this an ContentNode instance.
424 * @returns true / false */
425 bool isContent() const
426 {
427 return m_Type == IsContent;
428 }
429
430 /** Is this an AttributeNode instance.
431 * @returns true / false */
432 bool isAttribute() const
433 {
434 return m_Type == IsElement;
435 }
436
437 int getLineNumber() const;
438 /** @} */
439
440 /** @name General tree enumeration.
441 *
442 * Use the introspection methods isElement() and isContent() before doing static
443 * casting. Parents are always or ElementNode type, but siblings and children
444 * can be of both ContentNode and ElementNode types.
445 *
446 * @remarks Attribute node are in the attributes list, while both content and
447 * element nodes are in the list of children. See ElementNode.
448 *
449 * @remarks Careful mixing tree walking with node removal!
450 * @{
451 */
452 /** Get the parent node
453 * @returns Pointer to the parent node, or NULL if root. */
454 const Node *getParent() const
455 {
456 return m_pParent;
457 }
458
459 /** Get the previous sibling.
460 * @returns Pointer to the previous sibling node, NULL if first child.
461 */
462 const Node *getPrevSibiling() const
463 {
464 if (!m_pParentListAnchor)
465 return NULL;
466 return RTListGetPrevCpp(m_pParentListAnchor, this, const Node, m_listEntry);
467 }
468
469 /** Get the next sibling.
470 * @returns Pointer to the next sibling node, NULL if last child. */
471 const Node *getNextSibiling() const
472 {
473 if (!m_pParentListAnchor)
474 return NULL;
475 return RTListGetNextCpp(m_pParentListAnchor, this, const Node, m_listEntry);
476 }
477 /** @} */
478
479protected:
480 /** Node types. */
481 typedef enum { IsElement, IsAttribute, IsContent } EnumType;
482
483 /** The type of node this is an instance of. */
484 EnumType m_Type;
485 /** The parent node (always an element), NULL if root. */
486 Node *m_pParent;
487
488 xmlNode *m_pLibNode; ///< != NULL if this is an element or content node
489 xmlAttr *m_pLibAttr; ///< != NULL if this is an attribute node
490 const char *m_pcszNamespacePrefix; ///< not always set
491 const char *m_pcszNamespaceHref; ///< full http:// spec
492 const char *m_pcszName; ///< element or attribute name, points either into pLibNode or pLibAttr;
493 ///< NULL if this is a content node
494
495 /** Child list entry of this node. (List head m_pParent->m_children.) */
496 RTLISTNODE m_listEntry;
497 /** Pointer to the parent list anchor.
498 * This allows us to use m_listEntry both for children and attributes. */
499 PRTLISTANCHOR m_pParentListAnchor;
500
501 // hide the default constructor so people use only our factory methods
502 Node(EnumType type,
503 Node *pParent,
504 PRTLISTANCHOR pListAnchor,
505 xmlNode *pLibNode,
506 xmlAttr *pLibAttr);
507 Node(const Node &x); // no copying
508
509 friend class AttributeNode;
510 friend class ElementNode; /* C list hack. */
511};
512
513/**
514 * Node subclass that represents an attribute of an element.
515 *
516 * For attributes, Node::getName() returns the attribute name, and Node::getValue()
517 * returns the attribute value, if any.
518 *
519 * Since the Node constructor is private, one can create new attribute nodes
520 * only through the following factory methods:
521 *
522 * -- ElementNode::setAttribute()
523 */
524class RT_DECL_CLASS AttributeNode : public Node
525{
526public:
527
528protected:
529 // hide the default constructor so people use only our factory methods
530 AttributeNode(const ElementNode *pElmRoot,
531 Node *pParent,
532 PRTLISTANCHOR pListAnchor,
533 xmlAttr *pLibAttr);
534 AttributeNode(const AttributeNode &x); // no copying
535
536 friend class Node;
537 friend class ElementNode;
538};
539
540/**
541 * Node subclass that represents an element.
542 *
543 * For elements, Node::getName() returns the element name, and Node::getValue()
544 * returns the text contents, if any.
545 *
546 * Since the Node constructor is private, one can create element nodes
547 * only through the following factory methods:
548 *
549 * -- Document::createRootElement()
550 * -- ElementNode::createChild()
551 */
552class RT_DECL_CLASS ElementNode : public Node
553{
554public:
555 int getChildElements(ElementNodesList &children, const char *pcszMatch = NULL) const;
556
557 const ElementNode *findChildElementNS(const char *pcszNamespace, const char *pcszMatch) const;
558 const ElementNode *findChildElement(const char *pcszMatch) const
559 {
560 return findChildElementNS(NULL, pcszMatch);
561 }
562 const ElementNode *findChildElementFromId(const char *pcszId) const;
563
564 /** Finds the first decendant matching the name at the end of @a pcszPath and
565 * optionally namespace.
566 *
567 * @returns Pointer to the child string value, NULL if not found or no value.
568 * @param pcszPath The attribute name. Slashes can be used to make a
569 * simple path to any decendant.
570 * @param pcszNamespace The namespace to match, NULL (default) match any
571 * namespace. When using a path, this matches all
572 * elements along the way.
573 * @see findChildElement, findChildElementP
574 */
575 const ElementNode *findChildElementP(const char *pcszPath, const char *pcszNamespace = NULL) const;
576
577 /** Finds the first child with matching the give name and optionally namspace,
578 * returning its value.
579 *
580 * @returns Pointer to the child string value, NULL if not found or no value.
581 * @param pcszPath The attribute name. Slashes can be used to make a
582 * simple path to any decendant.
583 * @param pcszNamespace The namespace to match, NULL (default) match any
584 * namespace. When using a path, this matches all
585 * elements along the way.
586 * @see findChildElement, findChildElementP
587 */
588 const char *findChildElementValueP(const char *pcszPath, const char *pcszNamespace = NULL) const
589 {
590 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
591 if (pElem)
592 return pElem->getValue();
593 return NULL;
594 }
595
596 /** Combines findChildElementP and findAttributeValue.
597 *
598 * @returns Pointer to attribute string value, NULL if either the element or
599 * the attribute was not found.
600 * @param pcszPath The attribute name. Slashes can be used to make a
601 * simple path to any decendant.
602 * @param pcszAttribute The attribute name.
603 * @param pcszPathNamespace The namespace to match @pcszPath with, NULL
604 * (default) match any namespace. When using a
605 * path, this matches all elements along the way.
606 * @param pcszAttribNamespace The namespace prefix to apply to the attribute,
607 * NULL (default) match any namespace.
608 * @see findChildElementP and findAttributeValue
609 */
610 const char *findChildElementAttributeValueP(const char *pcszPath, const char *pcszAttribute,
611 const char *pcszPathNamespace = NULL,
612 const char *pcszAttributeNamespace = NULL) const
613 {
614 const ElementNode *pElem = findChildElementP(pcszPath, pcszPathNamespace);
615 if (pElem)
616 return pElem->findAttributeValue(pcszAttribute, pcszAttributeNamespace);
617 return NULL;
618 }
619
620
621 /** @name Tree enumeration.
622 * @{ */
623
624 /** Get the next tree element in a full tree enumeration.
625 *
626 * By starting with the root node, this can be used to enumerate the entire tree
627 * (or sub-tree if @a pElmRoot is used).
628 *
629 * @returns Pointer to the next element in the tree, NULL if we're done.
630 * @param pElmRoot The root of the tree we're enumerating. NULL if
631 * it's the entire tree.
632 */
633 ElementNode const *getNextTreeElement(ElementNode const *pElmRoot = NULL) const;
634 RT_CPP_GETTER_UNCONST_RET(ElementNode *, ElementNode, getNextTreeElement, (const ElementNode *pElmRoot = NULL), (pElmRoot))
635
636 /** Get the first child node.
637 * @returns Pointer to the first child node, NULL if no children. */
638 const Node *getFirstChild() const
639 {
640 return RTListGetFirstCpp(&m_children, const Node, m_listEntry);
641 }
642 RT_CPP_GETTER_UNCONST_RET(Node *, ElementNode, getFirstChild,(),())
643
644 /** Get the last child node.
645 * @returns Pointer to the last child node, NULL if no children. */
646 const Node *getLastChild() const
647 {
648 return RTListGetLastCpp(&m_children, const Node, m_listEntry);
649 }
650
651 /** Get the first child node.
652 * @returns Pointer to the first child node, NULL if no children. */
653 const ElementNode *getFirstChildElement() const;
654
655 /** Get the last child node.
656 * @returns Pointer to the last child node, NULL if no children. */
657 const ElementNode *getLastChildElement() const;
658
659 /** Get the previous sibling element.
660 * @returns Pointer to the previous sibling element, NULL if first child
661 * element.
662 * @see getNextSibilingElement, getPrevSibling
663 */
664 const ElementNode *getPrevSibilingElement() const;
665
666 /** Get the next sibling element.
667 * @returns Pointer to the next sibling element, NULL if last child element.
668 * @see getPrevSibilingElement, getNextSibling
669 */
670 const ElementNode *getNextSibilingElement() const;
671
672 /** Find the previous element matching the given name and namespace (optionally).
673 * @returns Pointer to the previous sibling element, NULL if first child
674 * element.
675 * @param pcszName The element name to match.
676 * @param pcszNamespace The namespace name, default is NULL which means
677 * anything goes.
678 * @note Changed the order of the arguments.
679 */
680 const ElementNode *findPrevSibilingElement(const char *pcszName, const char *pcszNamespace = NULL) const;
681
682 /** Find the next element matching the given name and namespace (optionally).
683 * @returns Pointer to the previous sibling element, NULL if first child
684 * element.
685 * @param pcszName The element name to match.
686 * @param pcszNamespace The namespace name, default is NULL which means
687 * anything goes.
688 * @note Changed the order of the arguments.
689 */
690 const ElementNode *findNextSibilingElement(const char *pcszName, const char *pcszNamespace = NULL) const;
691 /** @} */
692
693
694 const AttributeNode *findAttribute(const char *pcszMatch, const char *pcszNamespace = NULL) const;
695 /** Find the first attribute with the given name, returning its value string.
696 * @returns Pointer to the attribute string value.
697 * @param pcszName The attribute name.
698 * @param pcszNamespace The namespace name, default is NULL which means
699 * anything goes.
700 * @see getAttributeValue
701 */
702 const char *findAttributeValue(const char *pcszName, const char *pcszNamespace = NULL) const
703 {
704 const AttributeNode *pAttr = findAttribute(pcszName, pcszNamespace);
705 if (pAttr)
706 return pAttr->getValue();
707 return NULL;
708 }
709
710 bool getAttributeValue(const char *pcszMatch, const char *&pcsz, const char *pcszNamespace = NULL) const
711 { return getAttributeValue(pcszMatch, &pcsz, pcszNamespace); }
712 bool getAttributeValue(const char *pcszMatch, RTCString &str, const char *pcszNamespace = NULL) const
713 { return getAttributeValue(pcszMatch, &str, pcszNamespace); }
714 bool getAttributeValuePath(const char *pcszMatch, RTCString &str, const char *pcszNamespace = NULL) const
715 { return getAttributeValue(pcszMatch, &str, pcszNamespace); }
716 bool getAttributeValue(const char *pcszMatch, int32_t &i, const char *pcszNamespace = NULL) const
717 { return getAttributeValue(pcszMatch, &i, pcszNamespace); }
718 bool getAttributeValue(const char *pcszMatch, uint32_t &i, const char *pcszNamespace = NULL) const
719 { return getAttributeValue(pcszMatch, &i, pcszNamespace); }
720 bool getAttributeValue(const char *pcszMatch, int64_t &i, const char *pcszNamespace = NULL) const
721 { return getAttributeValue(pcszMatch, &i, pcszNamespace); }
722 bool getAttributeValue(const char *pcszMatch, uint64_t &u, const char *pcszNamespace = NULL) const
723 { return getAttributeValue(pcszMatch, &u, pcszNamespace); }
724 bool getAttributeValue(const char *pcszMatch, bool &f, const char *pcszNamespace = NULL) const
725 { return getAttributeValue(pcszMatch, &f, pcszNamespace); }
726
727 /** @name Variants that for clarity does not use references for output params.
728 * @{ */
729 bool getAttributeValue(const char *pcszMatch, const char **ppcsz, const char *pcszNamespace = NULL) const;
730 bool getAttributeValue(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace = NULL) const;
731 bool getAttributeValuePath(const char *pcszMatch, RTCString *pStr, const char *pcszNamespace = NULL) const;
732 bool getAttributeValue(const char *pcszMatch, int32_t *pi, const char *pcszNamespace = NULL) const;
733 bool getAttributeValue(const char *pcszMatch, uint32_t *pu, const char *pcszNamespace = NULL) const;
734 bool getAttributeValue(const char *pcszMatch, int64_t *piValue, const char *pcszNamespace = NULL) const;
735 bool getAttributeValue(const char *pcszMatch, uint64_t *pu, const char *pcszNamespace = NULL) const;
736 bool getAttributeValue(const char *pcszMatch, bool *pf, const char *pcszNamespace = NULL) const;
737 /** @} */
738
739 /** @name Convenience methods for convering the element value.
740 * @{ */
741 bool getElementValue(int32_t *piValue) const;
742 bool getElementValue(uint32_t *puValue) const;
743 bool getElementValue(int64_t *piValue) const;
744 bool getElementValue(uint64_t *puValue) const;
745 bool getElementValue(bool *pfValue) const;
746 /** @} */
747
748 /** @name Convenience findChildElementAttributeValueP and getElementValue.
749 * @{ */
750 bool getChildElementValueP(const char *pcszPath, int32_t *piValue, const char *pcszNamespace = NULL) const
751 {
752 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
753 return pElem && pElem->getElementValue(piValue);
754 }
755 bool getChildElementValueP(const char *pcszPath, uint32_t *puValue, const char *pcszNamespace = NULL) const
756 {
757 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
758 return pElem && pElem->getElementValue(puValue);
759 }
760 bool getChildElementValueP(const char *pcszPath, int64_t *piValue, const char *pcszNamespace = NULL) const
761 {
762 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
763 return pElem && pElem->getElementValue(piValue);
764 }
765 bool getChildElementValueP(const char *pcszPath, uint64_t *puValue, const char *pcszNamespace = NULL) const
766 {
767 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
768 return pElem && pElem->getElementValue(puValue);
769 }
770 bool getChildElementValueP(const char *pcszPath, bool *pfValue, const char *pcszNamespace = NULL) const
771 {
772 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
773 return pElem && pElem->getElementValue(pfValue);
774 }
775
776 /** @} */
777
778 /** @name Convenience findChildElementAttributeValueP and getElementValue with a
779 * default value being return if the child element isn't present.
780 *
781 * @remarks These will return false on conversion errors.
782 * @{ */
783 bool getChildElementValueDefP(const char *pcszPath, int32_t iDefault, int32_t *piValue, const char *pcszNamespace = NULL) const
784 {
785 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
786 if (pElem)
787 return pElem->getElementValue(piValue);
788 *piValue = iDefault;
789 return true;
790 }
791 bool getChildElementValueDefP(const char *pcszPath, uint32_t uDefault, uint32_t *puValue, const char *pcszNamespace = NULL) const
792 {
793 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
794 if (pElem)
795 return pElem->getElementValue(puValue);
796 *puValue = uDefault;
797 return true;
798 }
799 bool getChildElementValueDefP(const char *pcszPath, int64_t iDefault, int64_t *piValue, const char *pcszNamespace = NULL) const
800 {
801 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
802 if (pElem)
803 return pElem->getElementValue(piValue);
804 *piValue = iDefault;
805 return true;
806 }
807 bool getChildElementValueDefP(const char *pcszPath, uint64_t uDefault, uint64_t *puValue, const char *pcszNamespace = NULL) const
808 {
809 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
810 if (pElem)
811 return pElem->getElementValue(puValue);
812 *puValue = uDefault;
813 return true;
814 }
815 bool getChildElementValueDefP(const char *pcszPath, bool fDefault, bool *pfValue, const char *pcszNamespace = NULL) const
816 {
817 const ElementNode *pElem = findChildElementP(pcszPath, pcszNamespace);
818 if (pElem)
819 return pElem->getElementValue(pfValue);
820 *pfValue = fDefault;
821 return true;
822 }
823 /** @} */
824
825 ElementNode *createChild(const char *pcszElementName);
826
827 ContentNode *addContent(const char *pcszContent);
828 ContentNode *addContent(const RTCString &strContent)
829 {
830 return addContent(strContent.c_str());
831 }
832
833 AttributeNode *setAttribute(const char *pcszName, const char *pcszValue);
834 AttributeNode *setAttribute(const char *pcszName, const RTCString &strValue)
835 {
836 return setAttribute(pcszName, strValue.c_str());
837 }
838 AttributeNode *setAttributePath(const char *pcszName, const RTCString &strValue);
839 AttributeNode *setAttribute(const char *pcszName, int32_t i);
840 AttributeNode *setAttribute(const char *pcszName, uint32_t i);
841 AttributeNode *setAttribute(const char *pcszName, int64_t i);
842 AttributeNode *setAttribute(const char *pcszName, uint64_t i);
843 AttributeNode *setAttributeHex(const char *pcszName, uint32_t i);
844 AttributeNode *setAttribute(const char *pcszName, bool f);
845
846 virtual ~ElementNode();
847
848protected:
849 // hide the default constructor so people use only our factory methods
850 ElementNode(const ElementNode *pElmRoot, Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode);
851 ElementNode(const ElementNode &x); // no copying
852
853 /** We keep a pointer to the root element for attribute namespace handling. */
854 const ElementNode *m_pElmRoot;
855
856 /** List of child elements and content nodes. */
857 RTLISTANCHOR m_children;
858 /** List of attributes nodes. */
859 RTLISTANCHOR m_attributes;
860
861 static void buildChildren(ElementNode *pElmRoot);
862
863 friend class Node;
864 friend class Document;
865 friend class XmlFileParser;
866};
867
868/**
869 * Node subclass that represents content (non-element text).
870 *
871 * Since the Node constructor is private, one can create new content nodes
872 * only through the following factory methods:
873 *
874 * -- ElementNode::addContent()
875 */
876class RT_DECL_CLASS ContentNode : public Node
877{
878public:
879
880protected:
881 // hide the default constructor so people use only our factory methods
882 ContentNode(Node *pParent, PRTLISTANCHOR pListAnchor, xmlNode *pLibNode);
883 ContentNode(const ContentNode &x); // no copying
884
885 friend class Node;
886 friend class ElementNode;
887};
888
889
890/**
891 * Handy helper class with which one can loop through all or some children
892 * of a particular element. See NodesLoop::forAllNodes() for details.
893 */
894class RT_DECL_CLASS NodesLoop
895{
896public:
897 NodesLoop(const ElementNode &node, const char *pcszMatch = NULL);
898 ~NodesLoop();
899 const ElementNode* forAllNodes() const;
900
901private:
902 /* Obscure class data */
903 struct Data;
904 Data *m;
905};
906
907/**
908 * The XML document class. An instance of this needs to be created by a user
909 * of the XML classes and then passed to
910 *
911 * -- XmlMemParser or XmlFileParser to read an XML document; those classes then
912 * fill the caller's Document with ElementNode, ContentNode and AttributeNode
913 * instances. The typical sequence then is:
914 * @code
915 Document doc;
916 XmlFileParser parser;
917 parser.read("file.xml", doc);
918 Element *pElmRoot = doc.getRootElement();
919 @endcode
920 *
921 * -- XmlMemWriter or XmlFileWriter to write out an XML document after it has
922 * been created and filled. Example:
923 *
924 * @code
925 Document doc;
926 Element *pElmRoot = doc.createRootElement();
927 // add children
928 xml::XmlFileWriter writer(doc);
929 writer.write("file.xml", true);
930 @endcode
931 */
932class RT_DECL_CLASS Document
933{
934public:
935 Document();
936 ~Document();
937
938 Document(const Document &x);
939 Document& operator=(const Document &x);
940
941 const ElementNode* getRootElement() const;
942 ElementNode* getRootElement();
943
944 ElementNode* createRootElement(const char *pcszRootElementName,
945 const char *pcszComment = NULL);
946
947private:
948 friend class XmlMemParser;
949 friend class XmlFileParser;
950 friend class XmlMemWriter;
951 friend class XmlFileWriter;
952
953 void refreshInternals();
954
955 /* Obscure class data */
956 struct Data;
957 Data *m;
958};
959
960/*
961 * XmlParserBase
962 *
963 */
964
965class RT_DECL_CLASS XmlParserBase
966{
967protected:
968 XmlParserBase();
969 ~XmlParserBase();
970
971 xmlParserCtxtPtr m_ctxt;
972};
973
974/*
975 * XmlMemParser
976 *
977 */
978
979class RT_DECL_CLASS XmlMemParser : public XmlParserBase
980{
981public:
982 XmlMemParser();
983 ~XmlMemParser();
984
985 void read(const void* pvBuf, size_t cbSize, const RTCString &strFilename, Document &doc);
986};
987
988/*
989 * XmlFileParser
990 *
991 */
992
993class RT_DECL_CLASS XmlFileParser : public XmlParserBase
994{
995public:
996 XmlFileParser();
997 ~XmlFileParser();
998
999 void read(const RTCString &strFilename, Document &doc);
1000
1001private:
1002 /* Obscure class data */
1003 struct Data;
1004 struct Data *m;
1005
1006 static int ReadCallback(void *aCtxt, char *aBuf, int aLen);
1007 static int CloseCallback (void *aCtxt);
1008};
1009
1010/*
1011 * XmlMemParser
1012 *
1013 */
1014
1015class RT_DECL_CLASS XmlMemWriter
1016{
1017public:
1018 XmlMemWriter();
1019 ~XmlMemWriter();
1020
1021 void write(const Document &doc, void** ppvBuf, size_t *pcbSize);
1022
1023private:
1024 void* m_pBuf;
1025};
1026
1027/*
1028 * XmlFileWriter
1029 *
1030 */
1031
1032class RT_DECL_CLASS XmlFileWriter
1033{
1034public:
1035 XmlFileWriter(Document &doc);
1036 ~XmlFileWriter();
1037
1038 /**
1039 * Writes the XML document to the specified file.
1040 *
1041 * @param pcszFilename The name of the output file.
1042 * @param fSafe If @c true, some extra safety precautions will be
1043 * taken when writing the file:
1044 * -# The file is written with a '-tmp' suffix.
1045 * -# It is flushed to disk after writing.
1046 * -# Any original file is renamed to '-prev'.
1047 * -# The '-tmp' file is then renamed to the
1048 * specified name.
1049 * -# The directory changes are flushed to disk.
1050 * The suffixes are available via s_pszTmpSuff and
1051 * s_pszPrevSuff.
1052 */
1053 void write(const char *pcszFilename, bool fSafe);
1054
1055 static int WriteCallback(void *aCtxt, const char *aBuf, int aLen);
1056 static int CloseCallback(void *aCtxt);
1057
1058 /** The suffix used by XmlFileWriter::write() for the temporary file. */
1059 static const char * const s_pszTmpSuff;
1060 /** The suffix used by XmlFileWriter::write() for the previous (backup) file. */
1061 static const char * const s_pszPrevSuff;
1062
1063private:
1064 void writeInternal(const char *pcszFilename, bool fSafe);
1065
1066 /* Obscure class data */
1067 struct Data;
1068 Data *m;
1069};
1070
1071#if defined(_MSC_VER)
1072#pragma warning (default:4251)
1073#endif
1074
1075/** @} */
1076
1077} // end namespace xml
1078
1079#endif /* !___iprt_xml_h */
1080
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette