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