BDE 4.14.0 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/// Note that this class is not value semantic and does not own any of its
279/// pointer values. The owner of the arguments used to set the value of a
280/// `ElementAttribute` is responsible for ensuring that the values remain
281/// valid or else must document the conditions that will make the values
282/// invalid. Some facets are computed the first time that they are needed.
283/// To avoid extra processing, the caller may supply otherwise-computed
284/// facets at construction or by calling `reset`. Facets provided by the
285/// caller are not checked to ensure that they are consistent with one
286/// another.
287///
288/// See @ref balxml_elementattribute
290
291 // MEMBER VARIABLES
292
293 // Mutable members may be used to cache computed results.
294 const PrefixStack *d_prefixStack; // Held, not owned
295 const char *d_qualifiedName; // Held, not owned
296 const char *d_value; // Held, not owned
297 mutable const char *d_prefix; // Held, not owned
298 mutable const char *d_localName; // Held, not owned
299 mutable int d_namespaceId;
300 mutable const char *d_namespaceUri; // Held, not owned
301 unsigned d_flags;
302
303 public:
304 // FLAGS
305
306 // The flags property should be set to the bitwise-OR of one or more of
307 // the following values:
308 enum {
309 /// No flags set.
311
312 /// Set this bit if the value for this attribute object was
313 /// generated from the default attribute value in the DTD or
314 /// schema.
316
317 /// Set this bit if this attribute represents a namespace
318 /// declaration.
320
321 /// Set this bit if this attribute represents a XML schema instance
322 /// declaration.
323 k_ATTR_IS_XSIDECL = 0x0004
324
325#ifndef BDE_OMIT_INTERNAL_DEPRECATED
333#endif // BDE_OMIT_INTERNAL_DEPRECATED
334 };
335
336 // TRAITS
339
340 // PUBLIC CREATORS
341
342 /// Construct a null attribute object: Set all string facets to zero,
343 /// the namespace ID to `INT_MIN`, and flags to zero.
345
346 /// Construct an attribute object with the specified, `prefixStack`,
347 /// `qualifiedName`, and `value`, with optionally specified `prefix`,
348 /// `localName`, `namespaceId`, `namespaceUri`, and `flags`. Except
349 /// for `flags`, if any of the optional arguments are null (for
350 /// pointers) or `INT_MIN` (for integer arguments), then the
351 /// corresponding facet will computed from the other arguments on an
352 /// as-needed basis. If all of the optional arguments are given
353 /// non-null, non-`INT_MIN` values, then `prefixStack` is unused and
354 /// may be null. Arguments are permitted to be inconsistent with one
355 /// another (e.g., `prefix` may not match the beginning of
356 /// `qualifiedName`) and will produce an object for with facets that
357 /// are inconsistent with one another. The constructed object will
358 /// become invalid if any of the supplied pointers is invalidated
359 /// during its lifetime (or before it is reset). An invalid object may
360 /// be destroyed or reset, but any other access yields undefined
361 /// behavior.
363 const char *qualifiedName,
364 const char *value,
365 const char *prefix = 0,
366 const char *localName = 0,
367 int namespaceId = INT_MIN,
368 const char *namespaceUri = 0,
369 unsigned flags = 0);
370
371#ifdef DOXYGEN
372 // For efficiency, use compiler-generated copy constructor, destructor,
373 // and assignment, but document them as though they were explicitly
374 // declared:
375
377 // Construct a copy of the specified 'other' attribute object. The
378 // copy will have pointers to the same strings and prefix table as
379 // 'other'.
380
382 // Destroy this attribute object. The targets of the pointers used to
383 // construct or reset this object are not owned by this object and are
384 // not deallocated. It is safe to destroy a 'ElementAttribute'
385 // object that is in an invalid state.
386
387 ElementAttribute operator=(const ElementAttribute& rhs);
388 // Assign this attribute object the value of 'rhs'. This object will
389 // have pointers to the same strings and prefix table as 'other'.
390#endif
391
392 /// Reset this object to the default-constructed state.
393 void reset();
394
395 /// Reset this attribute object with the specified, `prefixStack`,
396 /// `qualifiedName`, and `value`, with optionally specified `prefix`,
397 /// `localName`, `namespaceId`, `namespaceUri`, and `flags`. Except
398 /// for `flags`, if any of the optional arguments are null (for
399 /// pointers) or `INT_MIN` (for integer arguments), then the
400 /// corresponding facet will computed from the other arguments on an
401 /// as-needed basis. If all of the optional arguments are given
402 /// non-null, non-`INT_MIN` values, then `prefixStack` is unused and
403 /// may be null. Arguments are permitted to be inconsistent with one
404 /// another (e.g., `prefix` may not match the beginning of
405 /// `qualifiedName`) and will produce an object for with facets that
406 /// are inconsistent with one another. This object will become invalid
407 /// if any of the supplied pointers is invalidated during its lifetime
408 /// (or before it is reset). An invalid object may be destroyed or
409 /// reset, but any other access yields undefined behavior.
411 const char *qualifiedName,
412 const char *value,
413 const char *prefix = 0,
414 const char *localName = 0,
415 int namespaceId = INT_MIN,
416 const char *namespaceUri = 0,
417 unsigned flags = 0);
418
419 // ACCESSORS
420
421 /// Return the value of `prefixStack` specified at the last call to
422 /// `reset` or the constructor or 0 if no prefix stack was specified.
423 const PrefixStack *prefixStack() const;
424
425 /// Return the value of `qualifiedName` specified at the last call to
426 /// `reset` or the constructor or 0 if no qualified name was specified.
427 const char *qualifiedName() const;
428
429 /// Return the value of `value` specified at the last call to `reset`
430 /// or the constructor or 0 if no value was specified.
431 const char *value() const;
432
433 /// Return the value of `prefix` specified at the last call to `reset`
434 /// or the constructor, if non-zero, else return a copy of the prefix
435 /// portion of the qualified name. More precisely, return a copy of
436 /// the portion of `qualifiedName()` up to, but not including, the
437 /// colon. Return an empty string if the qualified name has no colon
438 /// or if `prefixStack()` returns zero.
439 const char *prefix() const;
440
441 /// Return the value of `localName` specified at the last call to
442 /// `reset` or the constructor, if non-zero, else return the local part
443 /// of the qualified name. More precisely, return the portion of
444 /// `qualifiedName()` after the colon, if any, or the entire
445 /// `qualifiedName()` if there is no colon.
446 const char *localName() const;
447
448 /// Return the value of `localName` specified at the last call to
449 /// `reset` or the constructor, if not `INT_MIN`, else return the ID
450 /// returned by the prefix stack for the current value of `prefix()`.
451 /// Return -1 if `prefix()` is an empty string, `prefixStack()` is
452 /// zero, or `prefix()` is not active in the prefix stack. Note that,
453 /// as per the XML namespace standard, an empty prefix does *NOT* refer
454 /// to the default namespace, but rather refers to *NO* namespace.
455 int namespaceId() const;
456
457 /// Return the value of `namespaceUri` specified at the last call to
458 /// `reset` or the constructor, if non-zero, else return the URI
459 /// returned by the prefix stack for the current value of `prefix()`.
460 /// Return an empty string if `prefix()` is an empty string,
461 /// `prefixStack()` is zero, or `prefix()` is not active in the prefix
462 /// stack. Note that, as per the XML namespace standard, an empty
463 /// prefix does *NOT* refer to the default namespace, but rather refers
464 /// to *NO* namespace.
465 const char *namespaceUri() const;
466
467 /// Return the value of `flags` specified at the last call to `reset`
468 /// or the constructor, if non-zero, or zero otherwise. Pre-defined
469 /// flags are enumerated in the class definition.
470 unsigned flags() const;
471
472 /// Return true if this object is null. More precisely, return true if
473 /// `qualifiedName()` returns 0. A default-constructed object will be
474 /// null, as will an object that was reset with no arguments.
475 bool isNull() const;
476
477 /// Format this object to the specified output `stream` at the
478 /// (absolute value of) the optionally specified indentation `level`
479 /// and return a reference to `stream`. If `level` is specified,
480 /// optionally specify `spacesPerLevel`, the number of spaces per
481 /// indentation level for this and all of its nested objects. If
482 /// `level` is negative, suppress indentation of the first line. If
483 /// `spacesPerLevel` is negative, format the entire output on one line.
484 /// If `stream` is not valid on entry, this operation has no effect.
485 /// Facet values that have not yet been computed are represented by
486 /// "<null>" in the resulting stream.
487 bsl::ostream& print(bsl::ostream& stream,
488 int level = 0,
489 int spacesPerLevel = 4) const;
490};
491
492// FREE OPERATORS
493
494/// Write the contents of the specified `attribute` object to the specified
495/// `os` in human-readable form. Attributes that have not yet been
496/// computed are not computed by this function.
497inline
498bsl::ostream& operator<<(bsl::ostream& os,
499 const ElementAttribute& attribute);
500
501// ============================================================================
502// INLINE DEFINITIONS
503// ============================================================================
504
505 // ----------------------
506 // class ElementAttribute
507 // ----------------------
508
509// ACCESSORS
510inline
512{
513 return d_prefixStack;
514}
515
516inline
518{
519 return d_qualifiedName;
520}
521
522inline
523const char *ElementAttribute::value() const
524{
525 return d_value;
526}
527
528inline
530{
531 return d_flags;
532}
533
534inline
536{
537 return 0 == d_qualifiedName;
538}
539
540} // close package namespace
541
542// FREE OPERATORS
543inline
544bsl::ostream& balxml::operator<<(bsl::ostream& os,
545 const ElementAttribute& attribute)
546{
547 return attribute.print(os);
548}
549
550
551
552#endif
553
554// ----------------------------------------------------------------------------
555// Copyright 2015 Bloomberg Finance L.P.
556//
557// Licensed under the Apache License, Version 2.0 (the "License");
558// you may not use this file except in compliance with the License.
559// You may obtain a copy of the License at
560//
561// http://www.apache.org/licenses/LICENSE-2.0
562//
563// Unless required by applicable law or agreed to in writing, software
564// distributed under the License is distributed on an "AS IS" BASIS,
565// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
566// See the License for the specific language governing permissions and
567// limitations under the License.
568// ----------------------------- END-OF-FILE ----------------------------------
569
570/** @} */
571/** @} */
572/** @} */
Definition balxml_elementattribute.h:289
const PrefixStack * prefixStack() const
Definition balxml_elementattribute.h:511
const char * prefix() const
const char * localName() const
@ BAEXML_ATTR_IS_NSDECL
Definition balxml_elementattribute.h:328
@ ATTR_IS_DEFAULT
Definition balxml_elementattribute.h:331
@ BAEXML_ATTR_IS_XSIDECL
Definition balxml_elementattribute.h:329
@ ATTR_IS_NSDECL
Definition balxml_elementattribute.h:332
@ BAEXML_ATTR_NO_FLAGS
Definition balxml_elementattribute.h:326
@ k_ATTR_NO_FLAGS
No flags set.
Definition balxml_elementattribute.h:310
@ k_ATTR_IS_DEFAULT
Definition balxml_elementattribute.h:315
@ k_ATTR_IS_NSDECL
Definition balxml_elementattribute.h:319
@ k_ATTR_IS_XSIDECL
Definition balxml_elementattribute.h:323
@ ATTR_NO_FLAGS
Definition balxml_elementattribute.h:330
@ BAEXML_ATTR_IS_DEFAULT
Definition balxml_elementattribute.h:327
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:517
void reset()
Reset this object to the default-constructed state.
unsigned flags() const
Definition balxml_elementattribute.h:529
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:523
bool isNull() const
Definition balxml_elementattribute.h:535
Definition balxml_prefixstack.h:137
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition balxml_base64parser.h:150
bsl::ostream & operator<<(bsl::ostream &stream, const ConfigSchema &schema)
Definition bslmf_istriviallycopyable.h:329