Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component balxml_elementattribute
[Package balxml]

Provide the properties of an attribute in an XML element tag. More...

Namespaces

namespace  balxml

Detailed Description

Outline
Purpose:
Provide the properties of an attribute in an XML element tag.
Classes:
balxml::ElementAttribute Properties of an attribute in an XML element tag.
See also:
Component balxml_reader, Component balxml_prefixstack
Description:
This component provides a class, balxml::ElementAttribute, that encapsulates the name, namespace, and value of an attribute within an element in an XML document, along with a flag indicating whether the value comes from the default value in the document's schema. There are accessors to return the attribute name as a qualified name, namespace prefix, namespace URI, namespace ID (in a namespace registry), and local name (without the prefix).
If a namespace prefix stack and a qualified name are provided at construction (or via the reset method), then all of the other facets of the name can be computed automatically. For efficiency reasons, these various decompositions of the attribute name are computed only when needed and cached within the balxml::ElementAttribute structure. The caller can supply any or all of these computed facets in the constructor or reset method. Explicitly supplying a facet prevents it from being computed, thus saving processing time. If the object is constructed with explicit values for all facets of the name, then the prefix stack is never used and may be null. If an explicitly-supplied facet differs from the value that would have been computed otherwise, then the facets returned by the accessors will be inconsistent with one-another. This inconsistency is deliberately permitted so that an program may construct a balxml::ElementAttribute even when some parts of the name are not yet known, e.g., if the prefix URI is known but the qualified name is not. If the qualified name facet is zero, then no other facets will be computed -- their original values will be returned from the accessors.
Not Value Semantic:
balxml::ElementAttribute is not a value-semantic class. It provides copy construction and assignment, but does not provide equality or persistence operators. Copying a balxml::ElementAttribute object copies all of its pointer facets but does not make copies of the pointed-to strings or objects. The presence of copy operations makes it possible to use balxml::ElementAttribute with container class templates.
A balxml::ElementAttribute object does not own any of its pointer facets and it performs no memory management. This means that a balxml::ElementAttribute object can be invalidated by modifying or deleting any of the pointed-to entities. Calling an accessor on an invalid balxml::ElementAttribute is unsafe because the accessor may return an invalid pointer. However an invalid object may be safely destroyed or reset. Components that set or return a balxml::ElementAttribute object should provide clear documentation describing the events that will cause the resulting balxml::ElementAttribute object to become invalid (see balxml::Reader).
Thread Safety:
It is safe to access or modify two balxml::ElementAttribute objects simultaneously, each from a separate thread. It is safe to access a single balxml::ElementAttribute object simultaneously from two or more separate threads, provided no other thread is simultaneously modifying the object. It is not safe to access or modify a balxml::ElementAttribute object in one thread while another thread modifies the same object.
A balxml::ElementAttribute object holds pointers to objects that it does not own and which can be modified independently of the balxml::ElementAttribute object. It is not safe to modify or delete any of these object in one thread while accessing or modifying the balxml::ElementAttribute object in another thread.
Usage:
The following function parses an XML-style attribute assignment in the form "qname='value'", where qname can be a qualified name in the form, "prefix:localName". The prefix (if any) must be registered in the specified prefixStack object. Either single or double quotes may be used to enclose the attribute value. The parsed attribute is stored in the specified attribute object of type balxml::ElementAttribute. Note that this function modifies the input string by inserting null characters, rather than copying the component parts into allocated memory. This is a realistic interface for a function used within an XML parser that has already copied the XML stream into allocated memory. Also note that this function does not interpret character escapes such as "&".
  int parseAttribute(balxml::ElementAttribute  *attribute,
                     char                     *attributeString,
                     const balxml::PrefixStack *prefixStack)
  {
First, find the end of the qualified name, i.e., the = character:
      char *qname    = attributeString;
      char *equalPtr = bsl::strchr(qname, '=');
      if (0 == equalPtr) {
          return -1;
      }
Then find out which quote character is used to start the value string
      char quote = *(equalPtr + 1);
      if (quote != '\'' && quote != '"') {
          return -1;
      }
The value string starts after the opening quote and extends until a matching quote:
      char *value    = equalPtr + 2;
      char *endValue = bsl::strchr(value, quote);
      if (0 == endValue) {
          return -1;
      }
Once we have successfully parsed the string, chop it into pieces by putting a null terminator at the end of the qualified name and at the end of the value string:
      *equalPtr = '\0';    // Terminate qualified name
      *endValue = '\0';    // Terminate value string
Use the prefix stack, qname, and value to set the attribute object. All other arguments are defaulted and will be computed as needed.
      attribute->reset(prefixStack, qname, value);
      return 0;
  }
