Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
DomUtils.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2022 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/* DomUtils.cc (C) 2000-2018 */
9/* */
10/* Fonctions utilitaires diveres concernant le DOM. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14#include "arcane/utils/ArcanePrecomp.h"
15
16#include "arcane/utils/Array.h"
17#include "arcane/utils/Iostream.h"
18#include "arcane/utils/Iterator.h"
19#include "arcane/utils/StdHeader.h"
20#include "arcane/utils/String.h"
21#include "arcane/utils/StringBuilder.h"
22#include "arcane/utils/NotImplementedException.h"
23#include "arcane/utils/FatalErrorException.h"
24
25#include "arcane/Dom.h"
26#include "arcane/DomUtils.h"
27#include "arcane/XmlNode.h"
28#include "arcane/IXmlDocumentHolder.h"
29
30#include <algorithm>
31
32/*---------------------------------------------------------------------------*/
33/*---------------------------------------------------------------------------*/
34
35ARCANE_BEGIN_NAMESPACE
36
37ARCANE_BEGIN_NAMESPACE_DOMUTILS
38
39extern "C++" ARCANE_CORE_EXPORT void
40removeAllChildren(const dom::Node& parent);
41
42extern "C++" ARCANE_CORE_EXPORT bool
43writeNode(std::ostream& ostr,const dom::Node&);
44
45extern "C++" ARCANE_CORE_EXPORT bool
46writeNodeChildren(std::ostream& ostr,const dom::Node&);
47
48ARCANE_END_NAMESPACE_DOMUTILS
49
50/*---------------------------------------------------------------------------*/
51/*---------------------------------------------------------------------------*/
52
53namespace
54{
55
56/*---------------------------------------------------------------------------*/
57/*---------------------------------------------------------------------------*/
58
59void
60_notImplemented(const char* reason)
61{
62 cerr << "* DOMUTILS NOT YET IMPLEMENTED: " << reason << '\n';
63 throw dom::DOMException(dom::NOT_IMPLEMENTED_ERR);
64}
65
66/*---------------------------------------------------------------------------*/
67/*---------------------------------------------------------------------------*/
68
69void
70_writeNodeChildren(std::ostream& o,const dom::Node& node)
71{
72 // Affiche récursivement les noeuds fils
73 dom::Node next = node.firstChild();
74 while (!next._null()){
75 domutils::writeNode(o,next);
76 next = next.nextSibling();
77 }
78}
79
80}
81
82/*---------------------------------------------------------------------------*/
83/*---------------------------------------------------------------------------*/
84
85String domutils::
86textContent(const dom::Node& node)
87{
88 using namespace dom;
89 StringBuilder str;
90 if (node._null())
91 return str.toString();
92
93 if (node.nodeType()!=Node::ELEMENT_NODE)
94 ARCANE_THROW(NotImplementedException,"get text value for non ELEMENT_NODE");
95 for( Node i=node.firstChild(); !i._null(); i=i.nextSibling() ){
96 UShort ntype = i.nodeType();
97 if (ntype==Node::TEXT_NODE)
98 str += i.nodeValue();
99 else if (ntype==Node::CDATA_SECTION_NODE){
100 str += i.nodeValue();
101 }
102 else if (ntype==Node::ENTITY_REFERENCE_NODE){
103 ARCANE_THROW(NotImplementedException,"get text value for non ENTITY_REFERENCE_NODE");
104 }
105 }
106 return str.toString();
107}
108
109/*---------------------------------------------------------------------------*/
110/*---------------------------------------------------------------------------*/
111
112void domutils::
113textContent(dom::Node& node,const String& new_value)
114{
115 // Même sémantique que Node::textContent du DOM3:
116 // - Supprime tous les noeuds fils.
117 // - création d'un seul noeud texte contenant la nouvelle valeur
118 using namespace dom;
119 if (node.nodeType()!=Node::ELEMENT_NODE)
120 ARCANE_THROW(NotImplementedException,"set text value for non ELEMENT_NODE");
121 removeAllChildren(node);
122 if (!new_value.null()){
123 Text text_node = node.ownerDocument().createTextNode(new_value);
124 node.appendChild(text_node);
125 }
126}
127
128/*---------------------------------------------------------------------------*/
129/*---------------------------------------------------------------------------*/
130
131String domutils::
132textValue(const dom::Node& node)
133{
134 return domutils::textContent(node);
135}
136
137/*---------------------------------------------------------------------------*/
138/*---------------------------------------------------------------------------*/
139
140void domutils::
141textValue(dom::Node& node,const String& new_value)
142{
143 textContent(node,new_value);
144}
145
146/*---------------------------------------------------------------------------*/
147/*---------------------------------------------------------------------------*/
148
149dom::Element domutils::
150createElement(const dom::Node& parent,const String& name,const String& value)
151{
152 if (parent._null())
153 return dom::Element();
154 dom::Document doc = parent.ownerDocument();
155 if (doc._null())
156 return dom::Element();
157 dom::Element elem = doc.createElement(name);
158 textContent(elem,value);
159 parent.appendChild(elem);
160 return elem;
161}
162
163/*---------------------------------------------------------------------------*/
164/*---------------------------------------------------------------------------*/
165
166String domutils::
167attrValue(const dom::Node& node,const String& attr_name)
168{
169 // TODO: Utiliser directement les méthodes du DOM que sont getAttribute()
170 // mais il faut pour cela gérer les namespace.
171 String str;
172 if (node._null())
173 return str;
174 const dom::NamedNodeMap& attr = node.attributes();
175 if (attr._null())
176 return str;
177 const dom::Node& n = attr.getNamedItem(attr_name);
178 if (n._null())
179 return str;
180 str = n.nodeValue();
181
182#if 0
183 // A activer lorsque l'implémentation via getAttribute() sera effective.
184 {
185 dom::Element element{node};
186 String str2 = element.getAttribute(attr_name);
187 if (str2!=str)
188 ARCANE_FATAL("Bad new value for attribute '{0}' new={1} current={2}",attr_name,str2,str);
189 }
190#endif
191
192 return str;
193}
194
195/*---------------------------------------------------------------------------*/
196/*---------------------------------------------------------------------------*/
197
198void domutils::
199setAttr(const dom::Element& elem,const String& name,const String& value)
200{
201 if (elem._null())
202 return;
203 elem.setAttribute(name,value);
204}
205
206/*---------------------------------------------------------------------------*/
207/*---------------------------------------------------------------------------*/
208
209dom::Node domutils::
210childNode(const dom::Node& parent,const String& child_name)
211{
212 dom::DOMString ref_name(child_name);
213 for( dom::Node i=parent.firstChild(); !i._null(); i=i.nextSibling() ){
214 if (i.nodeName()==ref_name)
215 return i;
216 }
217 return dom::Node();
218}
219
220/*---------------------------------------------------------------------------*/
221/*---------------------------------------------------------------------------*/
222
223void domutils::
224removeAllChildren(const dom::Node& parent)
225{
226 if (parent._null())
227 return;
228
229 // Supprime les noeuds fils.
230 dom::Node n = parent.firstChild();
231 while (!n._null()){
232 parent.removeChild(n);
233 // TODO LIBERER LA MEMOIRE
234 n = parent.firstChild();
235 }
236}
237
238/*---------------------------------------------------------------------------*/
239/*---------------------------------------------------------------------------*/
240/*!
241 * \brief Retourne le noeud correspondant à une expression XPath.
242 * Retourne le noeud correspondant à l'expression \a xpath_expr avec
243 * pour contexte le noeud \a context_node.
244 * L'implémentation actuelle ne supporte que le type suivant d'expression:
245 * - a/b*.
246 */
247dom::Node domutils::
248nodeFromXPath(const dom::Node& context_node,const String& xpath_expr)
249{
250 const char* expr = xpath_expr.localstr();
251 if (context_node._null()){
252 return dom::Node();
253 }
254 if (!expr){
255 return dom::Node();
256 }
257 const char* separator = ::strchr(expr,'/');
258 if (separator){
259 // Chaîne de type \a a/b. Recherche le noeud fils de nom \a a et
260 // lui applique récursivement cette fonction avec \a b comme expression.
261 std::string_view buf1(expr,(Int64)(separator-expr));
262 String buf(buf1);
263 dom::Node child = childNode(context_node,buf);
264 if (child._null()){
265 return dom::Node();
266 }
267 return nodeFromXPath(child,String(std::string_view(separator+1)));
268 }
269 return childNode(context_node,xpath_expr);
270}
271
272/*---------------------------------------------------------------------------*/
273/*---------------------------------------------------------------------------*/
274
275bool domutils::
276writeNodeChildren(std::ostream& ostr,const dom::Node& node)
277{
278 _writeNodeChildren(ostr,node);
279 return true;
280}
281
282/*---------------------------------------------------------------------------*/
283/*---------------------------------------------------------------------------*/
284
285bool domutils::
286writeNode(std::ostream& o,const dom::Node& node)
287{
288 using namespace dom;
289 switch(node.nodeType()){
290 case Node::ELEMENT_NODE:
291 {
292 o << '<' << node.nodeName();
293 NamedNodeMap attr_list = node.attributes();
294 for( ULong i=0, s=attr_list.length(); i<s; ++i ){
295 o << ' ';
296 writeNode(o,attr_list.item(i));
297 }
298 o << '>';
299 writeNodeChildren(o,node);
300 o << "</" << node.nodeName() << '>';
301 }
302 break;
303 case Node::ATTRIBUTE_NODE:
304 o << node.nodeName() << '='
305 << '"' << node.nodeValue() << '"';
306 break;
307 case Node::TEXT_NODE:
308 o << node.nodeValue();
309 //_notImplemented("Dom::writeNode() for TEXT_NODE");
310 break;
311 case Node::CDATA_SECTION_NODE:
312 o << node.nodeValue();
313 cerr << "** Dom::writeNode() for CDATA_SECTION_NODE Not fully implemented\n";
314 //_notImplemented("Dom::writeNode() for CDATA_SECTION_NODE");
315 break;
316 case Node::ENTITY_REFERENCE_NODE:
317 _notImplemented("Dom::writeNode() for ENTITY_REFERENCE_NODE");
318 break;
319 case Node::ENTITY_NODE:
320 _notImplemented("Dom::writeNode() for ENTITY_NODE");
321 break;
322 case Node::PROCESSING_INSTRUCTION_NODE:
323 _notImplemented("Dom::writeNode() for PROCESSING_INSTRUCTION_NODE");
324 break;
325 case Node::COMMENT_NODE:
326 o << "<!--" << node.nodeValue() << "-->";
327 break;
328 case Node::DOCUMENT_NODE:
329 _writeNodeChildren(o,node);
330 break;
331 case Node::DOCUMENT_TYPE_NODE:
332 _writeNodeChildren(o,node);
333 break;
334 case Node::DOCUMENT_FRAGMENT_NODE:
335 _notImplemented("Dom::writeNode() for DOCUMENT_FRAGMENT_NODE");
336 break;
337 case Node::NOTATION_NODE:
338 _notImplemented("Dom::writeNode() for NOTATION_NODE");
339 break;
340 default:
341 _notImplemented("Dom::writeNode() for unknown node");
342 break;
343 }
344 return false;
345}
346
347/*---------------------------------------------------------------------------*/
348/*---------------------------------------------------------------------------*/
349
350bool domutils::
351saveDocument(std::ostream& ostr,const dom::Document& doc,int indent_level)
352{
353 ByteUniqueArray bytes;
354 saveDocument(bytes,doc,indent_level);
355 ostr.write((const char*)bytes.data(),bytes.size());
356 return true;
357}
358
359/*---------------------------------------------------------------------------*/
360/*---------------------------------------------------------------------------*/
361
362bool domutils::
363saveDocument(ByteArray& bytes,const dom::Document& doc,int indent_level)
364{
365 dom::DOMImplementation domimp;
366 domimp._save(bytes,doc,indent_level);
367 Integer nb_byte = bytes.size();
368 if (nb_byte>=1 && bytes[nb_byte-1]=='\0'){
369 ARCANE_FATAL("Invalid null charactere at end of XML stream");
370 }
371 return true;
372}
373
374/*---------------------------------------------------------------------------*/
375/*---------------------------------------------------------------------------*/
376
377IXmlDocumentHolder* domutils::
378createXmlDocument()
379{
380 dom::DOMImplementation domimp;
381 return domimp._newDocument();
382}
383
384/*---------------------------------------------------------------------------*/
385/*---------------------------------------------------------------------------*/
386
387/*---------------------------------------------------------------------------*/
388/*---------------------------------------------------------------------------*/
389
390domutils::NameIterator::
391NameIterator(const dom::Node& from,const String& ref_name)
392: m_parent(from)
393, m_current()
394, m_ref_name(ref_name)
395{
396 _findNextValid(true);
397}
398
399/*---------------------------------------------------------------------------*/
400/*---------------------------------------------------------------------------*/
401
402void domutils::NameIterator::
403_findNextValid(bool is_init)
404{
405 if (is_init)
406 m_current = m_parent.firstChild();
407 else{
408 if (m_current._null())
409 return;
410 m_current = m_current.nextSibling();
411 }
412 while (!m_current._null()){
413 if (m_current.nodeName()==m_ref_name)
414 break;
415 m_current = m_current.nextSibling();
416 }
417}
418
419/*---------------------------------------------------------------------------*/
420/*---------------------------------------------------------------------------*/
421
422/*---------------------------------------------------------------------------*/
423/*---------------------------------------------------------------------------*/
424
425IXmlDocumentHolder* IXmlDocumentHolder::
426loadFromBuffer(Span<const Byte> buffer,const String& name,ITraceMng* tm)
427{
428 dom::DOMImplementation domimp;
429 // Lecture du fichier contenant les informations internes.
430 return domimp._load(asBytes(buffer),name,tm);
431}
432
433IXmlDocumentHolder* IXmlDocumentHolder::
434loadFromBuffer(ByteConstSpan buffer,const String& name,ITraceMng* tm)
435{
436 dom::DOMImplementation domimp;
437 // Lecture du fichier contenant les informations internes.
438 return domimp._load(buffer,name,tm);
439}
440
441/*---------------------------------------------------------------------------*/
442/*---------------------------------------------------------------------------*/
443
444IXmlDocumentHolder* IXmlDocumentHolder::
445loadFromFile(const String& filename,ITraceMng* tm)
446{
447 return loadFromFile(filename,String(),tm);
448}
449
450/*---------------------------------------------------------------------------*/
451/*---------------------------------------------------------------------------*/
452
453IXmlDocumentHolder* IXmlDocumentHolder::
454loadFromFile(const String& filename,const String& schema_filename,ITraceMng* tm)
455{
456 dom::DOMImplementation domimp;
457 return domimp._load(filename,tm,schema_filename);
458}
459
460/*---------------------------------------------------------------------------*/
461/*---------------------------------------------------------------------------*/
462
463ARCANE_END_NAMESPACE
464
465/*---------------------------------------------------------------------------*/
466/*---------------------------------------------------------------------------*/
467
#define ARCANE_THROW(exception_class,...)
Macro pour envoyer une exception avec formattage.
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
Gestionnaire d'un document DOM.
Interface du gestionnaire de traces.
Vue d'un tableau d'éléments de type T.
Definition Span.h:510
Chaîne de caractères unicode.
const char * localstr() const
Retourne la conversion de l'instance dans l'encodage UTF-8.
Definition String.cc:227
Span< const std::byte > ByteConstSpan
Vue en lecture seule d'un tableau à une dimension de caractères.
Definition UtilsTypes.h:706
dom::Node nodeFromXPath(const dom::Node &context_node, const String &xpath_expr)
Retourne le noeud correspondant à une expression XPath. Retourne le noeud correspondant à l'expressio...
Definition DomUtils.cc:248
UniqueArray< Byte > ByteUniqueArray
Tableau dynamique à une dimension de caractères.
Definition UtilsTypes.h:509
Int32 Integer
Type représentant un entier.