BDE 4.14.0 Production release
Loading...
Searching...
No Matches
balxml_elementattribute

Detailed Description

Outline

Purpose

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

Classes

See also
balxml_reader, 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

This section illustrates intended use of this component.

Example 1: Basic 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)
{
Definition balxml_elementattribute.h:289
Definition balxml_prefixstack.h:137

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;
}
void reset()
Reset this object to the default-constructed state.

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::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");
Definition balxml_namespaceregistry.h:181

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'";
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());
const char * prefix() const
const char * localName() const
const char * namespaceUri() const
const char * qualifiedName() const
Definition balxml_elementattribute.h:517
unsigned flags() const
Definition balxml_elementattribute.h:529
const char * value() const
Definition balxml_elementattribute.h:523
bool isNull() const
Definition balxml_elementattribute.h:535

Results are slightly different when the attribute name has no prefix:

char attrStr2[] = "name=\"Bloomberg, L.P.\"";
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;
}