Before calling the parseAttribute function, it is necessary to create a namespace registry and prefix stack, as well as to register one or more prefixes:
  int main()
  {
      balxml::NamespaceRegistry registry;
      balxml::PrefixStack prefixes(&registry);
      int cal = prefixes.pushPrefix("cal",
                                "http://www.bloomberg.com/schemas/calendar");
      prefixes.pushPrefix("math", "http://www.bloomberg.com/schemas/math");
      prefixes.pushPrefix("",  // Default namespace
                          "http://www.bloomberg.com/schemas/app");
Now we can parse an attribute string and the balxml::ElementAttribute object will provide detailed information about it.
      char attrStr1[] = "cal:date='12-07-2006'";
      balxml::ElementAttribute attribute1;
      assert(attribute1.isNull());
      parseAttribute(&attribute1, attrStr1, &prefixes);

      assert(0 == bsl::strcmp("cal:date", attribute1.qualifiedName()));
      assert(0 == bsl::strcmp("12-07-2006", attribute1.value()));
      assert(0 == bsl::strcmp("date", attribute1.localName()));
      assert(0 == bsl::strcmp("cal", attribute1.prefix()));
      assert(cal == attribute1.namespaceId());
      assert(0 == bsl::strcmp("http://www.bloomberg.com/schemas/calendar",
                              attribute1.namespaceUri()));
      assert(0 == attribute1.flags());
Results are slightly different when the attribute name has no prefix:
      char attrStr2[] = "name=\"Bloomberg, L.P.\"";
      balxml::ElementAttribute attribute2;
      parseAttribute(&attribute2, attrStr2, &prefixes);

      assert(0 == bsl::strcmp("name", attribute2.qualifiedName()));
      assert(0 == bsl::strcmp("Bloomberg, L.P.", attribute2.value()));
      assert(0 == bsl::strcmp("name", attribute2.localName()));
As per the XML namespace standard, an attribute with no namespace prefix does NOT inherit the default namespace but rather has NO namespace:
      assert(0 == bsl::strcmp("", attribute2.prefix()));
      assert(-1 == attribute2.namespaceId());
      assert(0 == bsl::strcmp("", attribute2.namespaceUri()));
      assert(0 == attribute2.flags());
A balxml::ElementAttribute does not need to be generated by parsing XML code. If a specific facet of the object is set to a non-null value, then that value will be returned by the corresponding accessor even if it is inconsistent with the other values in the object. For example, the following constructs a valid balxml::ElementAttribute object, even though the prefix value does not agree with the qualified name:
      balxml::ElementAttribute attribute3(&prefixes,
                                         "math:product", "4.5", "cal");
There is no consistency checking, and the mismatched prefix is simply returned by the accessor:
      assert(0 == bsl::strcmp("math:product", attribute3.qualifiedName()));
      assert(0 == bsl::strcmp("product", attribute3.localName()));
      assert(0 == bsl::strcmp("cal", attribute3.prefix()));
Note that the ability to create inconsistent objects is a deliberate feature. It allows parsers to construct balxml::Attribute objects before all information is known, e.g., before the namespace is registered with the prefix stack. Consistency checking also reduces performance.
      return 0;
  }