Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
AxlOptionsBuilder.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* AxlOptionsBuilder.cc (C) 2000-2023 */
9/* */
10/* Classes pour créer dynamiquement des options du jeu de données. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/core/AxlOptionsBuilder.h"
15
16#include "arcane/utils/FatalErrorException.h"
17#include "arcane/utils/Array.h"
18#include "arcane/utils/JSONWriter.h"
19
20#include "arcane/core/DomUtils.h"
21#include "arcane/core/XmlNode.h"
22#include "arcane/core/IXmlDocumentHolder.h"
23#include "arcane/core/CaseNodeNames.h"
24
25/*---------------------------------------------------------------------------*/
26/*---------------------------------------------------------------------------*/
27
28namespace Arcane::AxlOptionsBuilder
29{
30// TODO: traiter en JSON le cas où une option avec le même nom est présente
31// plusieurs fois.
32
33// TODO: utiliser une union dans option pour conserver les valeurs comme les
34// réels sans les transformer immédiatement en chaîne de caractères.
35
36/*---------------------------------------------------------------------------*/
37/*---------------------------------------------------------------------------*/
38
40{
41 friend DocumentXmlWriter;
42 friend DocumentJSONWriter;
43
44 public:
45
46 void add(const std::initializer_list<OneOption>& options)
47 {
48 for (const auto& o : options)
49 m_options.add(o);
50 }
51
52 public:
53
54 UniqueArray<OneOption> m_options;
55};
56
57/*---------------------------------------------------------------------------*/
58/*---------------------------------------------------------------------------*/
59
60OneOption::
61OneOption(Type type, const String& name, const OptionList& options)
62: m_type(type)
63, m_name(name)
64{
65 OptionList cloned_list = options.clone();
66 m_sub_option = cloned_list.m_p;
67}
68
69/*---------------------------------------------------------------------------*/
70/*---------------------------------------------------------------------------*/
71
72ServiceInstance::
73ServiceInstance(const String& option_name, const String& service_name,
74 const std::initializer_list<OneOption>& options)
75: OneOption(Type::CO_ServiceInstance, option_name, OptionList{})
76{
77 m_sub_option->add(options);
78 m_service_name = service_name;
79}
80
81/*---------------------------------------------------------------------------*/
82/*---------------------------------------------------------------------------*/
83
84ServiceInstance::
85ServiceInstance(const String& option_name, const String& service_name,
86 const OptionList& options)
87: OneOption(Type::CO_ServiceInstance, option_name, options)
88{
89 m_service_name = service_name;
90}
91
92/*---------------------------------------------------------------------------*/
93/*---------------------------------------------------------------------------*/
94
95ServiceInstance::
96ServiceInstance(const String& option_name, const String& service_name)
97: OneOption(Type::CO_ServiceInstance, option_name, String{})
98{
99 m_service_name = service_name;
100}
101
102/*---------------------------------------------------------------------------*/
103/*---------------------------------------------------------------------------*/
104
105Complex::
106Complex(const String& name, const std::initializer_list<OneOption>& options)
107: OneOption(Type::CO_Complex, name, OptionList{})
108{
109 m_sub_option->add(options);
110}
111
112/*---------------------------------------------------------------------------*/
113/*---------------------------------------------------------------------------*/
114
115Complex::
116Complex(const String& name, const OptionList& options)
117: OneOption(Type::CO_Complex, name, options)
118{
119}
120
121/*---------------------------------------------------------------------------*/
122/*---------------------------------------------------------------------------*/
123
124/*---------------------------------------------------------------------------*/
125/*---------------------------------------------------------------------------*/
126
129: m_p(std::make_shared<OneOptionImpl>())
130{
131}
132
133/*---------------------------------------------------------------------------*/
134/*---------------------------------------------------------------------------*/
135
137OptionList(const std::initializer_list<OneOption>& options)
138: m_p(std::make_shared<OneOptionImpl>())
139{
140 add(options);
141}
142
143/*---------------------------------------------------------------------------*/
144/*---------------------------------------------------------------------------*/
145
146OptionList& OptionList::
147add(const String& name, const OptionList& option)
148{
149 m_p->m_options.add(OneOption(OneOption::Type::CO_Complex, name, option));
150 return (*this);
151}
152
153/*---------------------------------------------------------------------------*/
154/*---------------------------------------------------------------------------*/
155
156OptionList& OptionList::
157add(const std::initializer_list<OneOption>& options)
158{
159 for (const auto& o : options)
160 m_p->m_options.add(o);
161 return (*this);
162}
163
164/*---------------------------------------------------------------------------*/
165/*---------------------------------------------------------------------------*/
166
167OptionList OptionList::
168clone() const
169{
170 OptionList new_opt;
171 new_opt.m_p->m_options = m_p->m_options;
172 return new_opt;
173}
174
175/*---------------------------------------------------------------------------*/
176/*---------------------------------------------------------------------------*/
177
178/*---------------------------------------------------------------------------*/
179/*---------------------------------------------------------------------------*/
180
181//! Écrivain au format XML pour un jeu de données.
183{
184 public:
185
186 static IXmlDocumentHolder* toXml(const Document& d)
187 {
188 auto* doc = domutils::createXmlDocument();
189 XmlNode document_node = doc->documentNode();
190 DocumentXmlWriter writer(d.language());
191 CaseNodeNames& cnn = writer.m_case_node_names;
192 XmlNode root_element = document_node.createAndAppendElement("root", String());
193 root_element.setAttrValue(cnn.lang_attribute, d.language());
194 XmlNode opt_element = root_element.createAndAppendElement("dynamic-options", String());
195 writer._writeToXml(d.m_options.m_p.get(), opt_element);
196 return doc;
197 }
198
199 private:
200
201 void _writeToXml(OneOptionImpl* opt, XmlNode element)
202 {
203 for (OneOption& o : opt->m_options) {
204 XmlNode current_element = element.createAndAppendElement(o.m_name, o.m_value);
205 if (o.m_sub_option.get())
206 _writeToXml(o.m_sub_option.get(), current_element);
207
208 if (!o.m_service_name.null())
209 current_element.setAttrValue("name", o.m_service_name);
210
211 if (!o.m_function_name.null()) {
212 String funcname_attr = m_case_node_names.function_ref;
213 current_element.setAttrValue(funcname_attr, o.m_function_name);
214 }
215 }
216 }
217
218 private:
219
220 explicit DocumentXmlWriter(const String& lang)
221 : m_case_node_names(lang)
222 {}
223
224 private:
225
226 CaseNodeNames m_case_node_names;
227};
228
229/*---------------------------------------------------------------------------*/
230/*---------------------------------------------------------------------------*/
231
232//! Écrivain au format JSON pour un jeu de données.
234{
235 public:
236
237 static String toJSON(const Document& d)
238 {
239 DocumentJSONWriter writer(d.language());
240
241 writer._write(d);
242 return writer.m_json_writer.getBuffer();
243 }
244
245 private:
246
247 void _write(const Document& doc)
248 {
249 JSONWriter::Object o(m_json_writer);
250 m_json_writer.write("language",doc.language());
251 m_json_writer.write("version","1");
252 {
253 JSONWriter::Object o2(m_json_writer,"options");
254 _write(doc.m_options.m_p.get());
255 }
256 }
257
258 void _write(OneOptionImpl* opt)
259 {
260 if (!opt)
261 return;
262 // TODO: traiter le cas où une option avec le même nom
263 // est présente plusieurs fois.
264 // En théorie on peut avoir plusieurs la même clé mais
265 // ce n'est pas recommandé. Le mieux dans ce cas est
266 // d'utiliser un tableau.
267 for (OneOption& o : opt->m_options) {
268 _write(o);
269 }
270 }
271
272 void _write(OneOption& o)
273 {
274 OneOptionImpl* sub_options = o.m_sub_option.get();
275 if (o.m_type==OneOption::Type::CO_ServiceInstance){
276 JSONWriter::Object j1(m_json_writer,o.m_name);
277 if (!o.m_service_name.null())
278 m_json_writer.write("$name",o.m_service_name);
279 _write(sub_options);
280 return;
281 }
282
283 if (o.m_type==OneOption::Type::CO_Complex){
284 JSONWriter::Object j1(m_json_writer,o.m_name);
285 _write(sub_options);
286 return;
287 }
288
289 // Valeur simple ou énuméréé ou étendu.
290 // Si pas de table de marche, on fait directement { "clé" : "valeur" }.
291 // Sinon on utilise un sous-objet:
292 // {
293 // "$function" : "nom_de_la_fonction,
294 // "$value" : "valeur"
295 // }
296
297 if (!o.m_function_name.null()) {
298 JSONWriter::Object j1(m_json_writer,o.m_name);
299 m_json_writer.write(m_case_function_json_name,o.m_function_name);
300 m_json_writer.write("$value",o.m_value);
301 return;
302 }
303
304 m_json_writer.write(o.m_name, o.m_value);
305 }
306
307 private:
308
309 explicit DocumentJSONWriter(const String& lang)
310 : m_case_node_names(lang)
311 {
312 m_case_function_json_name = String("$") + m_case_node_names.function_ref;
313 }
314
315 private:
316
317 CaseNodeNames m_case_node_names;
318 JSONWriter m_json_writer;
319 String m_case_function_json_name;
320};
321
322/*---------------------------------------------------------------------------*/
323/*---------------------------------------------------------------------------*/
324
325extern "C++" IXmlDocumentHolder*
326documentToXml(const Document& d)
327{
328 return DocumentXmlWriter::toXml(d);
329}
330
331/*---------------------------------------------------------------------------*/
332/*---------------------------------------------------------------------------*/
333
334} // namespace Arcane::AxlOptionsBuilder
335
336/*---------------------------------------------------------------------------*/
337/*---------------------------------------------------------------------------*/
338
339namespace Arcane
340{
341
342/*---------------------------------------------------------------------------*/
343/*---------------------------------------------------------------------------*/
344
345extern "C++" ARCANE_CORE_EXPORT void
346_testAxlOptionsBuilder()
347{
348 using namespace AxlOptionsBuilder;
349 std::cout << "TestOptionList\n";
350 OptionList sub_opt({ Simple("max", 35),
351 Simple("min", 13.2),
352 Simple("test", 1) });
353
354 OptionList service_opt({ Simple("service-option1", 42),
355 Simple("service-option2", -1.5) });
356
357 OptionList dco({ Simple("toto", 3),
358 Simple("titi", 3.1).addFunction("func1"),
359 Simple("tutu", "Hello"),
360 Enumeration("a", "vx"),
361 Extended("extended1", "ext"),
362 ServiceInstance("my-service1", "TestService1",
363 { Simple("service-option1", 25),
364 Simple("service-option2", 3.2) }),
365 ServiceInstance("my-service2", "TestService2"),
366 // TODO ajouter service avec nom par défaut.
367 ServiceInstance("my-service3", "TestService3", service_opt),
368 Complex("sub-opt1",
369 { Simple("max", 25),
370 Simple("min", 23.2),
371 Simple("test", 4) }),
372 Complex("sub-opt2", sub_opt) });
373 Document doc("fr", dco);
374 auto* x = DocumentXmlWriter::toXml(doc);
375 String s = x->save();
376 std::cout << "VALUE:" << s << "\n";
377
378 String ref_str = "<?xml version=\"1.0\"?>\n"
379 "<root xml:lang=\"fr\"><dynamic-options><toto>3</toto><titi fonction=\"func1\">3.1</titi>"
380 "<tutu>Hello</tutu><a>vx</a><extended1>ext</extended1><my-service1 name=\"TestService1\">"
381 "<service-option1>25</service-option1><service-option2>3.2</service-option2></my-service1>"
382 "<my-service2 name=\"TestService2\"/><my-service3 name=\"TestService3\">"
383 "<service-option1>42</service-option1><service-option2>-1.5</service-option2></my-service3>"
384 "<sub-opt1><max>25</max><min>23.2</min><test>4</test></sub-opt1><sub-opt2><max>35</max>"
385 "<min>13.2</min><test>1</test></sub-opt2></dynamic-options></root>\n";
386 if (s != ref_str)
387 ARCANE_FATAL("BAD VALUE v={0} expected={1}", s, ref_str);
388
389 {
390 String json_string = DocumentJSONWriter::toJSON(doc);
391 {
392 std::ofstream ofile("test1.json");
393 ofile << json_string;
394 }
395 std::cout << "JSON=" << json_string << "\n";
396 }
397}
398
399/*---------------------------------------------------------------------------*/
400/*---------------------------------------------------------------------------*/
401
402} // namespace Arcane
403
404/*---------------------------------------------------------------------------*/
405/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Écrivain au format JSON pour un jeu de données.
Écrivain au format XML pour un jeu de données.
Option 'ServiceInstance' du jeu de données.
Classe de base d'une option dynamique.
String m_service_name
Valeur de l'option (si option CO_Simple)
Liste d'options du jeu de données.
OptionList()
Construit un jeu d'options vide.
Gestionnaire d'un document DOM.
Ecrivain au format JSON.
Definition JSONWriter.h:33
Noeud d'un arbre DOM.
Definition XmlNode.h:51
void setAttrValue(const String &name, const String &value)
Positionne l'attribut name à la valeur value.
Definition XmlNode.cc:239
Chaîne de caractères unicode.
bool null() const
Retourne true si la chaîne est nulle.
Definition String.cc:304
Vecteur 1D de données avec sémantique par valeur (style STL).
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-