Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
Variant/XML/Reader.cpp
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#include "Stroika/Foundation/StroikaPreComp.h"
5
6#include <charconv>
7#include <cmath>
8
9#include "Stroika/Foundation/Characters/FloatConversion.h"
12#include "Stroika/Foundation/Containers/Mapping.h"
13#include "Stroika/Foundation/Containers/Sequence.h"
14#include "Stroika/Foundation/Containers/Set.h"
15#include "Stroika/Foundation/DataExchange/BadFormatException.h"
18#include "Stroika/Foundation/Execution/Exceptions.h"
19#include "Stroika/Foundation/Execution/Throw.h"
23#include "Stroika/Foundation/Streams/TextToBinary.h"
26
27#include "Reader.h"
28
29using std::byte;
30
31using namespace Stroika::Foundation;
35using namespace Stroika::Foundation::DataExchange::XML;
36using namespace Stroika::Foundation::DataExchange::Variant::XML;
37
39using Memory::MakeSharedPtr;
40
41// Comment this in to turn on aggressive noisy DbgTrace in this module
42//#define USE_NOISY_TRACE_IN_THIS_MODULE_ 1
43
44#if qStroika_Foundation_DataExchange_XML_SupportParsing
45namespace {
46 // whether the Binding names a member written as an element (or attribute) of that name - which the element then is, whatever
47 // else its name could make it (an item of an array). A presence marker is an element
48 bool NamesMember_ (const Binding* binding, Binding::Kind kind, const String& name)
49 {
50 auto isElement = [] (Binding::Kind k) { return k == Binding::Kind::eElement or k == Binding::Kind::ePresenceMarker; };
51 return binding != nullptr and binding->fMembers.Any ([&] (const Binding::Member& m) {
52 Binding::Kind k = binding->KindFor (m.fKey);
53 return (isElement (kind) ? isElement (k) : k == kind) and binding->NameFor (m.fKey).fName == name;
54 });
55 }
56
57 // what reading does with an element or attribute the Binding of the element it is in does not declare - and an array or a
58 // leaf the Binding declares has no members to declare, so none to keep: an array's Binding can say to skip what is not its
59 // item, and otherwise it is refused
60 Binding::UndeclaredMembers UndeclaredIn_ (const Binding* binding)
61 {
62 if (binding == nullptr) {
63 return Binding::UndeclaredMembers::eKeep;
64 }
65 if (binding->fType and binding->fType != VariantValue::eMap) {
66 if (binding->fType == VariantValue::eArray and binding->fUndeclaredMembers == Binding::UndeclaredMembers::eSkip) {
67 return Binding::UndeclaredMembers::eSkip;
68 }
69 return Binding::UndeclaredMembers::eReject;
70 }
71 return binding->GetUndeclaredMembers ();
72 }
73
74 template <typename INT>
75 optional<INT> ParseInteger_ (const String& text)
76 {
77 if (optional<string> s = text.AsASCIIQuietly ()) {
78 INT r{};
79 auto [ptr, ec] = from_chars (s->data (), s->data () + s->size (), r);
80 if (ec == errc{} and ptr == s->data () + s->size ()) {
81 return r;
82 }
83 }
84 return nullopt;
85 }
86
87 // text read back as the leaf type a Binding declares - throwing where it is not one, the document then not being what the
88 // Binding describes. Whitespace around a number, date or BLOB is dropped, as XML Schema collapses it
89 VariantValue AsDeclaredType_ (const String& text, VariantValue::Type type)
90 {
91 String trimmed = text.Trim ();
92 switch (type) {
93 case VariantValue::eString:
94 return VariantValue{text};
95 case VariantValue::eBoolean:
96 // as XML Schema's xs:boolean
97 if (trimmed == "true"sv or trimmed == "1"sv) {
98 return VariantValue{true};
99 }
100 if (trimmed == "false"sv or trimmed == "0"sv) {
101 return VariantValue{false};
102 }
103 break;
104 case VariantValue::eInteger:
105 if (optional<long long> i = ParseInteger_<long long> (trimmed)) {
106 return VariantValue{*i};
107 }
108 break;
109 case VariantValue::eUnsignedInteger:
110 if (optional<unsigned long long> i = ParseInteger_<unsigned long long> (trimmed)) {
111 return VariantValue{*i};
112 }
113 break;
114 case VariantValue::eFloat: {
115 long double d = FloatConversion::ToFloat<long double> (trimmed); // nan where it is not a number at all
116 if (not isnan (d) or trimmed.ToLowerCase ().Find ("nan"sv)) {
117 return VariantValue{d};
118 }
119 } break;
120 case VariantValue::eDate:
122 case VariantValue::eDateTime:
123 return VariantValue{Time::DateTime::Parse (trimmed, Time::DateTime::kISO8601Format)};
124 case VariantValue::eBLOB:
125 return VariantValue{VariantValue{trimmed}.As<Memory::BLOB> ()}; // base64, as the Writer writes it
126 default:
127 break; // not a leaf
128 }
129 Execution::Throw (BadFormatException{"'{}' is not {}"_f(text, type)});
130 }
131
132 /*
133 * The inverse of Variant::XML::Writer (its documentation has the shape): an element with child elements is an object, one
134 * with only text is that text (a String - XML says nothing of types, so the reader types nothing), and children of one
135 * name are an array. An attribute reads as a member too, by its name, so that reading a document of someone else's does
136 * not silently drop it.
137 */
138 struct Builder_ : StructuredStreamEvents::IConsumer {
139 using Name = StructuredStreamEvents::Name;
140
141 Builder_ (const Binding& binding, bool lenient)
142 : fBinding{binding}
143 , fLenient{lenient}
144 {
145 }
146 const Binding& fBinding; // the top level Binding - with an fName, the document element's own (@see Binding)
147 const bool fLenient; // Reader::Options::fLenient: what the Binding cannot hold is passed over, not thrown
148
149 // text as the type a Binding declares - or, read leniently, nullopt where it is not one: absent, rather than thrown
150 optional<VariantValue> Declared_ (const String& text, VariantValue::Type type) const
151 {
152 if (fLenient) {
153 try {
154 return AsDeclaredType_ (text, type);
155 }
156 catch (...) {
157 return nullopt;
158 }
159 }
160 return AsDeclaredType_ (text, type);
161 }
162
163 struct Frame_ {
164 String fElement; // its local name
165 String fKey; // the member it is: its own name, unless a Binding renamed it
166 const Binding* fBinding{nullptr}; // how its content differs from the default shape
167 const Binding* fDefaultArrayItems{&Binding::kDefaultArrayItems}; // the item Binding, here, of an array with no fItems
168 bool fIsItem{false}; // an item of the array the element it is in wraps - so not a member of it
169 bool fIsRepeatedItem{false}; // one of a member's elements, repeated: a Binding says the member is an array
170 bool fIsBoundArray{false}; // a Binding says it wraps an array - so it is one, however few items it has
171 bool fHasChildElements{false}; // any child element - an array item or a member - not merely attributes
172 bool fIsPresenceMarker{false}; // a presence marker (Binding::Kind::ePresenceMarker): an empty element, true by being there
173 optional<String> fItemName; // what the items of an array it wraps are called, where it may wrap one
174 const Binding* fItemBinding{nullptr}; // ... and their Binding
175 StringBuilder<> fText;
177 Set<String> fRepeated; // a name seen more than once, so fChildren holds its array
178 Sequence<VariantValue> fArrayItems; // its children named fItemName
179 };
180 vector<Frame_> fStack;
181 String fRootKey;
182 optional<VariantValue> fRootValue;
183 unsigned int fSkipDepth_{0}; // inside an element being skipped (Binding::UndeclaredMembers::eSkip): how deep
184
185 virtual void StartElement (const Name& name, const Mapping<Name, String>& attributes) override
186 {
187 if (fSkipDepth_ > 0) {
188 ++fSkipDepth_; // inside an element being skipped
189 return;
190 }
191 // what an element is, its own Binding says - and what it is inside says which Binding that is
192 Frame_ f;
193 const Binding* ownBinding = nullptr;
194 f.fElement = name.fLocalName;
195 if (fStack.empty ()) {
196 if (fBinding.fName) {
197 // it names the document element, so it is that element's - and a document element of another name is not what
198 // it describes. By local name, as every member is matched
199 if (name.fLocalName != fBinding.fName->fName) {
201 "the document element is <{}>, where the Binding names <{}>"_f(name.fLocalName, fBinding.fName->fName)});
202 }
203 ownBinding = &fBinding;
204 }
205 else {
206 // the document element is the value's one member, so its key and Binding are that member's
207 f.fKey = fBinding.KeyForName (Binding::Kind::eElement, name.fLocalName);
208 ownBinding = fBinding.MemberBinding (f.fKey);
209 if (fBinding.fDefaultArrayItems != nullptr) {
210 f.fDefaultArrayItems = fBinding.fDefaultArrayItems.get ();
211 }
212 }
213 }
214 else {
215 const Frame_& parent = fStack.back ();
216 f.fDefaultArrayItems = parent.fDefaultArrayItems;
217 if (parent.fItemName and name.fLocalName == *parent.fItemName and
218 not NamesMember_ (parent.fBinding, Binding::Kind::eElement, name.fLocalName)) {
219 f.fIsItem = true;
220 ownBinding = parent.fItemBinding;
221 }
222 else {
223 // one its parent's Binding does not declare (an array's items are, above): as that Binding says
224 if (not NamesMember_ (parent.fBinding, Binding::Kind::eElement, name.fLocalName)) {
225 switch (UndeclaredIn_ (parent.fBinding)) {
226 case Binding::UndeclaredMembers::eReject:
227 if (not fLenient) {
228 Execution::Throw (BadFormatException{"<{}> is not an element its parent's Binding declares"_f(name.fLocalName)});
229 }
230 [[fallthrough]]; // read leniently, skipped - even inside a leaf, as markup in its text
231 case Binding::UndeclaredMembers::eSkip:
232 fSkipDepth_ = 1; // it, and everything in it, unread
233 return;
234 case Binding::UndeclaredMembers::eKeep:
235 break;
236 }
237 }
238 f.fKey = parent.fBinding == nullptr ? name.fLocalName : parent.fBinding->KeyForName (Binding::Kind::eElement, name.fLocalName);
239 ownBinding = parent.fBinding == nullptr ? nullptr : parent.fBinding->MemberBinding (f.fKey);
240 }
241 }
242 if (ownBinding != nullptr and ownBinding->fDefaultArrayItems != nullptr) {
243 f.fDefaultArrayItems = ownBinding->fDefaultArrayItems.get ();
244 }
245 // its items' Binding, where its own says it is an array: fItems - else, where it declares an array, the default items
246 // in scope, as the Writer takes them
247 const Binding* items = nullptr;
248 if (ownBinding != nullptr) {
249 items = ownBinding->fItems != nullptr ? ownBinding->fItems.get ()
250 : ownBinding->fType == VariantValue::eArray ? f.fDefaultArrayItems
251 : nullptr;
252 }
253 f.fBinding = ownBinding;
254 f.fIsPresenceMarker = ownBinding != nullptr and ownBinding->fKind == Binding::Kind::ePresenceMarker;
255 if (items != nullptr and not items->fName) {
256 // items with no name of their own are the member's element, repeated: this is one of them, so the item
257 // Binding is what its content has
258 f.fIsRepeatedItem = true;
259 f.fBinding = items;
260 }
261 if (f.fBinding != ownBinding and f.fBinding->fDefaultArrayItems != nullptr) {
262 f.fDefaultArrayItems = f.fBinding->fDefaultArrayItems.get ();
263 }
264 // what the items of an array it wraps are called: as its Binding says, else as the default array items in scope do -
265 // and none, where its Binding declares an object or a leaf
266 bool declaresNoArray = f.fBinding != nullptr and f.fBinding->fType and f.fBinding->fType != VariantValue::eArray;
267 if (f.fBinding != nullptr and f.fBinding->fItems != nullptr) {
268 if (f.fBinding->fItems->fName) {
269 f.fIsBoundArray = true;
270 f.fItemName = f.fBinding->fItems->fName->fName;
271 f.fItemBinding = f.fBinding->fItems.get ();
272 }
273 }
274 else if (f.fDefaultArrayItems->fName and not declaresNoArray) {
275 f.fItemName = f.fDefaultArrayItems->fName->fName;
276 f.fItemBinding = f.fDefaultArrayItems;
277 }
278 fStack.push_back (move (f));
279 Frame_& top = fStack.back ();
280 for (const auto& i : attributes) {
281 if (not NamesMember_ (top.fBinding, Binding::Kind::eAttribute, i.fKey.fLocalName)) {
282 switch (UndeclaredIn_ (top.fBinding)) {
283 case Binding::UndeclaredMembers::eReject:
284 if (not fLenient) {
286 "<{}>'s attribute '{}' is not one its Binding declares"_f(name.fLocalName, i.fKey.fLocalName)});
287 }
288 continue; // read leniently, skipped
289 case Binding::UndeclaredMembers::eSkip:
290 continue;
291 case Binding::UndeclaredMembers::eKeep:
292 break;
293 }
294 }
295 String key = top.fBinding == nullptr ? i.fKey.fLocalName : top.fBinding->KeyForName (Binding::Kind::eAttribute, i.fKey.fLocalName);
296 const Binding* attrBinding = top.fBinding == nullptr ? nullptr : top.fBinding->MemberBinding (key);
297 if (attrBinding == nullptr or not attrBinding->fType) {
298 AddMember_ (top, key, VariantValue{i.fValue});
299 }
300 else if (optional<VariantValue> v = Declared_ (i.fValue, *attrBinding->fType)) {
301 AddMember_ (top, key, *v);
302 }
303 }
304 }
305 virtual void TextInsideElement (const String& text) override
306 {
307 if (not fStack.empty () and fSkipDepth_ == 0) {
308 fStack.back ().fText << text;
309 }
310 }
311 virtual void EndElement ([[maybe_unused]] const Name& name) override
312 {
313 if (fSkipDepth_ > 0) {
314 --fSkipDepth_;
315 return;
316 }
317 Require (not fStack.empty ());
318 Frame_ f = move (fStack.back ());
319 fStack.pop_back ();
320 optional<VariantValue> v = ValueOf_ (f);
321 if (fStack.empty ()) {
322 fRootKey = f.fKey;
323 VariantValue root = v.value_or (VariantValue{});
324 fRootValue = f.fIsRepeatedItem ? VariantValue{Sequence<VariantValue>{root}} : root; // a document has one root element
325 return;
326 }
327 Frame_& parent = fStack.back ();
328 parent.fHasChildElements = true;
329 if (not v) {
330 return; // read leniently, a value not of its declared type: absent
331 }
332 if (f.fIsItem) {
333 parent.fArrayItems.Append (*v);
334 }
335 else if (f.fIsRepeatedItem) {
336 // a Binding says the member is an array, so it is one however few elements the document has
338 if (optional<VariantValue> already = parent.fChildren.Lookup (f.fKey)) {
339 items = already->As<Sequence<VariantValue>> ();
340 }
341 items.Append (*v);
342 parent.fChildren.Add (f.fKey, VariantValue{items});
343 }
344 else {
345 AddMember_ (parent, f.fKey, *v);
346 }
347 }
348 // a member - and a name seen again makes it the array of them, in document order; but not where the element's Binding
349 // declares its type, which says what each member is (one its own Binding says is an array, its element repeated, is not
350 // added here: EndElement)
351 void AddMember_ (Frame_& f, const String& key, const VariantValue& v)
352 {
353 if (optional<VariantValue> already = f.fChildren.Lookup (key)) {
354 if (f.fBinding != nullptr and f.fBinding->fType) {
355 if (fLenient) {
356 f.fChildren.Add (key, v); // read leniently, the last
357 return;
358 }
359 Execution::Throw (BadFormatException{"<{}> has '{}' more than once, where its Binding declares one"_f(f.fElement, key)});
360 }
361 Sequence<VariantValue> items = f.fRepeated.Contains (key) ? already->As<Sequence<VariantValue>> () : Sequence<VariantValue>{*already};
362 items.Append (v);
363 f.fChildren.Add (key, VariantValue{items});
364 f.fRepeated.Add (key);
365 }
366 else {
367 f.fChildren.Add (key, v);
368 }
369 }
370 // its value - nullopt only read leniently, where it is not of its declared type, so is absent
371 optional<VariantValue> ValueOf_ (Frame_& f)
372 {
373 String text = f.fText.str ();
374 bool textBlank = text.Trim ().empty ();
375 optional<VariantValue::Type> declared = f.fBinding == nullptr ? nullopt : f.fBinding->fType;
376 if (f.fIsPresenceMarker) {
377 // there, so true: it says so by being there, and says nothing else - read leniently, whatever is in it passed over
378 if (not fLenient and (not f.fChildren.empty () or f.fHasChildElements or not textBlank)) {
379 Execution::Throw (BadFormatException{"<{}> is a presence marker (Binding::Kind::ePresenceMarker), so an empty element"_f(f.fElement)});
380 }
381 return VariantValue{true};
382 }
383 if (declared and *declared != VariantValue::eMap) {
384 // its Binding says what it is - and StartElement has let in no child element or attribute it does not declare
385 Assert (*declared == VariantValue::eArray or f.fChildren.empty ());
386 if (*declared == VariantValue::eArray) {
387 if (not fLenient and (not f.fChildren.empty () or not textBlank)) {
388 Execution::Throw (BadFormatException{"<{}> is not an array, as its Binding declares"_f(f.fElement)});
389 }
390 return VariantValue{f.fArrayItems}; // [] where it is empty - read leniently, text beside its items passed over
391 }
392 return Declared_ (text, *declared);
393 }
394 if (f.fIsBoundArray and f.fChildren.empty () and textBlank) {
395 return VariantValue{f.fArrayItems}; // a Binding says it is an array, so it is one - of no items, if it is empty
396 }
397 if (not f.fArrayItems.empty () and f.fChildren.empty () and textBlank) {
398 return VariantValue{f.fArrayItems}; // all its children were array items, so the element IS the array
399 }
400 if (not f.fArrayItems.empty ()) {
401 // ... beside other members, or text: just a member
402 AddMember_ (f, *f.fItemName, VariantValue{f.fArrayItems});
403 f.fArrayItems.clear ();
404 }
405 // a presence marker its Binding declares, absent, is false - as a false one is written: as nothing
406 if (f.fBinding != nullptr) {
407 for (const Binding::Member& m : f.fBinding->fMembers) {
408 if (f.fBinding->KindFor (m.fKey) == Binding::Kind::ePresenceMarker and not f.fChildren.ContainsKey (m.fKey)) {
409 f.fChildren.Add (m.fKey, VariantValue{false});
410 }
411 }
412 }
413 static const auto kMixedContent_ = BadFormatException{"mixed content (text beside child elements) cannot be read into a VariantValue"sv};
414 // a Binding may say this element's text is one of its members, beside its attributes - an empty one, where that member's
415 // Binding declares its type, written as none, so absent
416 if (optional<String> textKey = f.fBinding == nullptr ? nullopt : f.fBinding->TextMemberKey ()) {
417 if (f.fHasChildElements) {
418 // ... but not beside child elements, which is mixed content - the whitespace of a pretty-printed document aside,
419 // which is no text at all - read leniently, passed over
420 if (not textBlank and not fLenient) {
421 Execution::Throw (kMixedContent_);
422 }
423 return VariantValue{f.fChildren};
424 }
425 const Binding* textBinding = f.fBinding->MemberBinding (*textKey);
426 if (textBinding == nullptr or not textBinding->fType) {
427 f.fChildren.Add (*textKey, VariantValue{text});
428 }
429 else if (not text.empty ()) {
430 if (optional<VariantValue> v = Declared_ (text, *textBinding->fType)) {
431 f.fChildren.Add (*textKey, *v);
432 }
433 }
434 return VariantValue{f.fChildren};
435 }
436 if (f.fChildren.empty () and declared != VariantValue::eMap) {
437 return VariantValue{text}; // text, kept as it came: XML whitespace is significant
438 }
439 if (fLenient) {
440 return VariantValue{f.fChildren}; // read leniently, text it has nowhere for passed over
441 }
442 if (f.fChildren.empty () and not textBlank) {
443 Execution::Throw (BadFormatException{"<{}> has text, where its Binding declares an object"_f(f.fElement)});
444 }
445 if (not textBlank) {
446 // text this shape cannot hold, which reading on would silently drop - so say so, rather than lose it (it comes
447 // from the document, not from any caller's mistake). Beside attributes alone, a Binding could have held it
448 if (f.fHasChildElements) {
449 Execution::Throw (kMixedContent_);
450 }
451 static const auto kTextBesideAttributes_ = BadFormatException{
452 "text beside attributes cannot be read into a VariantValue with no Binding member for it (Binding::Kind::eText)"sv};
453 Execution::Throw (kTextBesideAttributes_);
454 }
455 return VariantValue{f.fChildren};
456 }
457 };
458}
459#endif
460
461class Variant::XML::Reader::Rep_ final : public Variant::Reader::_IRep, public Memory::UseBlockAllocationIfAppropriate<Rep_> {
462public:
463 Rep_ (const Options& options)
464 : fOptions_{options}
465 {
466 }
467
468public:
469 virtual optional<filesystem::path> GetDefaultFileSuffix () const override
470 {
471 return ".xml"sv;
472 }
473 virtual VariantValue Read ([[maybe_unused]] const Streams::InputStream::Ptr<byte>& in) const override
474 {
475#if qStroika_Foundation_DataExchange_XML_SupportParsing
476 Builder_ builder{fOptions_.fBinding, fOptions_.fLenient};
477 SAXParse (in, &builder, fOptions_.fValidateAgainst, nullptr, fOptions_.fXMLOptions);
478 if (not builder.fRootValue) {
479 static const auto kException_ = BadFormatException{"no root element"sv};
480 Execution::Throw (kException_);
481 }
482 // as the Writer has it: with the document element named, its content is the value; else the value is the object it is
483 // the one member of
484 return fOptions_.fBinding.fName ? *builder.fRootValue : VariantValue{Mapping<String, VariantValue> {
485 { builder.fRootKey,
486 *builder.fRootValue }
487 }};
488#else
489 static const Execution::Exception<runtime_error> kException_{
490 "Variant::XML::Reader requires an XML parser (qStroika_Foundation_DataExchange_XML_SupportParsing)"sv};
491 Execution::Throw (kException_);
492#endif
493 }
494 virtual VariantValue Read (const Streams::InputStream::Ptr<Character>& in) const override
495 {
496 // SAXParse reads bytes - so write the characters back out as UTF-8 for it
497 return Read (Streams::TextToBinary::Reader::New (in));
498 }
499
500private:
501 Options fOptions_;
502};
503
504#if qCompilerAndStdLib_default_member_initializer_needed_within_enclosing_class_Buggy
505Variant::XML::Reader::Reader ()
506 : Reader{Options{}}
507{
508}
509#endif
510
511Variant::XML::Reader::Reader (const Options& options)
512 : inherited{MakeSharedPtr<Rep_> (options)}
513{
514}
515
516Variant::XML::Reader::Reader (const Binding& binding)
517 : Reader{Options{.fBinding = binding}}
518{
519}
auto MakeSharedPtr(ARGS_TYPE &&... args) -> shared_ptr< T >
same as make_shared, but if type T has block allocation, then use block allocation for the 'shared pa...
conditional_t< qStroika_Foundation_Memory_PreferBlockAllocation and andTrueCheck, BlockAllocationUseHelper< T >, Common::Empty > UseBlockAllocationIfAppropriate
Use this to enable block allocation for a particular class. Beware of subclassing.
void SAXParse(const Providers::ISAXProvider &saxProvider, const Streams::InputStream::Ptr< byte > &in, StructuredStreamEvents::IConsumer *callback=nullptr, const Schema::Ptr &schema=nullptr, Execution::ProgressMonitor::Updater progress=nullptr)
Definition SAXReader.cpp:45
Similar to String, but intended to more efficiently construct a String. Mutable type (String is large...
String is like std::u32string, except it is much easier to use, often much more space efficient,...
Definition String.h:201
nonvirtual String ToLowerCase() const
Definition String.cpp:1765
nonvirtual String Trim(bool(*shouldBeTrimmed)(Character)=Character::IsWhitespace) const
Definition String.cpp:1651
nonvirtual optional< T > AsASCIIQuietly() const
nonvirtual optional< size_t > Find(Character c, CompareOptions co=eWithCase) const
Definition String.inl:687
A Mapping uniquely associates two elements: a key and a value (use Assocation to allow multiple value...
A generalization of a vector: a container whose elements are keyed by the natural numbers.
nonvirtual void As(CONTAINER_OF_ADDABLE *into) const
write this Sequence into an existing container
nonvirtual void Append(ArgByValueType< value_type > item)
Definition Sequence.inl:615
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
virtual void StartElement(const Name &name, const Mapping< Name, String > &attributes)
Definition IConsumer.cpp:24
Read XML as a VariantValue - the inverse of Variant::XML::Writer, whose documentation has the shape.
Simple variant-value (case variant union) object, with (variant) basic types analogous to a value in ...
Exception<> is a replacement (subclass) for any std c++ exception class (e.g. the default 'std::excep...
Definition Exceptions.h:219
InputStream<>::Ptr is Smart pointer (with abstract Rep) class defining the interface to reading from ...
static constexpr string_view kISO8601Format
Y-M-D format - locale independent, and ISO-8601 date format standard.
Definition Date.h:465
static Date Parse(const String &rep, const locale &l=locale{})
Definition Date.inl:316
void Throw(T &&e2Throw)
like the builtin C++ 'throw', but stamps in the current Activity context and does helpful,...
Definition Throw.inl:54
One member of an object: its key, and how that member differs from the default shape (nothing,...
Definition Binding.h:93
How a VariantValue is to be written as XML, and read back, where the default shape (.
Definition Binding.h:88
nonvirtual String KeyForName(Kind kind, const String &name) const
Reading: the key of the member of that kind (an element - or presence marker - or an attribute) writt...
Definition Binding.cpp:226
static const Binding kDefaultArrayItems
The Binding each item of an array is written with where neither fItems nor fDefaultArrayItems gives o...
Definition Binding.h:278
nonvirtual Kind KindFor(const String &key) const
That member's kind: its Binding's, else an element.
Definition Binding.cpp:220
nonvirtual UndeclaredMembers GetUndeclaredMembers() const
fUndeclaredMembers, or its default: eReject where fType is declared, eKeep where not
Definition Binding.cpp:246
UndeclaredMembers
What an object does with a member fMembers does not declare - an element or attribute in a document,...
Definition Binding.h:170
nonvirtual const Binding * MemberBinding(const String &key) const
The Binding for the member of this object with that key - nullptr where it has none,...
Definition Binding.cpp:202
shared_ptr< Binding > fDefaultArrayItems
The Binding each item of an array is written with, where the array's own Binding has no fItems: its f...
Definition Binding.h:271
How XML is read and written - for now, with which provider - taken last by each XML function (DOM::Do...