Arcane  v3.16.0.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-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
182//! Écrivain au format XML pour un jeu de données.
183class DocumentXmlWriter
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
233//! Écrivain au format JSON pour un jeu de données.
234class DocumentJSONWriter
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.
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
Encapsulation d'un pointeur qui se détruit automatiquement.
Definition ScopedPtr.h:44
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).
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
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-