Vaucanson  1.4.1
builders.hxx
1 // builders.hxx: this file is part of the Vaucanson project.
2 //
3 // Vaucanson, a generic library for finite state machines.
4 //
5 // Copyright (C) 2007, 2008, 2009, 2011 The Vaucanson Group.
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License
9 // as published by the Free Software Foundation; either version 2
10 // of the License, or (at your option) any later version.
11 //
12 // The complete GNU General Public Licence Notice can be found as the
13 // `COPYING' file in the root directory.
14 //
15 // The Vaucanson Group consists of people listed in the `AUTHORS' file.
16 //
17 #ifndef VCSN_XML_BUILDERS_HXX
18 # define VCSN_XML_BUILDERS_HXX
19 
20 # include <sstream>
21 
22 # include <vaucanson/algebra/concept/letter.hh>
23 # include <vaucanson/algebra/implementation/series/rat/exp.hh>
26 # include <vaucanson/algebra/concept/monoid_base.hh>
27 # include <vaucanson/algebra/implementation/monoid/monoid_rep.hh>
28 # include <vaucanson/algebra/concept/tropical_semiring.hh>
30 # include <vaucanson/algebra/implementation/semiring/cyclic_semiring.hh>
31 
32 namespace vcsn
33 {
34  namespace xml
35  {
39  template <typename T>
41  {
42  static_error(need_to_specialize_monGenAction_for_T)
43  }
44 
45  template <typename T>
47  monGenAction(monoid_t& monoid)
48  : alphabet_(monoid.alphabet())
49  {
50  }
51 
52  template <typename T, typename U, typename V>
53  monGenAction<vcsn::Element<vcsn::algebra::Series<T, U>, V> >::
54  monGenAction(series_t& s)
55  : s_(s)
56  {
57  }
58 
59  // Real work done here (insertion).
60  template <typename T>
61  void
62  monGenAction<vcsn::algebra::FreeMonoid<T> >::
63  operator () (const std::string& str)
64  {
65  alphabet_.insert(str);
66  }
67 
68  // Real work done here (concatanation).
69  template <typename T, typename U, typename V>
70  void
71  monGenAction<vcsn::Element<vcsn::algebra::Series<T, U>, V> >::
72  operator () (const std::string& str)
73  {
74  std::pair<bool, letter_t> res =
75  parse_letter(s_.structure().monoid().alphabet(), str);
76 
77  if (res.first)
78  {
79  typename series_t::monoid_elt_t m(s_.structure().monoid(),
80  res.second);
81  series_t tmp(s_.structure(), m);
82  s_ = s_ * tmp;
83  }
84  else
85  error::notletter(str);
86  }
87 
91  template <typename T, typename U>
92  monGenHandler<T, U>::monGenHandler (xercesc::SAX2XMLReader* parser,
93  Handler& root,
94  const monGenAction<U>& action,
95  const XMLCh* value)
96  : Handler(parser, root),
97  value_(value),
98  action_(action)
99  {
100  }
101 
102  template <typename T, typename U>
103  void
104  monGenHandler<T, U>::start (const XMLCh* const,
105  const XMLCh* const localname,
106  const XMLCh* const,
107  const xercesc::Attributes&)
108  {
109  error::token(localname);
110  }
111 
112  template <typename T, typename U>
113  void
114  monGenHandler<T, U>::end (const XMLCh* const,
115  const XMLCh* const localname,
116  const XMLCh* const)
117  {
118  if (xercesc::XMLString::equals(eq_.monGen, localname))
119  {
120  if (value_)
121  {
122  std::string letter = xmlstr(value_);
123  action_(letter);
124  parser_->setContentHandler(&root_);
125  }
126  else
127  {
128  error::missattrs(localname, "value");
129  }
130  }
131  else
132  error::token(localname);
133  }
134 
138  template <typename T, typename U>
139  monGenTupleHandler<T, U>::monGenTupleHandler (xercesc::SAX2XMLReader* parser,
140  Handler& root,
141  const monGenAction<U>& action)
142  : Handler(parser, root),
143  value_("("),
144  wait_begin_(true),
145  count_(0),
146  action_(action)
147  {
148  }
149 
150  template <typename T, typename U>
151  void
152  monGenTupleHandler<T, U>::start (const XMLCh* const,
153  const XMLCh* const localname,
154  const XMLCh* const,
155  const xercesc::Attributes& attrs)
156  {
157  if (xercesc::XMLString::equals(eq_.monCompGen, localname) && wait_begin_)
158  {
159  wait_begin_ = false;
160  const XMLCh* attr = tools::get_attribute(attrs, eq_.value);
161  if (!attr)
162  error::missattrs(localname, "value");
163  value_ += xmlstr(attr);
164  if (count_ == algebra::letter_traits<typename T::alphabet_t::letter_t>::dim() - 2)
165  value_ += ",";
166  }
167  else
168  error::token(localname);
169  }
170 
171  template <typename T, typename U>
172  void
173  monGenTupleHandler<T, U>::end (const XMLCh* const,
174  const XMLCh* const localname,
175  const XMLCh* const)
176  {
177  int dim = algebra::letter_traits<typename T::alphabet_t::letter_t>::
178  dim();
179 
180  if (xercesc::XMLString::equals(eq_.monGen, localname)
181  && count_ == dim)
182  {
183  value_ += ")";
184  action_(value_);
185  parser_->setContentHandler(&root_);
186  }
187  else if (xercesc::XMLString::equals(eq_.monCompGen, localname)
188  && !wait_begin_ && count_ < dim)
189  {
190  wait_begin_ = true;
191  count_++;
192  }
193  else
194  error::token(localname);
195  }
196 
200  template <typename T>
201  FreeMonoidHandler<T>::FreeMonoidHandler (xercesc::SAX2XMLReader* parser,
202  Handler& root,
203  T& monoid)
204  : Handler(parser, root),
205  monoid_(monoid),
206  user_rep_(false),
207  mongenh_(0),
208  unsuph_(parser, *this)
209  {
210  }
211 
212  template <typename T>
213  void
214  FreeMonoidHandler<T>::start (const XMLCh* const,
215  const XMLCh* const localname,
216  const XMLCh* const,
217  const xercesc::Attributes& attrs)
218  {
219  using namespace xercesc;
220 
221  if (XMLString::equals(eq_.monGen, localname))
222  {
223  // When we have a monGen, we will insert it in the monoid alphabet.
224  monGenAction<T> action(monoid_);
225 
226  // Delete the old handler.
227  delete mongenh_;
228 
229  // Choose statically the kind of generator.
230  if (algebra::letter_traits<typename T::alphabet_t::letter_t>::kind() == "simple")
231  {
232  const XMLCh* value = tools::get_attribute(attrs, eq_.value);
233  mongenh_ = new monGenHandler<T, T>(parser_, *this, action, value);
234  }
235  else
236  mongenh_ = new monGenTupleHandler<T, T>(parser_, *this, action);
237 
238  // Setup the new handler.
239  parser_->setContentHandler(mongenh_);
240  }
241  else if (XMLString::equals(eq_.genSort, localname))
242  {
243  // FIXME: we should store the informations of genSort to ensure monoid consistency.
244  parser_->setContentHandler(&unsuph_);
245  }
246  else if (XMLString::equals(eq_.writingData, localname))
247  {
248  algebra::MonoidRep<T> rep;
249  if (tools::has_attribute(attrs, eq_.identitySymbol))
250  rep.empty = xmlstr(tools::get_attribute(attrs, eq_.identitySymbol));
251  if (tools::has_attribute(attrs, eq_.concat))
252  rep.concat = xmlstr(tools::get_attribute(attrs, eq_.concat));
253  monoid_.set_representation(rep);
254  user_rep_ = true;
255  parser_->setContentHandler(&unsuph_);
256  }
257  else
258  error::token(localname);
259  }
260 
261  template <typename T>
262  void
263  FreeMonoidHandler<T>::end (const XMLCh* const,
264  const XMLCh* const localname,
265  const XMLCh* const)
266  {
267  using namespace xercesc;
268 
269  if (XMLString::equals(eq_.monoid, localname))
270  {
271  // We are done with the monoid, so delete remaining data.
272  delete mongenh_;
273 
274  // Build a new monoid with disambiguated symbols.
275  T new_monoid(monoid_.alphabet());
276 
277  // Overwrite with any user provided representation.
278  if (user_rep_)
279  new_monoid.set_representation(*(monoid_.representation()));
280 
281  monoid_ = new_monoid;
282 
283  // Go up one level.
284  parser_->setContentHandler(&root_);
285  }
286  else if (!XMLString::equals(eq_.monGen, localname))
287  error::token(localname);
288  }
289 
293  template <typename T>
295  Handler& root,
296  T& srep)
297  : Handler(parser, root),
298  rep_(srep),
299  unsuph_(parser, *this)
300  {
301  }
302 
303  template <typename T>
304  void
305  SeriesRepresentationHandler<T>::start(const XMLCh* const,
306  const XMLCh* const localname,
307  const XMLCh* const,
308  const xercesc::Attributes& attrs)
309  {
310  error::token(localname);
311  }
312 
313  template <typename T>
314  void
315  SeriesRepresentationHandler<T>::end(const XMLCh* const,
316  const XMLCh* const localname,
317  const XMLCh* const)
318  {
319  using namespace xercesc;
320 
321  if (XMLString::equals(eq_.writingData, localname))
322  {
323  // Go up one level.
324  parser_->setContentHandler(&root_);
325  }
326  else
327  error::token(localname);
328  }
329 
330  namespace builders
331  {
332  template <typename T>
333  typename T::monoid_t*
334  create_monoid(T& param,
335  const XMLCh* const localname,
336  const xercesc::Attributes& attrs,
337  XMLEq& eq)
338  {
339  // Type helpers.
340  typename T::monoid_t::alphabet_t at;
341  typedef typename T::monoid_t monoid_t;
342 
343  monoid_t* monoid = new monoid_t(at);
344  builders::check_monoid_consistency(param, localname, attrs, eq);
345 
346  return monoid;
347  }
348 
349  template <typename T>
350  Handler*
351  create_monoidh (T& monoid,
352  const xercesc::Attributes&,
353  xercesc::SAX2XMLReader* parser,
354  Handler& root)
355  {
356  return new vcsn::xml::FreeMonoidHandler<T>(parser, root, monoid);
357  }
358 
359  template <typename T>
360  typename T::series_set_t::series_rep_t*
361  create_series_representation(T& param,
362  const XMLCh* const localname,
363  const xercesc::Attributes& attrs,
364  XMLEq& eq)
365  {
366  // Type helpers.
367  typedef typename T::series_set_t::series_rep_t series_rep_t;
368 
369  return new series_rep_t();
370  }
371 
372  template <typename T>
373  Handler*
374  create_series_representationh(T& srep,
375  const xercesc::Attributes& attrs,
376  xercesc::SAX2XMLReader* parser,
377  Handler& root,
378  XMLEq& eq)
379  {
380  if (tools::has_attribute(attrs, eq.openPar))
381  srep.open_par = xmlstr(tools::get_attribute(attrs, eq.openPar));
382  if (tools::has_attribute(attrs, eq.closePar))
383  srep.close_par = xmlstr(tools::get_attribute(attrs, eq.closePar));
384  if (tools::has_attribute(attrs, eq.plusSym))
385  srep.plus = xmlstr(tools::get_attribute(attrs, eq.plusSym));
386  if (tools::has_attribute(attrs, eq.timesSym))
387  srep.times = xmlstr(tools::get_attribute(attrs, eq.timesSym));
388  if (tools::has_attribute(attrs, eq.starSym))
389  srep.star = xmlstr(tools::get_attribute(attrs, eq.starSym));
390  if (tools::has_attribute(attrs, eq.zeroSym))
391  srep.zero = xmlstr(tools::get_attribute(attrs, eq.zeroSym));
392  if (tools::has_attribute(attrs, eq.openWeight))
393  srep.open_weight = xmlstr(tools::get_attribute(attrs, eq.openWeight));
394  if (tools::has_attribute(attrs, eq.closeWeight))
395  srep.close_weight = xmlstr(tools::get_attribute(attrs, eq.closeWeight));
396  if (tools::has_attribute(attrs, eq.spacesSym))
397  {
398  srep.spaces.clear();
399  srep.spaces.push_back(xmlstr(tools::get_attribute(attrs, eq.spacesSym)));
400  }
401 
402  return new SeriesRepresentationHandler<T>(parser, root, srep);
403  }
404 
405  } // ! builders
406 
410  template <typename T>
411  NumSemiringHandler<T>::NumSemiringHandler (xercesc::SAX2XMLReader* parser,
412  Handler& root,
413  T& semiring)
414  : Handler(parser, root),
415  semiring_(semiring),
416  unsuph_(parser, *this)
417  {
418  }
419 
420  template <typename T>
421  void
422  NumSemiringHandler<T>::start (const XMLCh* const,
423  const XMLCh* const localname,
424  const XMLCh* const,
425  const xercesc::Attributes&)
426  {
427  if (xercesc::XMLString::equals(eq_.writingData, localname))
428  parser_->setContentHandler(&unsuph_);
429  else
430  error::token(localname);
431  }
432 
433  template <typename T>
434  void
435  NumSemiringHandler<T>::end (const XMLCh* const,
436  const XMLCh* const localname,
437  const XMLCh* const)
438  {
439  if (xercesc::XMLString::equals(eq_.semiring, localname))
440  parser_->setContentHandler(&root_);
441  else
442  error::token(localname);
443  }
444 
445  namespace builders
446  {
447  template <typename T>
448  typename T::semiring_t*
449  create_semiring (T&,
450  const XMLCh* const localname,
451  const xercesc::Attributes& attrs)
452  {
453  typedef typename T::semiring_t semiring_t;
454  semiring_t* semiring = new semiring_t();
455 
456  typedef typename T::semiring_elt_t semiring_elt_t;
457  semiring_elt_t elt;
458  builders::check_semiring_consistency(elt, localname, attrs);
459 
460  return semiring;
461  }
462 
463  template <typename T>
464  Handler*
465  create_semiringh(T& semiring,
466  const xercesc::Attributes&,
467  xercesc::SAX2XMLReader* parser,
468  Handler& root)
469  {
470  return new NumSemiringHandler<T>(parser, root, semiring);
471  }
472 
473  } // !builders
474 
478  template <typename T>
479  class MonElmtHandler;
480 
481  template <typename T>
482  class WeightHandler;
483 
484  namespace builders
485  {
486 
487  template <typename S, typename T>
488  RegexpHandler<S>*
489  create_monElmth(xercesc::SAX2XMLReader* parser,
490  RegexpHandler<T>& root,
491  S param)
492  {
493  return new MonElmtHandler<S>(parser, root, param);
494  }
495 
496  template <typename T>
497  RegexpHandler<T>*
498  create_weighth(xercesc::SAX2XMLReader* parser,
499  RegexpHandler<T>& root,
500  T param,
501  const xercesc::Attributes& attrs)
502  {
503  typename T::monoid_elt_value_t m =
504  vcsn::algebra::identity_as<typename T::monoid_elt_value_t>::of(param.structure().monoid()).value();
505  const std::string val(xmlstr(tools::get_attribute(attrs, root.eq().value)));
506  std::string::const_iterator i = val.begin();
507  typename T::semiring_elt_t w(param.structure().semiring());
508  if (!parse_weight(w, val, i))
509  error::attrs(tools::get_attribute(attrs, "localname"), "value", val);
510  param.assoc(m, w.value());
511  return new WeightHandler<T>(parser, root, param);
512  }
513  } // !builders
514 
518  namespace builders
519  {
520  // Default.
521  template <class T>
522  const char* get_semiring_set(const T&)
523  { return "undefined"; }
524 
525 # define GET_SEMIRING_SET(T, Value) \
526  const char* get_semiring_set(const T&) \
527  { return Value; }
528 
529  // FIXME: We should not depend on the implementation of the semiring, but on its concept.
530  GET_SEMIRING_SET(bool, "B")
531  GET_SEMIRING_SET(double, "R")
532  GET_SEMIRING_SET(float, "R")
533  GET_SEMIRING_SET(int, "Z")
534  GET_SEMIRING_SET(vcsn::algebra::RationalNumber, "Q")
535 # undef GET_SEMIRING_SET
536 
537  template <class S>
538  const char* get_semiring_operations(const S&)
539  { return "classical"; }
540 
541  template <>
542  const char*
543  get_semiring_operations(const algebra::TropicalSemiring<algebra::TropicalMin>&)
544  { return "minPlus"; }
545 
546  template <>
547  const char*
548  get_semiring_operations(const algebra::TropicalSemiring<algebra::TropicalMax>&)
549  { return "maxPlus"; }
550 
551  // This assumes that n is prime. Actually, because we do
552  // not output n in XML, we only support n==2.
553  template <unsigned int n>
554  const char*
555  get_semiring_operations(const algebra::CyclicSemiring<n>&)
556  { return "field"; }
557 
558  template <typename T>
559  void
560  check_monoid_consistency(T&,
561  const XMLCh* const localname,
562  const xercesc::Attributes& attrs,
563  XMLEq& eq)
564  {
565  const XMLCh* val = tools::get_attribute(attrs, eq.type);
566  if (!xercesc::XMLString::equals(val, eq.free))
567  error::attrs(localname, xmlstr(eq.type), xmlstr(val));
568  };
569 
570  template <typename T>
571  void
572  check_semiring_consistency (T& param,
573  const XMLCh* const localname,
574  const xercesc::Attributes& attrs)
575  {
576  std::string set(xmlstr(tools::get_attribute(attrs, "set")));
577  if (builders::get_semiring_set(param.value()) != set)
578  error::attrs(localname, "set", set);
579  std::string op(xmlstr(tools::get_attribute(attrs, "operations")));
580  if (builders::get_semiring_operations(param.structure()) != op)
581  error::attrs(localname, "operations", op);
582  };
583 
584  template <class T>
585  const char* get_monoid_gen_sort(const T&)
586  { return "undefined"; }
587 # define GET_MONOID_GEN_SORT(T, Value) \
588  const char* get_monoid_gen_sort(const T&) \
589  { return Value; }
590 
591  GET_MONOID_GEN_SORT(char, "letters")
592  GET_MONOID_GEN_SORT(int, "integers")
593 # undef GET_MONOID_GEN_SORT
594 
595  template <class T>
596  const char* get_monoid_gen_sort(const T&, int)
597  { return "undefined"; }
598 
599  template <class U, class V>
600  const char* get_monoid_gen_sort(const std::pair<U,V>& a, int i)
601  {
602  return i ? get_monoid_gen_sort(a.second) : get_monoid_gen_sort(a.first);
603  }
604  } // !builders
605 
606  namespace builders
607  {
608  template <typename T>
609  void
610  create_semiring_node(const T& aut,
611  xercesc::DOMDocument* doc,
612  xercesc::DOMElement* root)
613  {
614  typedef typename T::semiring_elt_t semiring_elt_t;
615  semiring_elt_t semiring(aut.series().semiring());
616  xercesc::DOMElement* node = tools::create_element(doc, "semiring");
617  tools::set_attribute(node, "type", "numerical");
618  tools::set_attribute(node, "set", get_semiring_set(semiring.value()));
619  tools::set_attribute(node, "operations", get_semiring_operations(semiring.structure()));
620  root->appendChild(node);
621  }
622  template <typename T>
623  void
624  create_monoid_node(const T& aut,
625  xercesc::DOMDocument* doc,
626  xercesc::DOMElement* root)
627  {
628  std::string letter_kind = algebra::letter_traits<typename T::monoid_t::alphabet_t::letter_t>::kind();
629  xercesc::DOMElement* node = tools::create_element(doc, "monoid");
630  tools::set_attribute(node, "type", "free");
631  tools::set_attribute(node, "genDescrip", "enum");
632  tools::set_attribute(node, "genKind", letter_kind);
633  root->appendChild(node);
634 
635  xercesc::DOMElement* writingData = tools::create_element(doc, "writingData");
636  tools::set_attribute(writingData, "identitySym", aut.series().monoid().representation()->empty);
637  tools::set_attribute(writingData, "timesSym", aut.series().monoid().representation()->concat);
638  node->appendChild(writingData);
639 
640  typedef typename T::monoid_t::alphabet_t::const_iterator alphabet_iterator;
641 
642  if (letter_kind == "simple")
643  tools::set_attribute(node, "genSort", get_monoid_gen_sort(*(aut.series().monoid().alphabet().begin())));
644  else
645  {
646  std::stringstream genDim;
647  int dim = algebra::letter_traits<typename T::monoid_t::alphabet_t::letter_t>::dim();
648  genDim << dim;
649  tools::set_attribute(node, "genDim", genDim.str());
650  xercesc::DOMElement* genSort = tools::create_element(doc, "genSort");
651  node->appendChild(genSort);
652  xercesc::DOMElement* genCompSort;
653  for (int i = 0; i != dim; i++)
654  {
655  genCompSort = tools::create_element(doc, "genCompSort");
656  tools::set_attribute(genCompSort, "value", get_monoid_gen_sort(*(aut.series().monoid().alphabet().begin()), i));
657  genSort->appendChild(genCompSort);
658  }
659  }
660 
661  create_monGen_node<typename T::monoid_t::alphabet_t::letter_t> monGen_maker;
662  for_all_letters(l, aut.series().monoid().alphabet())
663  monGen_maker(*l, doc, node);
664 
665  }
666 
667  template <typename T>
668  void
669  create_regexp_node(const T& e,
670  xercesc::DOMDocument* doc,
671  xercesc::DOMElement* root,
672  const char* root_name)
673  {
674  typedef typename T::value_t::monoid_elt_value_t monoid_elt_value_t;
675  typedef typename T::value_t::semiring_elt_value_t semiring_elt_value_t;
676  typedef typename rat::exp<monoid_elt_value_t, semiring_elt_value_t> krat_exp_impl_t;
677 
678  typedef Element<typename T::set_t, krat_exp_impl_t > krat_exp_t;
679 
680  krat_exp_t res(e);
681  rat::XmlExpVisitor<monoid_elt_value_t, semiring_elt_value_t> v(doc, root_name);
682  res.value().accept(v);
683  root->appendChild(v.get());
684  }
685 
686  template <typename U>
687  void
688  create_monElmt_node(const U& word,
689  xercesc::DOMDocument* doc,
690  xercesc::DOMElement* root)
691  {
692  xercesc::DOMElement* node;
693 
694  if (word.empty())
695  node = tools::create_element(doc, "one");
696  else
697  {
698  node = tools::create_element(doc, "monElmt");
699  create_monGen_node<typename U::value_type> monGen_maker;
700  for (typename U::const_iterator i = word.begin(); i != word.end(); ++i)
701  monGen_maker(*i, doc, node);
702  }
703  root->appendChild(node);
704  }
705 
706  template <typename T>
707  void
708  create_type_writingData_node(const T& aut,
709  xercesc::DOMDocument* doc,
710  xercesc::DOMElement* root)
711  {
712  xercesc::DOMElement* writingData = tools::create_element(doc, "writingData");
713 
714  // FIXME: we should use XMLEq
715  tools::set_attribute(writingData, "plusSym", aut.series().representation()->plus);
716  tools::set_attribute(writingData, "timesSym", aut.series().representation()->times);
717  tools::set_attribute(writingData, "starSym", aut.series().representation()->star);
718  tools::set_attribute(writingData, "zeroSym", aut.series().representation()->zero);
719  tools::set_attribute(writingData, "weightOpening", aut.series().representation()->open_weight);
720  tools::set_attribute(writingData, "weightClosing", aut.series().representation()->close_weight);
721  tools::set_attribute(writingData, "openPar", aut.series().representation()->open_par);
722  tools::set_attribute(writingData, "closePar", aut.series().representation()->close_par);
723  tools::set_attribute(writingData, "spacesSym", aut.series().representation()->spaces.front());
724 
725  root->appendChild(writingData);
726  }
727 
728  // FIXME: We should be able to specialize for all type U,
729  // whose letter_traits::kind() is "simple".
730  template <typename U>
731  struct create_monGen_node
732  {
733  void
734  operator()(const U& letter,
735  xercesc::DOMDocument* doc,
736  xercesc::DOMElement* root)
737  {
738  xercesc::DOMElement* gen = tools::create_element(doc, "monGen");
739 
740  tools::set_attribute(gen, "value",
741  algebra::letter_traits<U>::
742  letter_to_literal(letter));
743 
744  root->appendChild(gen);
745  }
746  };
747 
748  // FIXME: We should be able to specialize for all type U,
749  // whose kind() is "tuple" and dim() is 2 and has_first is
750  // true and has_second is true.
751  template <typename U, typename V>
752  struct create_monGen_node<std::pair<U, V> >
753  {
754  void
755  operator()(const std::pair<U, V>& letter,
756  xercesc::DOMDocument* doc,
757  xercesc::DOMElement* root)
758  {
759  xercesc::DOMElement* gen = tools::create_element(doc, "monGen");
760 
761  std::stringstream sstr_first;
762  std::stringstream sstr_second;
763  xercesc::DOMElement* first = tools::create_element(doc, "monCompGen");
764  xercesc::DOMElement* second = tools::create_element(doc, "monCompGen");
765  sstr_first << letter.first;
766  sstr_second << letter.second;
767  tools::set_attribute(first, "value", sstr_first.str());
768  tools::set_attribute(second, "value", sstr_second.str());
769  gen->appendChild(first);
770  gen->appendChild(second);
771 
772  root->appendChild(gen);
773  }
774  };
775 
776  } // ! builders
777 
778  } // ! xml
779 
780 } // ! vcsn
781 
782 #endif // ! VCSN_XML_BUILDERS_HXX