BDE 4.39.x Production Release
Loading...
Searching...
No Matches
balxml_minireader.h
Go to the documentation of this file.
1/// @file balxml_minireader.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balxml_minireader.h -*-C++-*-
8#ifndef INCLUDED_BALXML_MINIREADER
9#define INCLUDED_BALXML_MINIREADER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balxml_minireader balxml_minireader
15/// @brief Provide light-weight implementation of `balxml::Reader` protocol.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balxml
19/// @{
20/// @addtogroup balxml_minireader
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balxml_minireader-purpose"> Purpose</a>
25/// * <a href="#balxml_minireader-classes"> Classes </a>
26/// * <a href="#balxml_minireader-description"> Description </a>
27/// * <a href="#balxml_minireader-usage"> Usage </a>
28/// * <a href="#balxml_minireader-example-1-basic-usage"> Example 1: Basic Usage </a>
29///
30/// # Purpose {#balxml_minireader-purpose}
31/// Provide light-weight implementation of `balxml::Reader` protocol.
32///
33/// # Classes {#balxml_minireader-classes}
34///
35/// - balxml::MiniReader: light-weight `balxml::Reader` implementation
36///
37/// @see balxml_reader, balxml_errorinfo
38///
39/// # Description {#balxml_minireader-description}
40/// The `balxml::MiniReader` class is a light-weight
41/// implementation of `balxml::Reader` interface. The API acts as a currentNode
42/// going forward on the document stream and stopping at each node in the way.
43/// The current node refers to the node on which the reader is positioned. The
44/// user's code keeps control of the progress and simply calls a `read`
45/// function repeatedly to progress to each node in sequence in document order.
46/// This provides a far more standard, easy to use and powerful API than the
47/// existing SAX.
48///
49/// Data Validation
50/// - - - - - - - -
51/// The `balxml::MiniReader` `class` is not a validating reader
52/// (`balxml::ValidatingReader`). As a result while parsing data it does not
53/// make an attempt to ensure the correctness of either the data or the
54/// structure of the incoming XML. The `class` accepts characters as element
55/// data that the XML standard considers invalid. For example the `&` and `<`
56/// characters in element data will parse without error. Similarly, it does not
57/// return an error if the read data does not conform to its specified schema.
58/// To get stricter data validation, clients should use a concrete
59/// implementation of a validating reader (such as `a_xercesc::Reader`) instead.
60///
61/// ## Usage {#balxml_minireader-usage}
62///
63///
64/// This section illustrates intended use of this component.
65///
66/// ### Example 1: Basic Usage {#balxml_minireader-example-1-basic-usage}
67///
68///
69/// For this example, we will use `balxml::MiniReader` to read each node in an
70/// XML document. We do not care about whitespace, so we use the following
71/// utility function to skip over any whitespace nodes. This makes our example
72/// more portable to other implementations of the `balxml::Reader` protocol that
73/// handle whitespace differently from `balxml::MiniReader`.
74/// @code
75/// int advancePastWhiteSpace(balxml::Reader& reader) {
76/// const char *whiteSpace = "\n\r\t ";
77/// const char *value = '\0';
78/// int type = 0;
79/// int rc = 0;
80///
81/// do {
82/// rc = reader.advanceToNextNode();
83/// value = reader.nodeValue();
84/// type = reader.nodeType();
85/// } while(0 == rc &&
86/// type == balxml::Reader::e_NODE_TYPE_WHITESPACE ||
87/// (type == balxml::Reader::e_NODE_TYPE_TEXT &&
88/// bsl::strlen(value) == bsl::strspn(value, whiteSpace)));
89///
90/// assert( reader.nodeType() !=
91/// balxml::Reader::e_NODE_TYPE_WHITESPACE);
92///
93/// return rc;
94/// }
95/// @endcode
96/// The main program parses an XML string using the TestReader
97/// @code
98/// int main()
99/// {
100/// @endcode
101/// The following string describes xml for a very simple user directory. The
102/// top level element contains one xml namespace attribute, with one embedded
103/// entry describing a user.
104/// @code
105/// const char TEST_XML_STRING[] =
106/// "<?xml version='1.0' encoding='UTF-8'?>\n"
107/// "<directory-entry xmlns:dir="
108/// "'http://bloomberg.com/schemas/directory'>\n"
109/// " <name>John Smith</name>\n"
110/// " <phone dir:phonetype='cell'>212-318-2000</phone>\n"
111/// " <address/>\n"
112/// "</directory-entry>\n";
113/// @endcode
114/// In order to read the XML, we first need to construct a
115/// `balxml::NamespaceRegistry` object, a `balxml::PrefixStack` object, and a
116/// `TestReader` object, where `TestReader` is a derived implementation of
117/// @ref balxml_reader .
118/// @code
119/// balxml::NamespaceRegistry namespaces;
120/// balxml::PrefixStack prefixStack(&namespaces);
121/// balxml::MiniReader miniReader; balxml::Reader& reader = miniReader;
122///
123/// assert(!reader.isOpen());
124/// @endcode
125/// The reader uses a `balxml::PrefixStack` to manage namespace prefixes so we
126/// need to set it before we call open.
127/// @code
128/// reader.setPrefixStack(&prefixStack);
129/// assert(reader.prefixStack());
130/// assert(reader.prefixStack() == &prefixStack);
131/// @endcode
132/// Now we call the `open` method to setup the reader for parsing using the data
133/// contained in the in the XML string.
134/// @code
135/// reader.open(TEST_XML_STRING, sizeof(TEST_XML_STRING) -1, 0, "UTF-8");
136/// @endcode
137/// Confirm that the `bdem::Reader` has opened properly
138/// @code
139/// assert( reader.isOpen());
140/// assert(!bsl::strncmp(reader.documentEncoding(), "UTF-8", 5));
141/// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_NONE);
142/// assert(!reader.nodeName());
143/// assert(!reader.nodeHasValue());
144/// assert(!reader.nodeValue());
145/// assert(!reader.nodeDepth());
146/// assert(!reader.numAttributes());
147/// assert(!reader.isEmptyElement());
148/// @endcode
149/// Advance through all the nodes and assert all information contained at each
150/// node is correct.
151///
152/// Assert the next node's document type is xml.
153/// @code
154/// int rc = advancePastWhiteSpace(reader);
155/// assert( 0 == rc);
156/// assert( reader.nodeType() ==
157/// balxml::Reader::e_NODE_TYPE_XML_DECLARATION);
158/// assert(!bsl::strcmp(reader.nodeName(), "xml"));
159/// assert( reader.nodeHasValue());
160/// assert(!bsl::strcmp(reader.nodeValue(),
161/// "version='1.0' encoding='UTF-8'"));
162/// assert( reader.nodeDepth() == 1);
163/// assert(!reader.numAttributes());
164/// assert(!reader.isEmptyElement());
165/// assert( 0 == rc);
166/// assert( reader.nodeDepth() == 1);
167/// @endcode
168/// Advance to the top level element, which has one attribute, the xml
169/// namespace. Assert the namespace information has been added correctly to the
170/// prefix stack.
171/// @code
172/// rc = advancePastWhiteSpace(reader);
173/// assert( 0 == rc);
174/// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_ELEMENT);
175/// assert(!bsl::strcmp(reader.nodeName(), "directory-entry"));
176/// assert(!reader.nodeHasValue());
177/// assert( reader.nodeDepth() == 1);
178/// assert( reader.numAttributes() == 1);
179/// assert(!reader.isEmptyElement());
180///
181/// assert(!bsl::strcmp(prefixStack.lookupNamespacePrefix("dir"), "dir"));
182/// assert(prefixStack.lookupNamespaceId("dir") == 0);
183/// assert(!bsl::strcmp(prefixStack.lookupNamespaceUri("dir"),
184/// "http://bloomberg.com/schemas/directory"));
185/// @endcode
186/// The XML being read contains one entry describing a user, advance the users
187/// name name and assert all information can be read correctly.
188/// @code
189/// rc = advancePastWhiteSpace(reader);
190/// assert( 0 == rc);
191/// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_ELEMENT);
192/// assert(!bsl::strcmp(reader.nodeName(), "name"));
193/// assert(!reader.nodeHasValue());
194/// assert( reader.nodeDepth() == 2);
195/// assert( reader.numAttributes() == 0);
196/// assert(!reader.isEmptyElement());
197///
198/// rc = reader.advanceToNextNode();
199/// assert( 0 == rc);
200/// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_TEXT);
201/// assert( reader.nodeHasValue());
202/// assert(!bsl::strcmp(reader.nodeValue(), "John Smith"));
203/// assert( reader.nodeDepth() == 3);
204/// assert( reader.numAttributes() == 0);
205/// assert(!reader.isEmptyElement());
206///
207/// rc = reader.advanceToNextNode();
208/// assert( 0 == rc);
209/// assert( reader.nodeType() ==
210/// balxml::Reader::e_NODE_TYPE_END_ELEMENT);
211/// assert(!bsl::strcmp(reader.nodeName(), "name"));
212/// assert(!reader.nodeHasValue());
213/// assert( reader.nodeDepth() == 2);
214/// assert( reader.numAttributes() == 0);
215/// assert(!reader.isEmptyElement());
216/// @endcode
217/// Advance to the user's phone number and assert all information can be read
218/// correctly.
219/// @code
220/// rc = advancePastWhiteSpace(reader);
221/// assert( 0 == rc);
222/// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_ELEMENT);
223/// assert(!bsl::strcmp(reader.nodeName(), "phone"));
224/// assert(!reader.nodeHasValue());
225/// assert( reader.nodeDepth() == 2);
226/// assert( reader.numAttributes() == 1);
227/// assert(!reader.isEmptyElement());
228/// @endcode
229/// The phone node has one attribute, look it up and assert the
230/// `balxml::ElementAttribute` contains valid information and that the prefix
231/// returns the correct namespace URI from the prefix stack.
232/// @code
233/// balxml::ElementAttribute elemAttr;
234///
235/// rc = reader.lookupAttribute(&elemAttr, 0);
236/// assert( 0 == rc);
237/// assert(!elemAttr.isNull());
238/// assert(!bsl::strcmp(elemAttr.qualifiedName(), "dir:phonetype"));
239/// assert(!bsl::strcmp(elemAttr.value(), "cell"));
240/// assert(!bsl::strcmp(elemAttr.prefix(), "dir"));
241/// assert(!bsl::strcmp(elemAttr.localName(), "phonetype"));
242/// assert(!bsl::strcmp(elemAttr.namespaceUri(),
243/// "http://bloomberg.com/schemas/directory"));
244/// assert( elemAttr.namespaceId() == 0);
245///
246/// assert(!bsl::strcmp(prefixStack.lookupNamespaceUri(elemAttr.prefix()),
247/// elemAttr.namespaceUri()));
248///
249/// rc = advancePastWhiteSpace(reader);
250/// assert( 0 == rc);
251/// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_TEXT);
252/// assert( reader.nodeHasValue());
253/// assert(!bsl::strcmp(reader.nodeValue(), "212-318-2000"));
254/// assert( reader.nodeDepth() == 3);
255/// assert( reader.numAttributes() == 0);
256/// assert(!reader.isEmptyElement());
257///
258/// rc = advancePastWhiteSpace(reader);
259/// assert( 0 == rc);
260/// assert( reader.nodeType() ==
261/// balxml::Reader::e_NODE_TYPE_END_ELEMENT);
262/// assert(!bsl::strcmp(reader.nodeName(), "phone"));
263/// assert(!reader.nodeHasValue());
264/// assert( reader.nodeDepth() == 2);
265/// assert( reader.numAttributes() == 0);
266/// assert(!reader.isEmptyElement());
267/// @endcode
268/// Advance to the user's address and assert all information can be read
269/// correctly.
270/// @code
271/// rc = advancePastWhiteSpace(reader);
272/// assert( 0 == rc);
273/// assert( reader.nodeType() == balxml::Reader::e_NODE_TYPE_ELEMENT);
274/// assert(!bsl::strcmp(reader.nodeName(), "address"));
275/// assert(!reader.nodeHasValue());
276/// assert( reader.nodeDepth() == 2);
277/// assert( reader.numAttributes() == 0);
278/// assert( reader.isEmptyElement());
279/// @endcode
280/// Advance to the end element.
281/// @code
282/// rc = advancePastWhiteSpace(reader);
283/// assert( 0 == rc);
284/// assert( reader.nodeType() ==
285/// balxml::Reader::e_NODE_TYPE_END_ELEMENT);
286/// assert(!bsl::strcmp(reader.nodeName(), "directory-entry"));
287/// assert(!reader.nodeHasValue());
288/// assert( reader.nodeDepth() == 1);
289/// assert( reader.numAttributes() == 0);
290/// assert(!reader.isEmptyElement());
291/// @endcode
292/// Close the reader.
293/// @code
294/// reader.close();
295/// assert(!reader.isOpen());
296///
297/// return 0;
298/// }
299/// @endcode
300/// @}
301/** @} */
302/** @} */
303
304/** @addtogroup bal
305 * @{
306 */
307/** @addtogroup balxml
308 * @{
309 */
310/** @addtogroup balxml_minireader
311 * @{
312 */
313
314#include <balscm_version.h>
315
316#include <balxml_reader.h>
319#include <balxml_prefixstack.h>
320
321#include <bslma_allocator.h>
322
323#include <bsls_keyword.h>
324
325#include <bsl_cstring.h>
326#include <bsl_cstddef.h>
327#include <bsl_cstdlib.h>
328#include <bsl_fstream.h>
329#include <bsl_string.h>
330#include <bsl_vector.h>
331
332
333namespace balxml {
334
335 // ================
336 // class MiniReader
337 // ================
338
339/// This `class` provides a concrete and efficient implementation of the
340/// `Reader` protocol.
341///
342/// See @ref balxml_minireader
343class MiniReader : public Reader {
344
345 private:
346 // PRIVATE TYPES
347 enum {
348 k_MIN_BUFSIZE = 1024, // MIN - 1 KB
349 k_MAX_BUFSIZE = 1024 * 128, // MAX - 128 KB
350 k_DEFAULT_BUFSIZE = 1024 * 8, // DEFAULT - 8 KB
351 k_DEFAULT_DEPTH = 20 // Average expected deep
352 }; // to minimize allocations
353
356
357 struct Node;
358 friend struct Node;
359 struct Node {
360 enum {
361 k_NODE_NO_FLAGS = 0x0000,
362 k_NODE_EMPTY = 0x0001
363 };
364
365 NodeType d_type;
366 const char *d_qualifiedName;
367 const char *d_prefix;
368 const char *d_localName;
369 const char *d_value;
370 int d_namespaceId;
371 const char *d_namespaceUri;
372 int d_flags;
373 AttributeVector d_attributes;
374 size_t d_attrCount;
375 size_t d_namespaceCount;
376 int d_startPos;
377 int d_endPos;
378
379 Node(bslma::Allocator *basicAllocator = 0);
380 Node(const Node& other, bslma::Allocator *basicAllocator = 0);
381
382 void reset();
383 void swap(Node& other);
384 void addAttribute(const Attribute& attr);
385 };
386
387 typedef bsl::pair<bsl::string, int> Element;
388
389 typedef bsl::vector<Element> ElementVector;
390
391 enum State {
392 ST_INITIAL, // Initial state after successful open
393 ST_TAG_BEGIN, // Current position - next symbol after '<'
394 ST_TAG_END, // Current position - next symbol after '>'
395 ST_EOF, // End of Data is reached successfully
396 ST_ERROR, // Parser error : prevents from further scanning
397 ST_CLOSED // close method has been called
398 };
399
400 enum Flags {
401 FLG_READ_EOF = 0x0001, // End of input data
402 FLG_ROOT_CLOSED = 0x0002 // Root closed
403 };
404
405 enum StringType {
406 // The return value of 'searchCommentCDataOrElementName', says what
407 // node the function has found.
408
409 e_STRINGTYPE_NONE,
410 e_STRINGTYPE_COMMENT,
411 e_STRINGTYPE_CDATA,
412 e_STRINGTYPE_START_ELEMENT,
413 e_STRINGTYPE_END_ELEMENT
414 };
415
416 private:
417 // PRIVATE DATA
418 bslma::Allocator *d_allocator;
419 State d_state;
420 int d_flags;
421 int d_readSize;
422 bsl::vector<char> d_parseBuf;
423 int d_streamOffset;
424
425 bsl::ifstream d_stream;
426 bsl::streambuf *d_streamBuf;
427 const char * d_memStream; // memory buffer to decode from
428 size_t d_memSize; // memory buffer size
429
430 char *d_startPtr;
431 char *d_endPtr;
432 char *d_scanPtr; // pointer used to traverse the
433 // input
434
435 char *d_markPtr; // pointer to the previous node
436 // value
437
438 char *d_attrNamePtr;
439 char *d_attrValPtr;
440
441 int d_lineNum; // current line number
442
443 int d_lineOffset; // offset at the beginning of
444 // current line
445
446 ErrorInfo d_errorInfo;
447 XmlResolverFunctor d_resolver;
448
449 NamespaceRegistry d_ownNamespaces;
450 PrefixStack d_ownPrefixes;
451 PrefixStack *d_prefixes;
452
453 Node d_currentNode;
454 size_t d_activeNodesCount; // active nodes count
455 ElementVector d_activeNodes; // active nodes stack
456
457 bsl::string d_baseURL;
458 bsl::string d_encoding;
459 bsl::string d_dummyStr;
460
461 unsigned int d_options; // option flags for the reader
462
463 private:
464 // NOT IMPLEMENTED
465 MiniReader(const MiniReader&); // = delete;
466 MiniReader& operator=(const MiniReader&); // = delete;
467
468 // PRIVATE MANIPULATORS
469 Node& currentNode();
470 const Node& currentNode() const;
471
472 int setError(ErrorInfo::Severity error, const bsl::string &msg);
473
474 int setParseError(const char *errText,
475 const char *startFragment,
476 const char *endFragment);
477
478 // HIGH LEVEL PARSING PRIMITIVES
479
480 void preAdvance();
481 const bsl::string& findNamespace(const char *prefix) const;
482 const bsl::string& findNamespace(const bsl::string &prefix) const;
483 int checkPrefixes();
484
485 /// Push the `currentNode()`s data onto the `d_activeNodes` stack.
486 void pushElementName();
487
488 /// Validate that if a BOM is present at the start of the document, it is
489 /// the UTF-8 BOM. If a valid or no BOM is present, adjust `d_scanPtr`,
490 /// `d_startPtr`, and `d_endPtr` accordingly. If an invalid BOM is
491 /// present, set the reader to the error state. Returns 0 on success, and
492 /// a non-zero value otherwise.
493 int bomCheck();
494
495 /// Scan the node at the current position.
496 int scanNode();
497 int updateAttributes();
498 int updateElementInfo();
499
500 int addAttribute();
501
502 int scanAttributes();
503
504 /// Scan an end element without updating the element info.
505 int scanEndElementRaw();
506
507 int scanEndElement();
508 int scanExclaimConstruct();
509 int scanOpenTag();
510 int scanProcessingInstruction();
511 int scanStartElement();
512 int scanText();
513
514 /// Scan the input for a comment, a CDATA section, the specified element
515 /// `name`, or the end tag corresponding to `name`. Stop at the first
516 /// instance of either one of those strings and update the internal read
517 /// pointer (d_scanPtr) to point to the next character after the string
518 /// read. Return the string type found.
519 StringType searchCommentCDataOrEndElementName(const bsl::string& name);
520
521 /// Scan the input for the specified element `name`, or the end tag
522 /// corresponding to `name`. Stop at the first instance and update the
523 /// internal read pointer (d_scanPtr) to point to the next character
524 /// after the string read. Return the string type found. Notice that
525 /// this method (unlike `searchCommentCDataOrElementName`) does not
526 /// return `e_STRINGTYPE_COMMENT` or `e_STRINGTYPE_CDATA`.
527 StringType searchElementName(const bsl::string& name);
528
529 // LOW LEVEL PARSING PRIMITIVES
530 const char *rebasePointer(const char *ptr, const char *newBase);
531 void rebasePointers(const char *newBase, size_t newLength);
532
533 int readInput();
534 int doOpen(const char *url, const char *encoding);
535
536 /// Return the character at the current position, and zero if the end of
537 /// stream was reached.
538 int peekChar();
539
540 /// Call `readInput` until there are at least the specified `number` of
541 /// characters in the buffer. Return zero if `number` characters cannot
542 /// be read, and return a positive value otherwise.
543 int readAtLeast(bsl::ptrdiff_t number);
544
545 /// Return the character at the current position and then advance the
546 /// current position. If the end of stream is reached the return value is zero.
547 ///
548 /// \pre The behavior is undefined if this method is called once
549 /// the end is reached.
550 int getChar();
551
552 /// Set the specified symbol `ch` at the current position. Return the
553 /// original character at the current position, and advance the current
554 /// position. If the end of stream is reached the return value is zero.
555 ///
556 /// \pre The behavior is undefined if this method is called once the end is
557 /// reached.
558 int getCharAndSet(char ch);
559
560 /// Check if the current symbol is NL and adjust line number
561 /// information. Return `true` if it was NL, otherwise `false`
562 bool checkForNewLine();
563
564 /// Skip spaces and set the current position to first non space
565 /// character or to end if there is no non space found symbol. Return
566 /// the character at the new current position.
567 int skipSpaces();
568
569 /// Scan for the specified `symbol` and set the current position to the
570 /// found symbol. Return the character at the new current position. If
571 /// the symbol is not found, the current position is set to end and
572 /// returned value is zero.
573 int scanForSymbol(char symbol);
574
575 /// Scan one of the specified `symbol`, `symbol1`, or `symbol2`
576 /// characters or any space character and set the current position to
577 /// the found symbol. Return the character at the new current position.
578 /// If there were no symbols found, the current position is set to end
579 /// and returned value is zero.
580 int scanForSymbolOrSpace(char symbol1, char symbol2);
581 int scanForSymbolOrSpace(char symbol);
582
583 /// Scan for the required string and set the current position to the
584 /// first character of the found string. Return the character at the
585 /// new current position. If there were no symbols found, the current
586 /// position is set to end and returned value is zero.
587 int scanForString(const char * str);
588
589 /// Compare the content of the buffer, starting from the current
590 /// position, with the specified string `str`. If matches, advance the
591 /// current position by the length of `str` and return `true`; otherwise
592 /// return `false` and the current position is unmodified.
593 bool skipIfMatch(const char *str);
594
595 public:
596 // PUBLIC CREATORS
598
599 /// Construct a reader with the optionally specified `bufSize`. The
600 /// instantiated MiniReader will utilize a memory buffer of `bufSize`
601 /// while reading the input document. Optionally specify a
602 /// `basicAllocator` used to supply memory. If `basicAllocator` is 0,
603 /// the currently installed default allocator is used.
604 ///
605 /// \note Note that `bufSize` is a hint, which may be modified or ignored if it is not
606 /// within a "sane" range.
607 explicit MiniReader(bslma::Allocator *basicAllocator = 0);
608 explicit MiniReader(int bufSize, bslma::Allocator *basicAllocator = 0);
609
610 //------------------------------------------------
611 // INTERFACE Reader
612 //------------------------------------------------
613
614 // MANIPULATORS - SETUP METHODS
615
616 /// Set the prefix stack to the stack at the specified `prefixes`
617 /// address or disable prefix stack support if `prefixes` == 0. This
618 /// stack is used to push and pop namespace prefixes as the parse
619 /// progresses, so that, at any point, the stack will reflect the set of
620 /// active prefixes for the current node. It is legitimate to pass a
621 /// stack that already contains prefixes, these prefixes shall be
622 /// preserved when `close` is called, i.e., the prefix stack shall be
623 /// returned to the stack depth it had when `setPrefixStack` was called.
624 ///
625 /// \pre The behavior is undefined if this method is called after calling
626 /// `open` and before calling `close`.
628
629 /// Set the external XML resource resolver to the specified `resolver`.
630 /// The XML resource resolver is used by the @ref balxml_reader to find and
631 /// open an external resources (See the `XmlResolverFunctor` typedef for
632 /// more details). The XML resource resolver remains valid; it is not
633 /// affected by a call to `close` and should be available until the reader is destroyed.
634 ///
635 /// \pre The behavior is undefined if this method is
636 /// called after calling `open` and before calling `close`.
638
639 // MANIPULATORS - OPEN/CLOSE AND NAVIGATION METHODS
640
641 /// Set up the reader for parsing using the data contained in the XML
642 /// file described by the specified `filename`, and set the encoding
643 /// value to the optionally specified `encoding` ("ASCII", "UTF-8",
644 /// etc). Returns 0 on success and non-zero otherwise. The encoding
645 /// passed to `Reader::open` will take effect only when there is no
646 /// encoding information in the original document, i.e., the encoding
647 /// information obtained from the XML file described by the `filename`
648 /// trumps all. If there is no encoding provided within the document
649 /// and `encoding` is null or a blank string is passed, then set the
650 /// encoding to the default "UTF-8". It is an error to `open` a reader that is already open.
651 ///
652 /// \note Note that the reader will not be on a valid
653 /// node until `advanceToNextNode` is called. Also note that if a Byte
654 /// Order Mark (BOM) is present at the start of the document, it must be
655 /// the UTF-8 BOM, or else an error will be returned.
656 int open(const char *filename,
657 const char *encoding = 0) BSLS_KEYWORD_OVERRIDE;
658
659 /// Set up the reader for parsing using the data contained in the
660 /// specified (XML) `buffer` of the specified `size`, set the base URL
661 /// to the optionally specified `url` and set the encoding value to the
662 /// optionally specified `encoding` ("ASCII", "UTF-8", etc). Return 0
663 /// on success and non-zero otherwise. If `url` is null 0 or a blank
664 /// string is passed, then base URL will be empty. The encoding passed
665 /// to `Reader::open` will take effect only when there is no encoding
666 /// information in the original document, i.e., the encoding information
667 /// obtained from the (XML) `buffer` trumps all. If there is no
668 /// encoding provided within the document and `encoding` is null or a
669 /// blank string is passed, then set the encoding to the default
670 /// "UTF-8". It is an error to `open` a reader that is already open.
671 ///
672 /// \note Note that the reader will not be on a valid node until
673 /// `advanceToNextNode` is called.
674 int open(const char *buffer,
675 bsl::size_t size,
676 const char *url = 0,
677 const char *encoding = 0) BSLS_KEYWORD_OVERRIDE;
678
679 /// Set up the reader for parsing using the data contained in the
680 /// specified (XML) `stream`, set the base URL to the optionally
681 /// specified `url` and set the encoding value to the optionally
682 /// specified `encoding` ("ASCII", "UTF-8", etc). Return 0 on success
683 /// and non-zero otherwise. If `url` is null or a blank string is
684 /// passed, then base URL will be empty. The encoding passed to
685 /// `Reader::open` will take effect only when there is no encoding
686 /// information in the original document, i.e., the encoding information
687 /// obtained from the (XML) `stream` trumps all. If there is no
688 /// encoding provided within the document and `encoding` is null or a
689 /// blank string is passed, then set the encoding to the default
690 /// "UTF-8". It is an error to `open` a reader that is already open.
691 ///
692 /// \note Note that the reader will not be on a valid node until
693 /// `advanceToNextNode` is called.
694 int open(bsl::streambuf *stream,
695 const char *url = 0,
696 const char *encoding = 0) BSLS_KEYWORD_OVERRIDE;
697
698 /// Close the reader. Most, but not all state is reset. Specifically,
699 /// the XML resource resolver and the prefix stack remain. The prefix
700 /// stack shall be returned to the stack depth it had when
701 /// `setPrefixStack` was called. Call the method `open` to reuse the reader.
702 ///
703 /// \note Note that `close` invalidates all strings and data
704 /// structures obtained via `Reader` accessors. E.g., the pointer
705 /// returned from `nodeName` for this node will not be valid once
706 /// `close` is called.
708
709 /// Skip all the sub elements of the current node and position the
710 /// reader on its corresponding end node. While skipping ensure that
711 /// the elements being skipped are well-formed and do not contain any
712 /// parsing errors. Return 0 on successful skip, and a negative number otherwise (error).
713 ///
714 /// \pre The behavior is undefined unless
715 /// `balxml::Reader::e_NODE_TYPE_ELEMENT == node.type()`.
716 ///
717 /// \note Note that each call to `advanceToEndNode` invalidates strings and data
718 /// structures returned when `Reader` accessors were called for the
719 /// "prior node". E.g., the pointer returned from `nodeName` for this
720 /// node won't be valid once `advanceToEndNode` is called.
721 ///
722 /// \note Note that this method leaves the reader pointing to an end node, so calling
723 /// one of the `advanceToEndNode` immediately after will not advance the
724 /// reader further (first call `advanceToNextNode` before calling the
725 /// `advanceToEndNode` function again).
726 virtual int advanceToEndNode();
727
728 /// Skip all the sub elements of the current node and position the
729 /// reader on its corresponding end node, and (unlike
730 /// `advanceToNextNode`) perform no checks to ensure that the elements
731 /// being skipped are well-formed and that they do not contain any
732 /// parsing errors. Return 0 on successful skip, and a negative number otherwise (error).
733 ///
734 /// \pre The behavior is undefined unless
735 /// `balxml::Reader::e_NODE_TYPE_ELEMENT == node.type()`.
736 ///
737 /// \note Note that each call to `advanceToEndNodeRaw` invalidates strings and data
738 /// structures returned when `Reader` accessors were called for the
739 /// "prior node". E.g., the pointer returned from `nodeName` for this
740 /// node will not be valid once `advanceToEndNodeRaw` is called.
741 ///
742 /// \note Note that this method leaves the reader pointing to an end node, so
743 /// calling one of the `advanceToEndNodeRaw` immediately after will not
744 /// advance the reader further (first call `advanceToNextNode` before
745 /// calling the `advanceToEndNodeRaw` function again).
746 virtual int advanceToEndNodeRaw();
747
748 /// Skip all the sub elements of the current node and position the
749 /// reader on its corresponding end node, and (unlike
750 /// `advanceToNextNode`) perform no checks to ensure that the elements
751 /// being skipped are well-formed and that they do not contain any
752 /// parsing errors. Unlike `advanceToEndNodeRaw` this method does not
753 /// expect (allow) comments or CDATA nodes in the input XML, in other
754 /// words it is expecting "bare" XML. Return 0 on successful skip, and
755 /// a negative number otherwise (error).
756 ///
757 /// \pre The behavior is undefined unless `balxml::Reader::e_NODE_TYPE_ELEMENT == node.type()`. The
758 /// behavior is also undefined if the input XML contains comment or CDATA nodes.
759 ///
760 /// \note Note that each call to `advanceToEndNodeRawBare`
761 /// invalidates strings and data structures returned when `Reader`
762 /// accessors were called for the "prior node". E.g., the pointer
763 /// returned from `nodeName` for this node will not be valid once `advanceToEndNodeRawBare` is called.
764 ///
765 /// \note Note that this method leaves
766 /// the reader pointing to an end node, so calling one of the
767 /// `advanceToEndNodeRawBare` immediately after will not advance the
768 /// reader further (first call `advanceToNextNode` before calling the
769 /// `advanceToEndNodeRawBare` function again).
771
772 /// Move to the next node in the data steam created by `open` thus
773 /// allowing the node's properties to be queried via the `Reader`
774 /// accessors. Return 0 on successful read, 1 if there are no more nodes to read, and a negative number otherwise.
775 ///
776 /// \note Note that each call
777 /// to `advanceToNextNode` invalidates strings and data structures
778 /// returned when `Reader` accessors were called for the "prior node".
779 /// E.g., the pointer returned from `nodeName` for this node will not be valid once `advanceToNextNode` is called.
780 ///
781 /// \note Note that the reader will
782 /// not be on a valid node until the first call to `advanceToNextNode`
783 /// after the reader is opened.
785
786 /// Find the attribute at the specified `index` in the current node, and
787 /// fill in the specified `attribute` structure. Return 0 on success, 1
788 /// if no attribute is found at the `index`, and an a negative value
789 /// otherwise. The strings that were filled into the `attribute`
790 /// structure are invalid upon the next `advanceToNextNode` or `close`
791 /// is called.
793 int index) const BSLS_KEYWORD_OVERRIDE;
794
795 /// Find the attribute with the specified `qname` (qualified name) in
796 /// the current node, and fill in the specified `attribute` structure.
797 /// Return 0 on success, 1 if there is no attribute found with `qname`,
798 /// and a negative value otherwise. The strings that were filled into
799 /// the `attribute` structure are invalid upon the next
800 /// `advanceToNextNode` or `close` is called.
802 const char *qname) const BSLS_KEYWORD_OVERRIDE;
803
804 /// Find the attribute with the specified `localName` and specified
805 /// `namespaceUri` in the current node, and fill in the specified
806 /// `attribute` structure. Return 0 on success, 1 if there is no
807 /// attribute found with `localName` and `namespaceUri`, and a negative
808 /// value otherwise. If `namespaceUri` == 0 or a blank string is
809 /// passed, then the document's default namespace will be used. The
810 /// strings that were filled into the `attribute` structure are invalid
811 /// upon the next `advanceToNextNode` or `close` is called.
813 const char *localName,
814 const char *namespaceUri) const
816
817 /// Find the attribute with the specified `localName` and specified
818 /// `namespaceId` in the current node, and fill in the specified
819 /// `attribute` structure. Return 0 on success, 1 if there is no
820 /// attribute found with `localName` and `namespaceId`, and a negative
821 /// value otherwise. If `namespaceId` == -1, then the document's
822 /// default namespace will be used. The strings that were filled into
823 /// the `attribute` structure are invalid upon the next
824 /// `advanceToNextNode` or `close` is called.
826 const char *localName,
827 int namespaceId) const
829
830 /// Set the options to the flags in the specified `flags`. The options
831 /// for the reader are persistent, i.e., the options are not reset by `close`.
832 ///
833 /// \pre The behavior is undefined if this method is called after
834 /// calling `open` and before calling `close`.
835 void setOptions(unsigned int flags) BSLS_KEYWORD_OVERRIDE;
836
837 // ACCESSORS
838
839 /// Return the document encoding or NULL on error. The returned pointer
840 /// is owned by this object and must not be modified or deallocated by
841 /// the caller. The returned pointer becomes invalid when `close` is
842 /// called or the reader is destroyed.
844
845 /// Return the external XML resource resolver.
847
848 /// Return true if `open` was called successfully and `close` has not
849 /// yet been called and false otherwise.
851
852 /// Return a reference to the non-modifiable error information for this
853 /// reader. The returned value becomes invalid when `close` is called
854 /// or the reader is destroyed.
856
857 /// Return the current line number within the input stream. The current
858 /// line is the last line for which the reader has not yet seen a
859 /// newline. Lines are counted starting at one from the time a stream is provide to `open`. Return 0 if not available.
860 ///
861 /// \note Note that a
862 /// derived-class implementation is not required to count lines and may
863 /// just return 0.
865
866 /// Return the current column number within the input stream. The
867 /// current column number is the number of characters since the last
868 /// newline was read by the reader plus one, i.e., the first column of
869 /// each line is column number one. Return 0 if not available.
870 ///
871 /// \note Note that a derived-class implementation is not required to count
872 /// columns and may just return 0.
874
875 /// Return a pointer to the modifiable prefix stack that is used by this
876 /// reader to manage namespace prefixes or 0 if namespace support is disabled.
877 ///
878 /// \pre The behavior is undefined if the returned prefix stack is
879 /// augmented in any way after calling `open` and before calling
880 /// `close`.
882
883 /// Return the node type of the current node if the reader `isOpen` and
884 /// has not encounter an error and `Reader::NONE` otherwise.
886
887 /// Return the qualified name of the current node if the current node
888 /// has a name and NULL otherwise. The returned pointer is owned by
889 /// this object and must not be modified or deallocated by the caller.
890 /// The returned pointer becomes invalid upon the next
891 /// `advanceToNextNode`, when `close` is called or the reader is
892 /// destroyed.
893 const char *nodeName() const BSLS_KEYWORD_OVERRIDE;
894
895 /// Return the local name of the current node if the current node has a
896 /// local name and NULL otherwise. The returned pointer is owned by
897 /// this object and must not be modified or deallocated by the caller.
898 /// The returned pointer becomes invalid upon the next
899 /// `advanceToNextNode`, when `close` is called or the reader is
900 /// destroyed.
902
903 /// Return the prefix name of the current node if the correct node has a
904 /// prefix name and NULL otherwise. The returned pointer is owned by
905 /// this object and must not be modified or deallocated by the caller.
906 /// The returned pointer becomes invalid upon the next
907 /// `advanceToNextNode`, when `close` is called or the reader is
908 /// destroyed.
910
911 /// Return the namespace ID of the current node if the current node has
912 /// a namespace id and a negative number otherwise.
914
915 /// Return the namespace URI name of the current node if the current
916 /// node has a namespace URI and NULL otherwise. The returned pointer
917 /// is owned by this object and must not be modified or deallocated by
918 /// the caller. The returned pointer becomes invalid upon the next
919 /// `advanceToNextNode`, when `close` is called or the reader is
920 /// destroyed.
922
923 /// Return the base URI name of the current node if the current node has
924 /// a base URI and NULL otherwise. The returned pointer is owned by
925 /// this object and must not be modified or deallocated by the caller.
926 /// The returned pointer becomes invalid upon the next
927 /// `advanceToNextNode`, when `close` is called or the reader is
928 /// destroyed.
930
931 /// Return true if the current node has a value and false otherwise.
933
934 /// Return the value of the current node if the current node has a value
935 /// and NULL otherwise. The returned pointer is owned by this object
936 /// and must not be modified or deallocated by the caller. The returned
937 /// pointer becomes invalid upon the next `advanceToNextNode`, when
938 /// `close` is called or the reader is destroyed.
939 const char *nodeValue() const BSLS_KEYWORD_OVERRIDE;
940
941 /// Return the nesting depth of the current node in the XML document.
942 /// The root node has depth 0.
944
945 /// Return the number of attributes for the current node if that node
946 /// has attributes and 0 otherwise.
948
949 /// Return true if the current node is an element (i.e., node type is
950 /// `NODE_TYPE_ELEMENT`) that ends with `/>`; and false otherwise.
951 ///
952 /// \note Note that `<a/>` will be considered empty but `<a></a>` will not.
954
955 /// Return the option flags.
956 unsigned int options() const BSLS_KEYWORD_OVERRIDE;
957
958 // ACCESSORS
959 // SPECIFIC FOR MiniReader
960
961 /// Return the current scanner position as offset from the beginning of
962 /// document.
963 int getCurrentPosition() const;
964
965 /// Return the byte position within the document corresponding to the
966 /// first byte of the current node.
967 int nodeStartPosition() const;
968
969 /// Return the byte position within the document corresponding to the
970 /// byte following after the last byte of the current node.
971 int nodeEndPosition() const;
972
973};
974
975// ============================================================================
976// INLINE DEFINITIONS
977// ============================================================================
978
979 // ----------------
980 // class MiniReader
981 // ----------------
982
983inline
984MiniReader::Node& MiniReader::currentNode()
985{
986 return d_currentNode;
987}
988
989inline
990const MiniReader::Node& MiniReader::currentNode() const
991{
992 return d_currentNode;
993}
994
995inline
996int MiniReader::peekChar()
997{
998 if (d_scanPtr >= d_endPtr) {
999 if (readInput() == 0) {
1000 return 0; // RETURN
1001 }
1002 }
1003
1004 return *d_scanPtr;
1005}
1006
1007inline
1008int MiniReader::getChar()
1009{
1010 if (d_scanPtr >= d_endPtr) {
1011 if (readInput() == 0) {
1012 return 0; // RETURN
1013 }
1014 }
1015 return *d_scanPtr++;
1016}
1017
1018inline
1019bool MiniReader::checkForNewLine()
1020{
1021 if (*d_scanPtr == '\n') {
1022 ++d_lineNum;
1023 d_lineOffset = getCurrentPosition() + 1;
1024
1025 return true; // RETURN
1026 }
1027
1028 return false;
1029}
1030
1031inline
1032int MiniReader::getCharAndSet(char ch)
1033{
1034 //checkForNewLine(); // modify line, column
1035
1036 int rc = peekChar(); // get current char
1037
1038 if (rc != 0) {
1039 checkForNewLine();
1040 *d_scanPtr++ = ch; // replace, advance position
1041 }
1042 return rc;
1043}
1044
1045inline
1046const char *MiniReader::rebasePointer(const char *ptr, const char *newBase)
1047{
1048 if (ptr && ptr >= d_markPtr && ptr <= d_endPtr) {
1049 return newBase + (ptr - d_markPtr); // RETURN
1050 }
1051 return ptr;
1052}
1053
1054inline
1056{
1057 return static_cast<int>(d_streamOffset + (d_scanPtr - d_startPtr));
1058}
1059
1060inline
1062{
1063 return currentNode().d_startPos;
1064}
1065
1066inline
1068{
1069 return currentNode().d_endPos;
1070}
1071
1072} // close package namespace
1073
1074
1075#endif // INCLUDED_BALXML_MINIREADER
1076
1077// ----------------------------------------------------------------------------
1078// Copyright 2015 Bloomberg Finance L.P.
1079//
1080// Licensed under the Apache License, Version 2.0 (the "License");
1081// you may not use this file except in compliance with the License.
1082// You may obtain a copy of the License at
1083//
1084// http://www.apache.org/licenses/LICENSE-2.0
1085//
1086// Unless required by applicable law or agreed to in writing, software
1087// distributed under the License is distributed on an "AS IS" BASIS,
1088// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1089// See the License for the specific language governing permissions and
1090// limitations under the License.
1091// ----------------------------- END-OF-FILE ----------------------------------
1092
1093/** @} */
1094/** @} */
1095/** @} */
Definition balxml_elementattribute.h:290
Definition balxml_errorinfo.h:353
Severity
Definition balxml_errorinfo.h:358
Definition balxml_minireader.h:343
~MiniReader() BSLS_KEYWORD_OVERRIDE
int advanceToNextNode() BSLS_KEYWORD_OVERRIDE
bool nodeHasValue() const BSLS_KEYWORD_OVERRIDE
Return true if the current node has a value and false otherwise.
void close() BSLS_KEYWORD_OVERRIDE
int open(const char *filename, const char *encoding=0) BSLS_KEYWORD_OVERRIDE
int getCurrentPosition() const
Definition balxml_minireader.h:1055
const char * nodeValue() const BSLS_KEYWORD_OVERRIDE
unsigned int options() const BSLS_KEYWORD_OVERRIDE
Return the option flags.
const char * documentEncoding() const BSLS_KEYWORD_OVERRIDE
NodeType nodeType() const BSLS_KEYWORD_OVERRIDE
XmlResolverFunctor resolver() const BSLS_KEYWORD_OVERRIDE
Return the external XML resource resolver.
const char * nodePrefix() const BSLS_KEYWORD_OVERRIDE
virtual int advanceToEndNodeRaw()
const char * nodeBaseUri() const BSLS_KEYWORD_OVERRIDE
const char * nodeNamespaceUri() const BSLS_KEYWORD_OVERRIDE
const ErrorInfo & errorInfo() const BSLS_KEYWORD_OVERRIDE
int getColumnNumber() const BSLS_KEYWORD_OVERRIDE
const char * nodeName() const BSLS_KEYWORD_OVERRIDE
friend struct Node
Definition balxml_minireader.h:358
int nodeDepth() const BSLS_KEYWORD_OVERRIDE
int nodeNamespaceId() const BSLS_KEYWORD_OVERRIDE
const char * nodeLocalName() const BSLS_KEYWORD_OVERRIDE
void setResolver(XmlResolverFunctor resolver) BSLS_KEYWORD_OVERRIDE
void setPrefixStack(PrefixStack *prefixes) BSLS_KEYWORD_OVERRIDE
virtual int advanceToEndNode()
int nodeEndPosition() const
Definition balxml_minireader.h:1067
int numAttributes() const BSLS_KEYWORD_OVERRIDE
bool isOpen() const BSLS_KEYWORD_OVERRIDE
int lookupAttribute(ElementAttribute *attribute, int index) const BSLS_KEYWORD_OVERRIDE
virtual int advanceToEndNodeRawBare()
int getLineNumber() const BSLS_KEYWORD_OVERRIDE
int nodeStartPosition() const
Definition balxml_minireader.h:1061
bool isEmptyElement() const BSLS_KEYWORD_OVERRIDE
void setOptions(unsigned int flags) BSLS_KEYWORD_OVERRIDE
PrefixStack * prefixStack() const BSLS_KEYWORD_OVERRIDE
Definition balxml_prefixstack.h:137
Definition balxml_reader.h:835
bsl::function< StreamBufPtr(const char *location, const char *namespaceUri)> XmlResolverFunctor
Definition balxml_reader.h:921
NodeType
Definition balxml_reader.h:839
Definition bslstl_string.h:1252
Forward declaration.
Definition bslstl_function.h:946
Definition bslstl_pair.h:1280
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:695
Definition balxml_base64parser.h:150
Definition bdlat_valuetypefunctions.h:939
Definition baljsn_encoder_testtypes.h:76