BDE 4.39.x Production Release
Loading...
Searching...
No Matches
balxml_elementattribute.h
Go to the documentation of this file.
1/// @file balxml_elementattribute.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balxml_elementattribute.h -*-C++-*-
8#ifndef INCLUDED_BALXML_ELEMENTATTRIBUTE
9#define INCLUDED_BALXML_ELEMENTATTRIBUTE
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balxml_elementattribute balxml_elementattribute
15/// @brief Provide the properties of an attribute in an XML element tag.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balxml
19/// @{
20/// @addtogroup balxml_elementattribute
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balxml_elementattribute-purpose"> Purpose</a>
25/// * <a href="#balxml_elementattribute-classes"> Classes </a>
26/// * <a href="#balxml_elementattribute-description"> Description </a>
27/// * <a href="#balxml_elementattribute-not-value-semantic"> Not Value Semantic </a>
28/// * <a href="#balxml_elementattribute-thread-safety"> Thread Safety </a>
29/// * <a href="#balxml_elementattribute-usage"> Usage </a>
30/// * <a href="#balxml_elementattribute-example-1-basic-usage"> Example 1: Basic Usage </a>
31///
32/// # Purpose {#balxml_elementattribute-purpose}
33/// Provide the properties of an attribute in an XML element tag.
34///
35/// # Classes {#balxml_elementattribute-classes}
36///
37/// - balxml::ElementAttribute: Properties of an attribute in an XML element tag.
38///
39/// @see balxml_reader, balxml_prefixstack
40///
41/// # Description {#balxml_elementattribute-description}
42/// This component provides a class, `balxml::ElementAttribute`,
43/// that encapsulates the name, namespace, and value of an attribute within an
44/// element in an XML document, along with a flag indicating whether the value
45/// comes from the default value in the document's schema. There are accessors
46/// to return the attribute name as a qualified name, namespace prefix,
47/// namespace URI, namespace ID (in a namespace registry), and local name
48/// (without the prefix).
49///
50/// If a namespace prefix stack and a qualified name are provided at
51/// construction (or via the `reset` method), then all of the other facets of
52/// the name can be computed automatically. For efficiency reasons, these
53/// various decompositions of the attribute name are computed only when needed
54/// and cached within the `balxml::ElementAttribute` structure. The caller can
55/// supply any or all of these computed facets in the constructor or `reset`
56/// method. Explicitly supplying a facet prevents it from being computed, thus
57/// saving processing time. If the object is constructed with explicit values
58/// for all facets of the name, then the prefix stack is never used and may be
59/// null. If an explicitly-supplied facet differs from the value that would
60/// have been computed otherwise, then the facets returned by the accessors
61/// will be inconsistent with one-another. This inconsistency is deliberately
62/// permitted so that an program may construct a `balxml::ElementAttribute`
63/// even when some parts of the name are not yet known, e.g., if the prefix URI
64/// is known but the qualified name is not. If the qualified name facet is
65/// zero, then no other facets will be computed -- their original values will be
66/// returned from the accessors.
67///
68/// ## Not Value Semantic {#balxml_elementattribute-not-value-semantic}
69///
70///
71/// `balxml::ElementAttribute` is not a value-semantic class. It provides copy
72/// construction and assignment, but does not provide equality or persistence
73/// operators. Copying a `balxml::ElementAttribute` object copies all of its
74/// pointer facets but does not make copies of the pointed-to strings or
75/// objects. The presence of copy operations makes it possible to use
76/// `balxml::ElementAttribute` with container class templates.
77///
78/// A `balxml::ElementAttribute` object does not own any of its pointer facets
79/// and it performs no memory management. This means that a
80/// `balxml::ElementAttribute` object can be invalidated by modifying or
81/// deleting any of the pointed-to entities. Calling an accessor on an invalid
82/// `balxml::ElementAttribute` is unsafe because the accessor may return an
83/// invalid pointer. However an invalid object may be safely destroyed or
84/// reset. Components that set or return a `balxml::ElementAttribute` object
85/// should provide clear documentation describing the events that will cause
86/// the resulting `balxml::ElementAttribute` object to become invalid (see
87/// `balxml::Reader`).
88///
89/// ## Thread Safety {#balxml_elementattribute-thread-safety}
90///
91///
92/// It is safe to access or modify two `balxml::ElementAttribute` objects
93/// simultaneously, each from a separate thread. It is safe to access a single
94/// `balxml::ElementAttribute` object simultaneously from two or more separate
95/// threads, provided no other thread is simultaneously modifying the object.
96/// It is not safe to access or modify a `balxml::ElementAttribute` object in
97/// one thread while another thread modifies the same object.
98///
99/// A `balxml::ElementAttribute` object holds pointers to objects that it does
100/// not own and which can be modified independently of the
101/// `balxml::ElementAttribute` object. It is not safe to modify or delete any
102/// of these object in one thread while accessing or modifying the
103/// `balxml::ElementAttribute` object in another thread.
104///
105/// ## Usage {#balxml_elementattribute-usage}
106///
107///
108/// This section illustrates intended use of this component.
109///
110/// ### Example 1: Basic Usage {#balxml_elementattribute-example-1-basic-usage}
111///
112///
113/// The following function parses an XML-style attribute assignment in the form
114/// "qname=`value`", where `qname` can be a qualified name in the form,
115/// "prefix:localName". The prefix (if any) must be registered in the specified
116/// `prefixStack` object. Either single or double quotes may be used to
117/// enclose the attribute value. The parsed attribute is stored in the
118/// specified `attribute` object of type `balxml::ElementAttribute`. Note that
119/// this function modifies the input string by inserting null characters,
120/// rather than copying the component parts into allocated memory. This is a
121/// realistic interface for a function used within an XML parser that has
122/// already copied the XML stream into allocated memory. Also note that this
123/// function does not interpret character escapes such as "&amp;".
124/// @code
125/// int parseAttribute(balxml::ElementAttribute *attribute,
126/// char *attributeString,
127/// const balxml::PrefixStack *prefixStack)
128/// {
129/// @endcode
130/// First, find the end of the qualified name, i.e., the `=` character:
131/// @code
132/// char *qname = attributeString;
133/// char *equalPtr = bsl::strchr(qname, '=');
134/// if (0 == equalPtr) {
135/// return -1;
136/// }
137/// @endcode
138/// Then find out which quote character is used to start the value string
139/// @code
140/// char quote = *(equalPtr + 1);
141/// if (quote != '\'' && quote != '"') {
142/// return -1;
143/// }
144/// @endcode
145/// The value string starts after the opening quote and extends until a
146/// matching quote:
147/// @code
148/// char *value = equalPtr + 2;
149/// char *endValue = bsl::strchr(value, quote);
150/// if (0 == endValue) {
151/// return -1;
152/// }
153/// @endcode
154/// Once we have successfully parsed the string, chop it into pieces by putting
155/// a null terminator at the end of the qualified name and at the end of the
156/// value string:
157/// @code
158/// *equalPtr = '\0'; // Terminate qualified name
159/// *endValue = '\0'; // Terminate value string
160/// @endcode
161/// Use the prefix stack, qname, and value to set the attribute object. All
162/// other arguments are defaulted and will be computed as needed.
163/// @code
164/// attribute->reset(prefixStack, qname, value);
165/// return 0;
166/// }
167/// @endcode
168/// Before calling the `parseAttribute` function, it is necessary to create a
169/// namespace registry and prefix stack, as well as to register one or more
170/// prefixes:
171/// @code
172/// int main()
173/// {
174/// balxml::NamespaceRegistry registry;
175/// balxml::PrefixStack prefixes(&registry);
176/// int cal = prefixes.pushPrefix("cal",
177/// "http://www.bloomberg.com/schemas/calendar");
178/// prefixes.pushPrefix("math", "http://www.bloomberg.com/schemas/math");
179/// prefixes.pushPrefix("", // Default namespace
180/// "http://www.bloomberg.com/schemas/app");
181/// @endcode
182/// Now we can parse an attribute string and the `balxml::ElementAttribute`
183/// object will provide detailed information about it.
184/// @code
185/// char attrStr1[] = "cal:date='12-07-2006'";
186/// balxml::ElementAttribute attribute1;
187/// assert(attribute1.isNull());
188/// parseAttribute(&attribute1, attrStr1, &prefixes);
189///
190/// assert(0 == bsl::strcmp("cal:date", attribute1.qualifiedName()));
191/// assert(0 == bsl::strcmp("12-07-2006", attribute1.value()));
192/// assert(0 == bsl::strcmp("date", attribute1.localName()));
193/// assert(0 == bsl::strcmp("cal", attribute1.prefix()));
194/// assert(cal == attribute1.namespaceId());
195/// assert(0 == bsl::strcmp("http://www.bloomberg.com/schemas/calendar",
196/// attribute1.namespaceUri()));
197/// assert(0 == attribute1.flags());
198/// @endcode
199/// Results are slightly different when the attribute name has no prefix:
200/// @code
201/// char attrStr2[] = "name=\"Bloomberg, L.P.\"";
202/// balxml::ElementAttribute attribute2;
203/// parseAttribute(&attribute2, attrStr2, &prefixes);
204///
205/// assert(0 == bsl::strcmp("name", attribute2.qualifiedName()));
206/// assert(0 == bsl::strcmp("Bloomberg, L.P.", attribute2.value()));
207/// assert(0 == bsl::strcmp("name", attribute2.localName()));
208/// @endcode
209/// As per the XML namespace standard, an attribute with no namespace prefix
210/// does NOT inherit the default namespace but rather has NO namespace:
211/// @code
212/// assert(0 == bsl::strcmp("", attribute2.prefix()));
213/// assert(-1 == attribute2.namespaceId());
214/// assert(0 == bsl::strcmp("", attribute2.namespaceUri()));
215/// assert(0 == attribute2.flags());
216/// @endcode
217/// A `balxml::ElementAttribute` does not need to be generated by parsing XML
218/// code. If a specific facet of the object is set to a non-null value, then
219/// that value will be returned by the corresponding accessor even if it is
220/// inconsistent with the other values in the object. For example, the
221/// following constructs a valid `balxml::ElementAttribute` object, even though
222/// the prefix value does not agree with the qualified name:
223/// @code
224/// balxml::ElementAttribute attribute3(&prefixes,
225/// "math:product", "4.5", "cal");
226/// @endcode
227/// There is no consistency checking, and the mismatched prefix is simply
228/// returned by the accessor:
229/// @code
230/// assert(0 == bsl::strcmp("math:product", attribute3.qualifiedName()));
231/// assert(0 == bsl::strcmp("product", attribute3.localName()));
232/// assert(0 == bsl::strcmp("cal", attribute3.prefix()));
233/// @endcode
234/// Note that the ability to create inconsistent objects is a deliberate
235/// feature. It allows parsers to construct `balxml::Attribute` objects before
236/// all information is known, e.g., before the namespace is registered with the
237/// prefix stack. Consistency checking also reduces performance.
238/// @code
239/// return 0;
240/// }
241/// @endcode
242/// @}
243/** @} */
244/** @} */
245
246/** @addtogroup bal
247 * @{
248 */
249/** @addtogroup balxml
250 * @{
251 */
252/** @addtogroup balxml_elementattribute
253 * @{
254 */
255
256#include <balscm_version.h>
257
260
261#include <bsl_climits.h>
262#include <bsl_ostream.h>
263
264#ifndef BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
265#include <bslalg_typetraits.h>
266#endif // BDE_DONT_ALLOW_TRANSITIVE_INCLUDES
267
268
269namespace balxml {
270
271class PrefixStack;
272
273 // ======================
274 // class ElementAttribute
275 // ======================
276
277/// Class to represent the properties of an attribute in an XML element tag.
278///
279/// \note Note that this class is not value semantic and does not own any of its
280/// pointer values. The owner of the arguments used to set the value of a
281/// `ElementAttribute` is responsible for ensuring that the values remain
282/// valid or else must document the conditions that will make the values
283/// invalid. Some facets are computed the first time that they are needed.
284/// To avoid extra processing, the caller may supply otherwise-computed
285/// facets at construction or by calling `reset`. Facets provided by the
286/// caller are not checked to ensure that they are consistent with one
287/// another.
288///
289/// See @ref balxml_elementattribute
291
292 // MEMBER VARIABLES
293
294 // Mutable members may be used to cache computed results.
295 const PrefixStack *d_prefixStack; // Held, not owned
296 const char *d_qualifiedName; // Held, not owned
297 const char *d_value; // Held, not owned
298 mutable const char *d_prefix; // Held, not owned
299 mutable const char *d_localName; // Held, not owned
300 mutable int d_namespaceId;
301 mutable const char *d_namespaceUri; // Held, not owned
302 unsigned d_flags;
303
304 public:
305 // FLAGS
306
307 // The flags property should be set to the bitwise-OR of one or more of
308 // the following values:
309 enum {
310 /// No flags set.
312
313 /// Set this bit if the value for this attribute object was
314 /// generated from the default attribute value in the DTD or
315 /// schema.
317
318 /// Set this bit if this attribute represents a namespace
319 /// declaration.
321
322 /// Set this bit if this attribute represents a XML schema instance
323 /// declaration.
324 k_ATTR_IS_XSIDECL = 0x0004
325
326#ifndef BDE_OMIT_INTERNAL_DEPRECATED
334#endif // BDE_OMIT_INTERNAL_DEPRECATED
335 };
336
337 // TRAITS
340
341 // PUBLIC CREATORS
342
343 /// Construct a null attribute object: Set all string facets to zero,
344 /// the namespace ID to `INT_MIN`, and flags to zero.
346
347 /// Construct an attribute object with the specified, `prefixStack`,
348 /// `qualifiedName`, and `value`, with optionally specified `prefix`,
349 /// `localName`, `namespaceId`, `namespaceUri`, and `flags`. Except
350 /// for `flags`, if any of the optional arguments are null (for
351 /// pointers) or `INT_MIN` (for integer arguments), then the
352 /// corresponding facet will computed from the other arguments on an
353 /// as-needed basis. If all of the optional arguments are given
354 /// non-null, non-`INT_MIN` values, then `prefixStack` is unused and
355 /// may be null. Arguments are permitted to be inconsistent with one
356 /// another (e.g., `prefix` may not match the beginning of
357 /// `qualifiedName`) and will produce an object for with facets that
358 /// are inconsistent with one another. The constructed object will
359 /// become invalid if any of the supplied pointers is invalidated
360 /// during its lifetime (or before it is reset). An invalid object may
361 /// be destroyed or reset, but any other access yields undefined
362 /// behavior.
364 const char *qualifiedName,
365 const char *value,
366 const char *prefix = 0,
367 const char *localName = 0,
368 int namespaceId = INT_MIN,
369 const char *namespaceUri = 0,
370 unsigned flags = 0);
371
372#ifdef DOXYGEN
373 // For efficiency, use compiler-generated copy constructor, destructor,
374 // and assignment, but document them as though they were explicitly
375 // declared:
376
378 // Construct a copy of the specified 'other' attribute object. The
379 // copy will have pointers to the same strings and prefix table as
380 // 'other'.
381
383 // Destroy this attribute object. The targets of the pointers used to
384 // construct or reset this object are not owned by this object and are
385 // not deallocated. It is safe to destroy a 'ElementAttribute'
386 // object that is in an invalid state.
387
388 ElementAttribute operator=(const ElementAttribute& rhs);
389 // Assign this attribute object the value of 'rhs'. This object will
390 // have pointers to the same strings and prefix table as 'other'.
391#endif
392
393 /// Reset this object to the default-constructed state.
394 void reset();
395
396 /// Reset this attribute object with the specified, `prefixStack`,
397 /// `qualifiedName`, and `value`, with optionally specified `prefix`,
398 /// `localName`, `namespaceId`, `namespaceUri`, and `flags`. Except
399 /// for `flags`, if any of the optional arguments are null (for
400 /// pointers) or `INT_MIN` (for integer arguments), then the
401 /// corresponding facet will computed from the other arguments on an
402 /// as-needed basis. If all of the optional arguments are given
403 /// non-null, non-`INT_MIN` values, then `prefixStack` is unused and
404 /// may be null. Arguments are permitted to be inconsistent with one
405 /// another (e.g., `prefix` may not match the beginning of
406 /// `qualifiedName`) and will produce an object for with facets that
407 /// are inconsistent with one another. This object will become invalid
408 /// if any of the supplied pointers is invalidated during its lifetime
409 /// (or before it is reset). An invalid object may be destroyed or
410 /// reset, but any other access yields undefined behavior.
412 const char *qualifiedName,
413 const char *value,
414 const char *prefix = 0,
415 const char *localName = 0,
416 int namespaceId = INT_MIN,
417 const char *namespaceUri = 0,
418 unsigned flags = 0);
419
420 // ACCESSORS
421
422 /// Return the value of `prefixStack` specified at the last call to
423 /// `reset` or the constructor or 0 if no prefix stack was specified.
424 const PrefixStack *prefixStack() const;
425
426 /// Return the value of `qualifiedName` specified at the last call to
427 /// `reset` or the constructor or 0 if no qualified name was specified.
428 const char *qualifiedName() const;
429
430 /// Return the value of `value` specified at the last call to `reset`
431 /// or the constructor or 0 if no value was specified.
432 const char *value() const;
433
434 /// Return the value of `prefix` specified at the last call to `reset`
435 /// or the constructor, if non-zero, else return a copy of the prefix
436 /// portion of the qualified name. More precisely, return a copy of
437 /// the portion of `qualifiedName()` up to, but not including, the
438 /// colon. Return an empty string if the qualified name has no colon
439 /// or if `prefixStack()` returns zero.
440 const char *prefix() const;
441
442 /// Return the value of `localName` specified at the last call to
443 /// `reset` or the constructor, if non-zero, else return the local part
444 /// of the qualified name. More precisely, return the portion of
445 /// `qualifiedName()` after the colon, if any, or the entire
446 /// `qualifiedName()` if there is no colon.
447 const char *localName() const;
448
449 /// Return the value of `localName` specified at the last call to
450 /// `reset` or the constructor, if not `INT_MIN`, else return the ID
451 /// returned by the prefix stack for the current value of `prefix()`.
452 /// Return -1 if `prefix()` is an empty string, `prefixStack()` is
453 /// zero, or `prefix()` is not active in the prefix stack.
454 ///
455 /// \note Note that, as per the XML namespace standard, an empty prefix does *NOT* refer
456 /// to the default namespace, but rather refers to *NO* namespace.
457 int namespaceId() const;
458
459 /// Return the value of `namespaceUri` specified at the last call to
460 /// `reset` or the constructor, if non-zero, else return the URI
461 /// returned by the prefix stack for the current value of `prefix()`.
462 /// Return an empty string if `prefix()` is an empty string,
463 /// `prefixStack()` is zero, or `prefix()` is not active in the prefix stack.
464 ///
465 /// \note Note that, as per the XML namespace standard, an empty
466 /// prefix does *NOT* refer to the default namespace, but rather refers
467 /// to *NO* namespace.
468 const char *namespaceUri() const;
469
470 /// Return the value of `flags` specified at the last call to `reset`
471 /// or the constructor, if non-zero, or zero otherwise. Pre-defined
472 /// flags are enumerated in the class definition.
473 unsigned flags() const;
474
475 /// Return true if this object is null. More precisely, return true if
476 /// `qualifiedName()` returns 0. A default-constructed object will be
477 /// null, as will an object that was reset with no arguments.
478 bool isNull() const;
479
480 /// Format this object to the specified output `stream` at the
481 /// (absolute value of) the optionally specified indentation `level`
482 /// and return a reference to `stream`. If `level` is specified,
483 /// optionally specify `spacesPerLevel`, the number of spaces per
484 /// indentation level for this and all of its nested objects. If
485 /// `level` is negative, suppress indentation of the first line. If
486 /// `spacesPerLevel` is negative, format the entire output on one line.
487 /// If `stream` is not valid on entry, this operation has no effect.
488 /// Facet values that have not yet been computed are represented by
489 /// "<null>" in the resulting stream.
490 bsl::ostream& print(bsl::ostream& stream,
491 int level = 0,
492 int spacesPerLevel = 4) const;
493};
494
495// FREE OPERATORS
496
497/// Write the contents of the specified `attribute` object to the specified
498/// `os` in human-readable form. Attributes that have not yet been
499/// computed are not computed by this function.
500inline
501bsl::ostream& operator<<(bsl::ostream& os,
502 const ElementAttribute& attribute);
503
504// ============================================================================
505// INLINE DEFINITIONS
506// ============================================================================
507
508 // ----------------------
509 // class ElementAttribute
510 // ----------------------
511
512// ACCESSORS
513inline
515{
516 return d_prefixStack;
517}
518
519inline
521{
522 return d_qualifiedName;
523}
524
525inline
526const char *ElementAttribute::value() const
527{
528 return d_value;
529}
530
531inline
533{
534 return d_flags;
535}
536
537inline
539{
540 return 0 == d_qualifiedName;
541}
542
543} // close package namespace
544
545// FREE OPERATORS
546inline
547bsl::ostream& balxml::operator<<(bsl::ostream& os,
548 const ElementAttribute& attribute)
549{
550 return attribute.print(os);
551}
552
553
554
555#endif
556
557// ----------------------------------------------------------------------------
558// Copyright 2015 Bloomberg Finance L.P.
559//
560// Licensed under the Apache License, Version 2.0 (the "License");
561// you may not use this file except in compliance with the License.
562// You may obtain a copy of the License at
563//
564// http://www.apache.org/licenses/LICENSE-2.0
565//
566// Unless required by applicable law or agreed to in writing, software
567// distributed under the License is distributed on an "AS IS" BASIS,
568// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
569// See the License for the specific language governing permissions and
570// limitations under the License.
571// ----------------------------- END-OF-FILE ----------------------------------
572
573/** @} */
574/** @} */
575/** @} */
Definition balxml_elementattribute.h:290
const PrefixStack * prefixStack() const
Definition balxml_elementattribute.h:514
const char * prefix() const
const char * localName() const
@ BAEXML_ATTR_IS_NSDECL
Definition balxml_elementattribute.h:329
@ ATTR_IS_DEFAULT
Definition balxml_elementattribute.h:332
@ BAEXML_ATTR_IS_XSIDECL
Definition balxml_elementattribute.h:330
@ ATTR_IS_NSDECL
Definition balxml_elementattribute.h:333
@ BAEXML_ATTR_NO_FLAGS
Definition balxml_elementattribute.h:327
@ k_ATTR_NO_FLAGS
No flags set.
Definition balxml_elementattribute.h:311
@ k_ATTR_IS_DEFAULT
Definition balxml_elementattribute.h:316
@ k_ATTR_IS_NSDECL
Definition balxml_elementattribute.h:320
@ k_ATTR_IS_XSIDECL
Definition balxml_elementattribute.h:324
@ ATTR_NO_FLAGS
Definition balxml_elementattribute.h:331
@ BAEXML_ATTR_IS_DEFAULT
Definition balxml_elementattribute.h:328
ElementAttribute(const PrefixStack *prefixStack, const char *qualifiedName, const char *value, const char *prefix=0, const char *localName=0, int namespaceId=INT_MIN, const char *namespaceUri=0, unsigned flags=0)
const char * namespaceUri() const
const char * qualifiedName() const
Definition balxml_elementattribute.h:520
void reset()
Reset this object to the default-constructed state.
unsigned flags() const
Definition balxml_elementattribute.h:532
bsl::ostream & print(bsl::ostream &stream, int level=0, int spacesPerLevel=4) const
BSLMF_NESTED_TRAIT_DECLARATION(ElementAttribute, bsl::is_trivially_copyable)
void reset(const PrefixStack *prefixStack, const char *qualifiedName, const char *value, const char *prefix=0, const char *localName=0, int namespaceId=INT_MIN, const char *namespaceUri=0, unsigned flags=0)
const char * value() const
Definition balxml_elementattribute.h:526
bool isNull() const
Definition balxml_elementattribute.h:538
Definition balxml_prefixstack.h:137
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
Definition balxml_base64parser.h:150
bsl::ostream & operator<<(bsl::ostream &stream, const ConfigSchema &schema)
Definition bslmf_istriviallycopyable.h:324