4#include "Stroika/Foundation/StroikaPreComp.h"
8#include "Stroika/Foundation/Containers/Set.h"
9#include "Stroika/Foundation/DataExchange/XML/WriterUtils.h"
17using namespace Stroika::Foundation::DataExchange::Variant::XML;
23 bool SameBinding_ (
const shared_ptr<Binding>& lhs,
const shared_ptr<Binding>& rhs)
25 return (lhs ==
nullptr or rhs ==
nullptr) ? lhs == rhs : *lhs == *rhs;
30 return t != VariantValue::eNull and t != VariantValue::eMap and t != VariantValue::eArray;
36 return k == Binding::Kind::eElement or k == Binding::Kind::ePresenceMarker;
52 return "{}: declares no fType"_f(where);
54 for (
const auto& i : b.fNamespacePrefixes) {
55 if (not DataExchange::XML::IsNCName (i.fValue)) {
56 return "{}: the prefix '{}' is not an XML name"_f(where, i.fValue);
59 prefixes.
Add (i.fKey, i.fValue);
62 case VariantValue::eNull:
63 return "{}: declares eNull, which no value but null has"_f(where);
64 case VariantValue::eMap: {
66 return "{}: an object (eMap) with fItems"_f(where);
69 return "{}: keeps the members it does not declare (eKeep), untyped"_f(where);
75 bool hasElements =
false;
77 String memberWhere =
"{}/{}"_f(where, m.fKey);
78 if (keys.Contains (m.fKey)) {
79 return "{}: listed twice in fMembers"_f(memberWhere);
82 if (m.fBinding ==
nullptr) {
83 return "{}: no Binding, so declares no fType"_f(memberWhere);
85 if (optional<String> why = WhyIncompleteAt_ (*m.fBinding, memberWhere, Place_::eMember, prefixes)) {
89 if (m.fBinding->fKind != Binding::Kind::eElement and not IsLeaf_ (*m.fBinding->fType)) {
90 return "{}: an attribute, text or presence marker that is not a leaf"_f(memberWhere);
92 if (m.fBinding->fKind == Binding::Kind::ePresenceMarker and m.fBinding->fType != VariantValue::eBoolean) {
93 return "{}: a presence marker (ePresenceMarker) that is not a Boolean"_f(memberWhere);
95 switch (m.fBinding->fKind) {
96 case Binding::Kind::eAttribute:
97 if (not DataExchange::XML::IsNCName (name.
fName) or (name.
fName ==
"xmlns"sv and not name.
fNamespace)) {
98 return "{}: '{}' is not an XML attribute name"_f(memberWhere, name.
fName);
101 return "{}: an attribute in a namespace with no prefix in scope (fNamespacePrefixes)"_f(memberWhere);
103 if (attributeNames.Contains (name.
fName)) {
104 return "{}: another attribute's local name too: '{}'"_f(memberWhere, name.
fName);
108 case Binding::Kind::eText:
110 return "{}: a second text member"_f(memberWhere);
115 if (not DataExchange::XML::IsNCName (name.
fName)) {
116 return "{}: '{}' is not an XML name"_f(memberWhere, name.
fName);
118 if (elementNames.Contains (name.
fName)) {
119 return "{}: another member's element's local name too: '{}'"_f(memberWhere, name.
fName);
126 if (hasText and hasElements) {
127 return "{}: a text member beside child elements (mixed content)"_f(where);
130 case VariantValue::eArray: {
132 return "{}: an array (eArray) with fMembers"_f(where);
134 if (b.
fItems ==
nullptr) {
135 return "{}: an array with no fItems"_f(where);
137 if (b.
fItems->fKind != Binding::Kind::eElement) {
138 return "{}[]: an array's item that is not an element"_f(where);
141 if (not DataExchange::XML::IsNCName (b.
fItems->fName->fName)) {
142 return "{}[]: '{}' is not an XML name"_f(where, b.
fItems->fName->fName);
145 else if (place != Place_::eMember) {
146 return "{}: an array of repeated elements that is not an object's member, so has no element of its own to repeat"_f(where);
148 if (optional<String> why = WhyIncompleteAt_ (*b.
fItems,
"{}[]"_f(where), Place_::eItem, prefixes)) {
154 return "{}: a leaf ({}) with fMembers or fItems"_f(where, *b.
fType);
174 , fBinding{Memory::MakeSharedPtr<
Binding> (binding)}
178bool Binding::Member::operator== (
const Member& rhs)
const
180 return fKey == rhs.fKey and SameBinding_ (fBinding, rhs.fBinding);
187 if (fBinding !=
nullptr) {
188 sb <<
": "sv << fBinding->ToString_ (
false);
206 return i.fBinding.get ();
223 return b ==
nullptr ? Kind::eElement : b->fKind;
239 if (i.fBinding !=
nullptr and i.fBinding->fKind == Kind::eText) {
253 return not WhyIncomplete_ ().has_value ();
256optional<String> Binding::WhyIncomplete_ ()
const
261 return String{
"the document element is not named (fName)"sv};
263 if (not DataExchange::XML::IsNCName (
fName->fName)) {
264 return "the document element's name '{}' is not an XML name"_f(
fName->fName);
266 if (fKind != Kind::eElement) {
267 return String{
"the document element is not an element (fKind)"sv};
269 return WhyIncompleteAt_ (*
this,
fName->fName, Place_::eDocument, {});
281 return ToString_ (
true);
284String Binding::ToString_ (
bool top)
const
289 case Kind::eAttribute:
295 case Kind::ePresenceMarker:
296 sb <<
"presence marker"sv;
303 sb <<
", Name: "sv << *
fName;
306 sb <<
", Type: "sv << *
fType;
314 sb <<
", UndeclaredMembers: reject"sv;
317 sb <<
", UndeclaredMembers: skip"sv;
320 sb <<
", UndeclaredMembers: keep"sv;
325 sb <<
", Items: "sv <<
fItems->ToString_ (
false);
334 if (optional<String> why = WhyIncomplete_ ()) {
335 sb <<
", Incomplete: "sv << *why;
338 sb <<
", Complete"sv;
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,...
A Mapping uniquely associates two elements: a key and a value (use Assocation to allow multiple value...
nonvirtual bool Add(ArgByValueType< key_type > key, ArgByValueType< mapped_type > newElt, AddReplaceMode addReplaceMode=AddReplaceMode::eAddReplaces)
nonvirtual bool ContainsKey(ArgByValueType< key_type > key) const
nonvirtual void RemoveAll()
RemoveAll removes all, or all matching (predicate, iterator range, equals comparer or whatever) items...
Set<T> is a container of T, where once an item is added, additionally adds () do nothing.
nonvirtual void Add(ArgByValueType< value_type > item)
Type
Enumeration of variant types.
One member of an object: its key, and how that member differs from the default shape (nothing,...
Member(const String &key)
the member's own key, and the default shape
nonvirtual String ToString() const
How a VariantValue is to be written as XML, and read back, where the default shape (.
bool operator==(const Binding &rhs) const
Equal where every field is - fItems and fDefaultArrayItems by the Bindings they point to,...
nonvirtual bool IsComplete() const
Whether, given this Binding as the top level Binding (the one a Reader or Writer is given),...
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...
static const Binding kDefaultArrayItems
The Binding each item of an array is written with where neither fItems nor fDefaultArrayItems gives o...
nonvirtual optional< String > TextMemberKey() const
Reading: the key of the member that is this element's text, if one is.
Sequence< Member > fMembers
nonvirtual Kind KindFor(const String &key) const
That member's kind: its Binding's, else an element.
nonvirtual NameWithNamespace NameFor(const String &key) const
The name that member is written with: its Binding's fName, else its own key.
optional< VariantValue::Type > fType
nonvirtual UndeclaredMembers GetUndeclaredMembers() const
fUndeclaredMembers, or its default: eReject where fType is declared, eKeep where not
UndeclaredMembers
What an object does with a member fMembers does not declare - an element or attribute in a document,...
nonvirtual String ToString() const
Mapping< URI, String > fNamespacePrefixes
A prefix for each of these namespaces, declared on this element (xmlns:p=) and used for every element...
shared_ptr< Binding > fItems
static const Binding kRepeatedArrayItems
An item Binding with no name, so no element of the items' own: the member's own element is repeated,...
optional< NameWithNamespace > fName
nonvirtual const Binding * MemberBinding(const String &key) const
The Binding for the member of this object with that key - nullptr where it has none,...
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...
optional< UndeclaredMembers > fUndeclaredMembers
An element's or attribute's name (local-name, not including a prefix), plus the namespace that name i...
String fName
The LOCAL name - "Why" for <x:Why>
optional< URI > fNamespace
The namespace fName is in, however the document said so - nullopt for a name in no namespace.