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