Stroika Library 3.0d25
 
Loading...
Searching...
No Matches
Variant/XML/Reader.h
Go to the documentation of this file.
1/*
2 * Copyright(c) Sophist Solutions, Inc. 1990-2026. All rights reserved
3 */
4#ifndef _Stroika_Foundation_DataExchange_Variant_XML_Reader_h_
5#define _Stroika_Foundation_DataExchange_Variant_XML_Reader_h_ 1
6
7#include "Stroika/Foundation/StroikaPreComp.h"
8
9#include "Stroika/Foundation/Common/Common.h"
15
17
18/**
19 * \file
20 *
21 * \note Code-Status: <a href="Code-Status.md#Alpha">Alpha</a>
22 */
23
24namespace Stroika::Foundation::DataExchange::Variant::XML {
25
26 /**
27 * \brief Read XML as a VariantValue - the inverse of Variant::XML::Writer, whose documentation has the shape
28 *
29 * An element with child elements reads as an object, one with only text as that text, and children of one name as an
30 * array. An attribute reads as a member too, by its name, so reading a document of someone else's drops nothing
31 * silently. A Binding says the rest: which members are attributes, what they are named, which are arrays however few
32 * elements a document has - and (Binding::fType) what type each value is.
33 *
34 * **Whether the Binding declares a value's type changes how it reads, a great deal** (Binding::fType's table):
35 * - **No type declared** - the default - XML says nothing of one, so this guesses: **a leaf reads back as a String**
36 * (3 as "3", true as "true" - VariantValue::As, so ObjectVariantMapper's ToObject, coerces), an empty element as ""
37 * (which is what null, {} and an empty array of `<Array>`s are all written as), and an element it does not name as a
38 * member, by its name. A Binding saying a member is an array (fItems naming its items) reads its empty element back
39 * as []; an empty array written as the member's element repeated is no element at all, so reads back absent.
40 * - **A type declared**: the value reads back as that type - 3 as 3, an empty object as {}, an empty array as [] - and
41 * a document that is not of that type (text that is not a number, an element or attribute the Binding does not
42 * declare, a member repeated that it declares as one value) throws BadFormatException - unless the Binding says to
43 * skip what it does not declare (Binding::fUndeclaredMembers eSkip, as XSD's xs:any), as reading someone else's
44 * document - a vendor's own elements - needs; or the Reader reads leniently (Options::fLenient), passing over
45 * all of these.
46 *
47 * **Given a complete Binding (Binding::IsComplete), this reads back a value equal to what the Writer wrote
48 * (VariantValue::operator==: the same members, items and types, and Strings of the same code points) - or the Writer, or
49 * this Reader, throws BadFormatException, the value not being one the Binding describes: never anything in between** (but
50 * for what XML writes as nothing - @see Binding::IsComplete). The document is not promised: the Writer picks one spelling
51 * of each character - the character itself, or a character reference - and any other spelling reads the same (U+1F600
52 * written literally, as `&#128512;` or as `&#x1F600;` is one character). A character XML 1.0 cannot hold at all (U+0000
53 * to U+001F but TAB, LF and CR, U+FFFE, U+FFFF), the Writer throws on.
54 *
55 * Give it (Options::fBinding) the Binding the Writer was given. With the default - no Binding::fName - the document
56 * element is the value's one member, so its name is kept: `<a><b>1</b></a>` reads as `{"a": {"b": "1"}}`. A Binding with
57 * an fName reads the document element's content as the value - and throws DataExchange::BadFormatException where that
58 * element has another (local) name, the document not being one the Binding describes.
59 *
60 * \note Throws DataExchange::BadFormatException on mixed content (text beside child elements), which this shape cannot
61 * hold - nor can a text member (Binding::Kind::eText), text beside attributes only: reading on would silently drop
62 * the text. And on text beside attributes, unless a Binding says which member it is (Binding::Kind::eText).
63 *
64 * \note Comments and processing instructions are dropped - StructuredStreamEvents::IConsumer reports neither, so this
65 * Reader never sees them. So a document rewritten through a VariantValue loses the comments it had, which would
66 * matter most for a hand-edited config file.
67 *
68 * @todo keep comments and processing instructions, if ever wanted - easy enough here, but the SAX reader must
69 * report them first (a callback each on StructuredStreamEvents::IConsumer, emitted by both providers)
70 *
71 * \note Requires an XML parser (qStroika_Foundation_DataExchange_XML_SupportParsing); Read throws without one.
72 */
73 class Reader : public Variant::Reader {
74 private:
76
77 private:
78 class Rep_;
79
80 public:
81 /**
82 * \brief How to read: the Binding - and which parser reads, and a schema the document must hold to
83 */
84 struct Options {
85 /**
86 * \brief The Binding the Writer was given (@see Binding)
87 */
89
90 /**
91 * \brief How the XML is parsed - by default, with Stroika's default provider; nearly always left as is (@see
92 * DataExchange::XML::Options)
93 */
95
96 /**
97 * \brief A schema the document is validated against as it is read: reading one that does not hold to it throws.
98 * nullptr (the default) validates nothing
99 *
100 * Best compiled by the provider that reads (fXMLOptions) - @see DataExchange::XML::SAXParse.
101 */
103
104 /**
105 * \brief Read what the Binding describes from a document that does not quite hold to it, rather than throw - as
106 * reading others' documents wants: UPnP devices', say, which are famously loose
107 *
108 * Then an element or attribute the Binding does not declare is skipped, wherever it is - markup inside a leaf's
109 * text too; a member repeated that the Binding declares once keeps its last; text the Binding has nowhere for -
110 * in an object, an array, a presence marker - is passed over; and a value not of its declared type is absent.
111 *
112 * The Writer writes none of these, so what it wrote reads the same either way: a complete Binding still
113 * round-trips every value of its type.
114 */
115 bool fLenient{false};
116 };
117
118 public:
119#if qCompilerAndStdLib_default_member_initializer_needed_within_enclosing_class_Buggy
120 Reader ();
121 Reader (const Options& options); ///< \brief Reading as options says
122#else
123 Reader (const Options& options = {}); ///< \brief Reading as options says
124#endif
125 Reader (const Binding& binding); ///< \brief As Reader{Options{.fBinding = binding}}
126 };
127
128}
129
130/*
131 ********************************************************************************
132 ***************************** Implementation Details ***************************
133 ********************************************************************************
134 */
135
136#endif /*_Stroika_Foundation_DataExchange_Variant_XML_Reader_h_*/
abstract class specifying interface for readers that map a source like XML or JSON to a VariantValue ...
Read XML as a VariantValue - the inverse of Variant::XML::Writer, whose documentation has the shape.
Reader(const Binding &binding)
As Reader{Options{.fBinding = binding}}.
Reader(const Options &options={})
Reading as options says.
How a VariantValue is to be written as XML, and read back, where the default shape (.
Definition Binding.h:88
How to read: the Binding - and which parser reads, and a schema the document must hold to.
DataExchange::XML::Options fXMLOptions
How the XML is parsed - by default, with Stroika's default provider; nearly always left as is (.
bool fLenient
Read what the Binding describes from a document that does not quite hold to it, rather than throw - a...
DataExchange::XML::Schema::Ptr fValidateAgainst
A schema the document is validated against as it is read: reading one that does not hold to it throws...
How XML is read and written - for now, with which provider - taken last by each XML function (DOM::Do...