Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component balxml_minireader
[Package balxml]

Provide light-weight implementation of balxml::Reader protocol. More...

Namespaces

namespace  balxml

Detailed Description

Outline
Purpose:
Provide light-weight implementation of balxml::Reader protocol.
Classes:
balxml::MiniReader light-weight balxml::Reader implementation
See also:
Component balxml_reader, Component balxml_errorinfo
Description:
The balxml::MiniReader class is a light-weight implementation of balxml::Reader interface. The API acts as a currentNode going forward on the document stream and stopping at each node in the way. The current node refers to the node on which the reader is positioned. The user's code keeps control of the progress and simply calls a read function repeatedly to progress to each node in sequence in document order. This provides a far more standard, easy to use and powerful API than the existing SAX.
Data Validation
  • - - - - - - - The balxml::MiniReader class is not a validating reader (balxml::ValidatingReader). As a result while parsing data it does not make an attempt to ensure the correctness of either the data or the structure of the incoming XML. The class accepts characters as element data that the XML standard considers invalid. For example the & and < characters in element data will parse without error. Similarly, it does not return an error if the read data does not conform to its specified schema. To get stricter data validation, clients should use a concrete implementation of a validating reader (such as a_xercesc::Reader) instead.
Usage:
For this example, we will use balxml::MiniReader to read each node in an XML document. We do not care about whitespace, so we use the following utility function to skip over any whitespace nodes. This makes our example more portable to other implementations of the balxml::Reader protocol that handle whitespace differently from balxml::MiniReader.
  int advancePastWhiteSpace(balxml::Reader& reader) {
      const char *whiteSpace = "\n\r\t ";
      const char *value = '\0';
      int         type = 0;
      int         rc = 0;

      do {
          rc    = reader.advanceToNextNode();
          value = reader.nodeValue();
          type  = reader.nodeType();
      } while(0 == rc &&
              type == balxml::Reader::BAEXML_NODE_TYPE_WHITESPACE ||
              (type == balxml::Reader::BAEXML_NODE_TYPE_TEXT &&
               bsl::strlen(value) == bsl::strspn(value, whiteSpace)));

      assert( reader.nodeType() !=
                                balxml::Reader::BAEXML_NODE_TYPE_WHITESPACE);

      return rc;
  }
The main program parses an XML string using the TestReader
  int main()
  {
The following string describes xml for a very simple user directory. The top level element contains one xml namespace attribute, with one embedded entry describing a user.
      const char TEST_XML_STRING[] =
         "<?xml version='1.0' encoding='UTF-8'?>\n"
         "<directory-entry xmlns:dir="
                                "'http://bloomberg.com/schemas/directory'>\n"
         "    <name>John Smith</name>\n"
         "    <phone dir:phonetype='cell'>212-318-2000</phone>\n"
         "    <address/>\n"
         "</directory-entry>\n";
In order to read the XML, we first need to construct a balxml::NamespaceRegistry object, a balxml::PrefixStack object, and a TestReader object, where TestReader is a derived implementation of balxml_reader.
      balxml::NamespaceRegistry namespaces;
      balxml::PrefixStack prefixStack(&namespaces);
      balxml::MiniReader miniReader; balxml::Reader& reader = miniReader;

      assert(!reader.isOpen());
The reader uses a balxml::PrefixStack to manage namespace prefixes so we need to set it before we call open.
      reader.setPrefixStack(&prefixStack);
      assert(reader.prefixStack());
      assert(reader.prefixStack() == &prefixStack);
Now we call the open method to setup the reader for parsing using the data contained in the in the XML string.
      reader.open(TEST_XML_STRING, sizeof(TEST_XML_STRING) -1, 0, "UTF-8");
Confirm that the bdem::Reader has opened properly
      assert( reader.isOpen());
      assert(!bsl::strncmp(reader.documentEncoding(), "UTF-8", 5));
      assert( reader.nodeType() == balxml::Reader::BAEXML_NODE_TYPE_NONE);
      assert(!reader.nodeName());
      assert(!reader.nodeHasValue());
      assert(!reader.nodeValue());
      assert(!reader.nodeDepth());
      assert(!reader.numAttributes());
      assert(!reader.isEmptyElement());
Advance through all the nodes and assert all information contained at each node is correct.
Assert the next node's document type is xml.
      int rc = advancePastWhiteSpace(reader);
      assert( 0 == rc);
      assert( reader.nodeType() ==
                           balxml::Reader::BAEXML_NODE_TYPE_XML_DECLARATION);
      assert(!bsl::strcmp(reader.nodeName(), "xml"));
      assert( reader.nodeHasValue());
      assert(!bsl::strcmp(reader.nodeValue(),
                          "version='1.0' encoding='UTF-8'"));
      assert( reader.nodeDepth() == 1);
      assert(!reader.numAttributes());
      assert(!reader.isEmptyElement());
      assert( 0 == rc);
      assert( reader.nodeDepth() == 1);
Advance to the top level element, which has one attribute, the xml namespace. Assert the namespace information has been added correctly to the prefix stack.
      rc = advancePastWhiteSpace(reader);
      assert( 0 == rc);
      assert( reader.nodeType() == balxml::Reader::BAEXML_NODE_TYPE_ELEMENT);
      assert(!bsl::strcmp(reader.nodeName(), "directory-entry"));
      assert(!reader.nodeHasValue());
      assert( reader.nodeDepth() == 1);
      assert( reader.numAttributes() == 1);
      assert(!reader.isEmptyElement());

      assert(!bsl::strcmp(prefixStack.lookupNamespacePrefix("dir"), "dir"));
      assert(prefixStack.lookupNamespaceId("dir") == 0);
      assert(!bsl::strcmp(prefixStack.lookupNamespaceUri("dir"),
                          "http://bloomberg.com/schemas/directory"));
The XML being read contains one entry describing a user, advance the users name name and assert all information can be read correctly.
      rc = advancePastWhiteSpace(reader);
      assert( 0 == rc);
      assert( reader.nodeType() == balxml::Reader::BAEXML_NODE_TYPE_ELEMENT);
      assert(!bsl::strcmp(reader.nodeName(), "name"));
      assert(!reader.nodeHasValue());
      assert( reader.nodeDepth() == 2);
      assert( reader.numAttributes() == 0);
      assert(!reader.isEmptyElement());

      rc = reader.advanceToNextNode();
      assert( 0 == rc);
      assert( reader.nodeType() == balxml::Reader::BAEXML_NODE_TYPE_TEXT);
      assert( reader.nodeHasValue());
      assert(!bsl::strcmp(reader.nodeValue(), "John Smith"));
      assert( reader.nodeDepth() == 3);
      assert( reader.numAttributes() == 0);
      assert(!reader.isEmptyElement());

      rc = reader.advanceToNextNode();
      assert( 0 == rc);
      assert( reader.nodeType() ==
                               balxml::Reader::BAEXML_NODE_TYPE_END_ELEMENT);
      assert(!bsl::strcmp(reader.nodeName(), "name"));
      assert(!reader.nodeHasValue());
      assert( reader.nodeDepth() == 2);
      assert( reader.numAttributes() == 0);
      assert(!reader.isEmptyElement());
Advance to the user's phone number and assert all information can be read correctly.
      rc = advancePastWhiteSpace(reader);
      assert( 0 == rc);
      assert( reader.nodeType() == balxml::Reader::BAEXML_NODE_TYPE_ELEMENT);
      assert(!bsl::strcmp(reader.nodeName(), "phone"));
      assert(!reader.nodeHasValue());
      assert( reader.nodeDepth() == 2);
      assert( reader.numAttributes() == 1);
      assert(!reader.isEmptyElement());
The phone node has one attribute, look it up and assert the balxml::ElementAttribute contains valid information and that the prefix returns the correct namespace URI from the prefix stack.
      balxml::ElementAttribute elemAttr;

      rc = reader.lookupAttribute(&elemAttr, 0);
      assert( 0 == rc);
      assert(!elemAttr.isNull());
      assert(!bsl::strcmp(elemAttr.qualifiedName(), "dir:phonetype"));
      assert(!bsl::strcmp(elemAttr.value(), "cell"));
      assert(!bsl::strcmp(elemAttr.prefix(), "dir"));
      assert(!bsl::strcmp(elemAttr.localName(), "phonetype"));
      assert(!bsl::strcmp(elemAttr.namespaceUri(),
                          "http://bloomberg.com/schemas/directory"));
      assert( elemAttr.namespaceId() == 0);

      assert(!bsl::strcmp(prefixStack.lookupNamespaceUri(elemAttr.prefix()),
                          elemAttr.namespaceUri()));

      rc = advancePastWhiteSpace(reader);
      assert( 0 == rc);
      assert( reader.nodeType() == balxml::Reader::BAEXML_NODE_TYPE_TEXT);
      assert( reader.nodeHasValue());
      assert(!bsl::strcmp(reader.nodeValue(), "212-318-2000"));
      assert( reader.nodeDepth() == 3);
      assert( reader.numAttributes() == 0);
      assert(!reader.isEmptyElement());

      rc = advancePastWhiteSpace(reader);
      assert( 0 == rc);
      assert( reader.nodeType() ==
                               balxml::Reader::BAEXML_NODE_TYPE_END_ELEMENT);
      assert(!bsl::strcmp(reader.nodeName(), "phone"));
      assert(!reader.nodeHasValue());
      assert( reader.nodeDepth() == 2);
      assert( reader.numAttributes() == 0);
      assert(!reader.isEmptyElement());
Advance to the user's address and assert all information can be read correctly.
      rc = advancePastWhiteSpace(reader);
      assert( 0 == rc);
      assert( reader.nodeType() == balxml::Reader::BAEXML_NODE_TYPE_ELEMENT);
      assert(!bsl::strcmp(reader.nodeName(), "address"));
      assert(!reader.nodeHasValue());
      assert( reader.nodeDepth() == 2);
      assert( reader.numAttributes() == 0);
      assert( reader.isEmptyElement());
Advance to the end element.
      rc = advancePastWhiteSpace(reader);
      assert( 0 == rc);
      assert( reader.nodeType() ==
                               balxml::Reader::BAEXML_NODE_TYPE_END_ELEMENT);
      assert(!bsl::strcmp(reader.nodeName(), "directory-entry"));
      assert(!reader.nodeHasValue());
      assert( reader.nodeDepth() == 1);
      assert( reader.numAttributes() == 0);
      assert(!reader.isEmptyElement());
Close the reader.
      reader.close();
      assert(!reader.isOpen());

      return 0;
  }