texinfo-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

texinfo/tp Texinfo/Convert/XML.pm t/results/mis...


From: Patrice Dumas
Subject: texinfo/tp Texinfo/Convert/XML.pm t/results/mis...
Date: Tue, 15 Jan 2013 19:10:20 +0000

CVSROOT:        /sources/texinfo
Module name:    texinfo
Changes by:     Patrice Dumas <pertusus>        13/01/15 19:10:20

Modified files:
        tp/Texinfo/Convert: XML.pm 
        tp/t/results/misc_commands: definfoenclose_with_empty_arg.pl 
        tp/t/results/xtable: definfoenclose_on_table_line.pl 

Log message:
        Use function to abstract XML specific output, to ease outputting 
        something different and also have consistent output.

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/texinfo/tp/Texinfo/Convert/XML.pm?cvsroot=texinfo&r1=1.93&r2=1.94
http://cvs.savannah.gnu.org/viewcvs/texinfo/tp/t/results/misc_commands/definfoenclose_with_empty_arg.pl?cvsroot=texinfo&r1=1.4&r2=1.5
http://cvs.savannah.gnu.org/viewcvs/texinfo/tp/t/results/xtable/definfoenclose_on_table_line.pl?cvsroot=texinfo&r1=1.21&r2=1.22

Patches:
Index: Texinfo/Convert/XML.pm
===================================================================
RCS file: /sources/texinfo/texinfo/tp/Texinfo/Convert/XML.pm,v
retrieving revision 1.93
retrieving revision 1.94
diff -u -b -r1.93 -r1.94
--- Texinfo/Convert/XML.pm      15 Jan 2013 01:25:51 -0000      1.93
+++ Texinfo/Convert/XML.pm      15 Jan 2013 19:10:17 -0000      1.94
@@ -1,6 +1,6 @@
-# XML.pm: output tree as Texinfo XML.
+# XML.pm: output tree as elements with attributes, defaulting to XML.
 #
-# Copyright 2011, 2012 Free Software Foundation, Inc.
+# Copyright 2011, 2012, 2013 Free Software Foundation, Inc.
 # 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -54,6 +54,7 @@
 
 $VERSION = '5.0';
 
+# XML specific
 my %defaults = (
   'ENABLE_ENCODING'      => 0,
   'SHOW_MENU'            => 1,
@@ -69,59 +70,218 @@
 );
 
 
-my %specific_xml_commands_formatting = (
-           '*' => '&linebreak;',
-           ' ' => '<spacecmd type="spc"/>',
-           "\t" => '<spacecmd type="tab"/>',
-           "\n" => '<spacecmd type="nl"/>',
-           '-' => '&hyphenbreak;',  # hyphenation hint
+our %commands_formatting = (
+           '*' => 'linebreak',
+           ' ' => ['spacecmd', 'type', 'spc'],
+           "\t" => ['spacecmd', 'type', 'tab'],
+           "\n" => ['spacecmd', 'type', 'nl'],
+           '-' => 'hyphenbreak',  # hyphenation hint
            '|' => '',  # used in formatting commands @evenfooting and friends
-           '/' => '&slashbreak;',
-           ':' => '&noeos;',
-           '!' => '&eosexcl;',
-           '?' => '&eosquest;',
-           '.' => '&eosperiod;',
-           '@' => '&arobase;',
-           '{' => '&lbrace;',
-           '}' => '&rbrace;',
-           '\\' => '&backslash;',  # should only appear in math
-
-           'TeX' => '&tex;',
-           'LaTeX' => '&latex;',
-           'bullet' => '&bullet;',
-           'copyright'    => '&copyright;',
-           'registeredsymbol'   => '&registered;',
-           'dots'    => '&dots;',
-           'enddots'    => '&enddots;',
-           'error'        => '&errorglyph;',
-           'expansion'     => '&expansion;',
-           'arrow'        => '&rarr;',
-           'click'        => '<click command="arrow"/>',
-           'minus'        => '&minus;',
-           'point'        => '&point;',
-           'print'        => '&printglyph;',
-           'result'       => '&result;',
-           'l'            => '&lslash;',
-           'L'            => '&Lslash;',
-           'today'        => '<today/>',
-           'comma'        => '&comma;',
-           'atchar'       => '&atchar;',
-           'lbracechar'   => '&lbracechar;',
-           'rbracechar'   => '&rbracechar;',
-           'backslashchar' => '&backslashchar;',
-           'hashchar'      => '&hashchar;',
+           '/' => 'slashbreak',
+           ':' => 'noeos',
+           '!' => 'eosexcl',
+           '?' => 'eosquest',
+           '.' => 'eosperiod',
+           '@' => 'arobase',
+           '{' => 'lbrace',
+           '}' => 'rbrace',
+           '\\' => 'backslash',  # should only appear in math
+
+           'TeX' => 'tex',
+           'LaTeX' => 'latex',
+           'bullet' => 'bullet',
+           'copyright'    => 'copyright',
+           'registeredsymbol'   => 'registered',
+           'dots'    => 'dots',
+           'enddots'    => 'enddots',
+           'error'        => 'errorglyph',
+           'expansion'     => 'expansion',
+           'arrow'        => 'rarr',
+           'click'        => ['click', 'command', 'arrow'],
+           'minus'        => 'minus',
+           'point'        => 'point',
+           'print'        => 'printglyph',
+           'result'       => 'result',
+           'l'            => 'lslash',
+           'L'            => 'Lslash',
+           'today'        => ['today'],
+           'comma'        => 'comma',
+           'atchar'       => 'atchar',
+           'lbracechar'   => 'lbracechar',
+           'rbracechar'   => 'rbracechar',
+           'backslashchar' => 'backslashchar',
+           'hashchar'      => 'hashchar',
 );
 
-# our because it is used in the xml to texi translator
-our %xml_commands_formatting
-  = %{$Texinfo::Convert::Converter::default_xml_commands_formatting{'normal'}};
+# use default XML formatting to complete the hash, removing XML
+# specific formatting.  This avoids some duplication.
+my %default_xml_commands_formatting = 
+    %{$Texinfo::Convert::Converter::default_xml_commands_formatting{'normal'}};
+
+foreach my $command (keys(%default_xml_commands_formatting)) {
+  if (!exists($commands_formatting{$command})) {
+    if ($default_xml_commands_formatting{$command} ne '') {
+      if ($default_xml_commands_formatting{$command} =~ /^&(.*);$/) {
+        $commands_formatting{$command} = $1;
+      } else {
+        die "BUG: Strange xml_commands_formatting: 
$default_xml_commands_formatting{$command}\n";
+      }
+    } else {
+      $commands_formatting{$command} = '';
+    }
+  }
+}
+
+
+# Following are XML specific formatting functions.
+
+# format specific.  Used in few places where plain text is used outside
+# of attributes.
+sub protect_text($$)
+{
+  my $self = shift;
+  my $string = shift;
+  return $self->xml_protect_text($string);
+}
+
+sub _xml_attributes($$)
+{
+  my $self = shift;
+  my $attributes = shift;
+  if (ref($attributes) ne 'ARRAY') {
+    cluck "attributes not an array($attributes).";
+  }
+  my $result = '';
+  for (my $i = 0; $i < scalar(@$attributes); $i += 2) {
+    $result .= " 
$attributes->[$i]=\"".$self->xml_protect_text($attributes->[$i+1])."\"";
+  }
+  return $result;
+}
+
+# format specific
+sub element($$$)
+{
+  my $self = shift;
+  my $element_name = shift;
+  my $attributes = shift;
+  my $result= '<'.$element_name;
+  $result .= $self->_xml_attributes($attributes) if ($attributes);
+  $result .= '/>';
+  return $result;
+}
+
+# format specific
+sub open_element($$$)
+{
+  my $self = shift;
+  my $element_name = shift;
+  my $attributes = shift;
+  my $result= '<'."$element_name";
+  $result .= $self->_xml_attributes($attributes) if ($attributes);
+  $result .= '>';
+  return $result;
+}
+
+# format specific
+sub close_element($$)
+{
+  my $self = shift;
+  my $element_name = shift;
+  my $result= "</$element_name>";
+  return $result;
+}
 
-foreach my $command (keys(%specific_xml_commands_formatting)) {
-  $xml_commands_formatting{$command}
-    = $specific_xml_commands_formatting{$command}
+# format specific
+sub format_atom($$)
+{
+  my $self = shift;
+  my $atom = shift;
+  if ($commands_formatting{$atom} ne '') {
+    return '&'.$commands_formatting{$atom}.';';
+  } else {
+    return '';
+  }
 }
 
-my %xml_accents = (
+# format specific
+sub format_comment($$)
+{
+  my $self = shift;
+  my $string = shift;
+
+  return $self->xml_comment($string);
+}
+
+# format specific
+sub format_text($$)
+{
+  my $self = shift;
+  my $root = shift;
+  my $result = $self->xml_protect_text($root->{'text'});
+  if (! defined($root->{'type'}) or $root->{'type'} ne 'raw') {
+    if (!$self->{'document_context'}->[-1]->{'monospace'}->[-1]) {
+      $result =~ s/``/&textldquo;/g;
+      $result =~ s/\'\'/&textrdquo;/g;
+      $result =~ s/---/&textmdash;/g;
+      $result =~ s/--/&textndash;/g;
+      $result =~ s/'/&textrsquo;/g;
+      $result =~ s/`/&textlsquo;/g;
+    }
+  }
+  return $result;
+}
+
+# output format specific
+sub format_header($)
+{
+  my $self = shift;
+  my $encoding = '';
+  if ($self->get_conf('OUTPUT_ENCODING_NAME')
+      and $self->get_conf('OUTPUT_ENCODING_NAME') ne 'utf-8') {
+    $encoding = " encoding=\"".$self->get_conf('OUTPUT_ENCODING_NAME')."\" ";
+  }
+  my $texinfo_dtd_version = $self->get_conf('TEXINFO_DTD_VERSION');
+  if (!defined($texinfo_dtd_version)) {
+    $texinfo_dtd_version = '1.00';
+  }
+
+  my $header =  "<?xml version=\"1.0\"${encoding}?>".'
+<!DOCTYPE texinfo PUBLIC "-//GNU//DTD TexinfoML V'.$texinfo_dtd_version.'//EN" 
"http://www.gnu.org/software/texinfo/dtd/'.$texinfo_dtd_version.'/texinfo.dtd">
+'. $self->open_element('texinfo', ['xml:lang', 
$self->get_conf('documentlanguage')])."\n";
+  if ($self->{'output_file'} ne '') {
+    my $output_filename = $self->{'output_filename'};
+    $header .= $self->open_element('filename',['file', $output_filename])
+             .$self->close_element('filename')."\n";
+  }
+  return $header;
+}
+
+sub _format_command($$)
+{
+  my $self = shift;
+  my $command = shift;
+
+  if (! ref($commands_formatting{$command})) {
+    return $self->format_atom($command);
+  } else {
+    my @spec = @{$commands_formatting{$command}};
+    my $element_name = shift @spec;
+    return $self->element($element_name, address@hidden);
+  }
+}
+
+
+# XML specific hash.  Not used directly here, but available for other modules.
+our %xml_commands_formatting;
+foreach my $command (keys(%commands_formatting)) {
+  $xml_commands_formatting{$command} = 
Texinfo::Convert::XML->_format_command($command);
+}
+
+
+# following is not format specific.  Some infos are taken from generic XML, 
but 
+# XML specific formatting is stripped.
+
+my %accents = (
  '=' => 'macr',
 # following are not entities
  'H' => 'doubleacute',
@@ -129,14 +289,17 @@
  'v' => 'caron',
 );
 
-our %xml_accent_types = (%Texinfo::Convert::Converter::xml_accent_entities, 
%xml_accents);
+our %accent_types = (%Texinfo::Convert::Converter::xml_accent_entities, 
%accents);
 
 # no entity
 my @other_accents = ('dotaccent', 'tieaccent', 'ubaraccent', 'udotaccent');
 foreach my $accent (@other_accents) {
-  $xml_accent_types{$accent} = $accent;
+  $accent_types{$accent} = $accent;
 }
 
+# our because it is used in the xml to texi translator
+our %xml_accent_types = %accent_types;
+
 my %misc_command_line_attributes = (
   'setfilename' => 'file',
   'documentencoding' => 'encoding',
@@ -151,11 +314,11 @@
   'synindex' => [ 'from', 'to' ],
 );
 
-my %xml_misc_commands = %Texinfo::Common::misc_commands;
+my %misc_commands = %Texinfo::Common::misc_commands;
 
 foreach my $command ('item', 'headitem', 'itemx', 'tab', 
                       keys %Texinfo::Common::def_commands) {
-  delete $xml_misc_commands{$command};
+  delete $misc_commands{$command};
 }
 
 my %default_args_code_style
@@ -286,29 +449,10 @@
 
   $self->_set_global_multiple_commands(-1);
 
-  my $encoding = '';
-  if ($self->get_conf('OUTPUT_ENCODING_NAME')
-      and $self->get_conf('OUTPUT_ENCODING_NAME') ne 'utf-8') {
-    $encoding = " encoding=\"".$self->get_conf('OUTPUT_ENCODING_NAME')."\" ";
-  }
-  my $texinfo_dtd_version = $self->get_conf('TEXINFO_DTD_VERSION');
-  if (!defined($texinfo_dtd_version)) {
-    $texinfo_dtd_version = '1.00';
-  }
-
-  my $header =  "<?xml version=\"1.0\"${encoding}?>".'
-<!DOCTYPE texinfo PUBLIC "-//GNU//DTD TexinfoML V'.$texinfo_dtd_version.'//EN" 
"http://www.gnu.org/software/texinfo/dtd/'.$texinfo_dtd_version.'/texinfo.dtd">
-<texinfo xml:lang="' . $self->get_conf('documentlanguage') ."\">\n";
-  if ($self->{'output_file'} ne '') {
-    my $output_filename = $self->{'output_filename'};
-    $header .= "<filename file=\"".$self->xml_protect_text($output_filename)
-                ."\"></filename>\n";
-  }
-
   my $result = '';
-  $result .= $self->_output_text($header, $fh);
+  $result .= $self->_output_text($self->format_header(), $fh);
   $result .= $self->convert_document_sections($root, $fh);
-  $result .= $self->_output_text("</texinfo>\n", $fh);
+  $result .= $self->_output_text($self->close_element('texinfo')."\n", $fh);
   if ($fh and $self->{'output_file'} ne '-') {
     $self->register_close_file($self->{'output_file'});
     if (!close ($fh)) {
@@ -326,26 +470,27 @@
   my $root = shift;
   if ($root->{'extra'} and $root->{'extra'}->{'index_entry'}) {
     my $index_entry = $root->{'extra'}->{'index_entry'};
-    my $attribute = '';
+    my $attribute = ['index', $index_entry->{'index_name'}];
     # in case the index is not a default index, or the style of the
     # entry (in code or not) is not the default for this index
     if ($self->{'index_names'}) {
       my $in_code = 
$self->{'index_names'}->{$index_entry->{'index_name'}}->{'in_code'};
       if (!$Texinfo::Common::index_names{$index_entry->{'index_name'}}
           or $in_code != 
$Texinfo::Common::index_names{$index_entry->{'index_name'}}->{'in_code'}) {
-        $attribute .= " incode=\"$in_code\"";
+        push @$attribute, ('incode', $in_code);
       }
       if 
($self->{'index_names'}->{$index_entry->{'index_name'}}->{'merged_in'}) {
-        $attribute .= " 
mergedindex=\"$self->{'index_names'}->{$index_entry->{'index_name'}}->{'merged_in'}\"";
+        push @$attribute, ('mergedindex', 
+         
$self->{'index_names'}->{$index_entry->{'index_name'}}->{'merged_in'});
       }
     }
-    my $result = "<indexterm 
index=\"$index_entry->{'index_name'}\"${attribute}>";
+    my $result = $self->open_element('indexterm', $attribute);
     push @{$self->{'document_context'}}, {'monospace' => [0]};
     $self->{'document_context'}->[-1]->{'monospace'}->[-1] = 1
       if ($index_entry->{'in_code'});
     $result .= $self->_convert({'contents' => $index_entry->{'content'}});
     pop @{$self->{'document_context'}};
-    $result .= "</indexterm>";
+    $result .= $self->close_element('indexterm');
     return $result;
   }
   return '';
@@ -354,29 +499,28 @@
 sub _infoenclose_attribute($$) {
   my $self = shift;
   my $root = shift;
-  my $attribute = '';
-  return '' if (!$root->{'extra'});
-  $attribute .= " begin=\"".
-        $self->xml_protect_text($root->{'extra'}->{'begin'})."\""
+  my @attribute = ();
+  return @attribute if (!$root->{'extra'});
+  push @attribute, ('begin', $root->{'extra'}->{'begin'})
     if (defined($root->{'extra'}->{'begin'}));
-  $attribute .= "  end=\"".
-        $self->xml_protect_text($root->{'extra'}->{'end'})."\""
+  push @attribute, ('end', $root->{'extra'}->{'end'})
     if (defined($root->{'extra'}->{'end'}));
-  return $attribute;
+  return @attribute;
 }
 
-sub _texinfo_xml_accent($$$;$$)
+sub _accent($$;$$$)
 {
   my $self = shift;
   my $text = shift;
   my $root = shift;
   my $in_upper_case = shift;
   my $attributes = shift;
-  $attributes = '' if (!defined($attributes));
+  $attributes = [] if (!defined($attributes));
 
-  my $result = "<accent 
type=\"$xml_accent_types{$root->{'cmdname'}}\"${attributes}>";
+  unshift @$attributes, ('type', $accent_types{$root->{'cmdname'}});
+  my $result = $self->open_element('accent', $attributes);
   $result .= $text;
-  $result .= '</accent>';
+  $result .= $self->close_element('accent');
   return $result;
 }
 
@@ -409,10 +553,10 @@
   my $root = shift;
   if ($root->{'extra'} and $root->{'extra'}->{'spaces_after_command'}
       and $root->{'extra'}->{'spaces_after_command'}->{'type'} eq 
'empty_spaces_after_command') {
-    return " spaces=\""._protect_end_of_lines(
-         $root->{'extra'}->{'spaces_after_command'}->{'text'})."\"";
+    return ('spaces', _protect_end_of_lines(
+         $root->{'extra'}->{'spaces_after_command'}->{'text'}));
   } else {
-    return '';
+    return ();
   }
 }
 
@@ -422,10 +566,10 @@
   if ($root->{'extra'} and $root->{'extra'}->{'spaces_before_argument'}
       and $root->{'extra'}->{'spaces_before_argument'}->{'type'} eq 
'empty_spaces_before_argument'
       and $root->{'extra'}->{'spaces_before_argument'}->{'text'} ne '') {
-    return " spaces=\""._protect_end_of_lines(
-                 $root->{'extra'}->{'spaces_before_argument'}->{'text'})."\"";
+    return ('spaces', _protect_end_of_lines(
+                 $root->{'extra'}->{'spaces_before_argument'}->{'text'}));
   } else {
-    return '';
+    return ();
   }
 }
 
@@ -462,10 +606,10 @@
     my $line = $root->{'extra'}->{'arg_line'};
     chomp($line);
     if ($line ne '') {
-      return " line=\"".$self->xml_protect_text($line)."\"";
+      return ('line', $line);
     }
   } 
-  return '';
+  return ();
 }
 
 sub _trailing_spaces_arg($$)
@@ -477,10 +621,10 @@
   if (defined($spaces[1])) {
     chomp($spaces[1]);
     if ($spaces[1] ne '') {
-      return " trailingspaces=\"$spaces[1]\"";
+      return ('trailingspaces', $spaces[1]);
     }
   }
-  return '';
+  return ();
 }
 
 sub _leading_spaces_arg($$)
@@ -488,12 +632,12 @@
   my $self = shift;
   my $root = shift;
 
-  my $result = '';
+  my @result = ();
   my @spaces = $self->_collect_leading_trailing_spaces_arg($root);
   if (defined($spaces[0]) and $spaces[0] ne '') {
-    $result .= " spaces=\""._protect_end_of_lines($spaces[0])."\"";
+    @result = ('spaces', _protect_end_of_lines($spaces[0]));
   }
-  return $result;
+  return @result;
 }
 
 sub _leading_trailing_spaces_arg($$)
@@ -501,18 +645,18 @@
   my $self = shift;
   my $root = shift;
 
-  my $result = '';
+  my @result;
   my @spaces = $self->_collect_leading_trailing_spaces_arg($root);
   if (defined($spaces[0]) and $spaces[0] ne '') {
-    $result .= " spaces=\""._protect_end_of_lines($spaces[0])."\"";
+    push @result, ('spaces', _protect_end_of_lines($spaces[0]));
   }
   if (defined($spaces[1])) {
     chomp($spaces[1]);
     if ($spaces[1] ne '') {
-      $result .= " trailingspaces=\"$spaces[1]\"";
+      push @result, ('trailingspaces', $spaces[1]);
     }
   }
-  return $result;
+  return @result;
 }
 
 sub _texinfo_line($$)
@@ -525,16 +669,16 @@
   my $line = Texinfo::Convert::Texinfo::convert($tree);
   chomp($line);
   if ($line ne '') {
-    return ' line="'.$self->xml_protect_text($line).'"';
+    return ('line', $line);
   } else {
-    return '';
+    return ();
   }
 }
 
 my @node_directions = ('Next', 'Prev', 'Up');
 
-# not used here, but it is consistent and may be used 
-# by XML to Texinfo converters
+# not used here, but it is consistent with other %commands_args_elements
+# entries and may be used by XML to Texinfo converters
 $commands_args_elements{'node'} = ['nodename'];
 foreach my $direction (@node_directions) {
   push @{$commands_args_elements{'node'}}, 'node'.lc($direction);
@@ -569,7 +713,8 @@
         return $root->{'text'};
       }
     } elsif ($root->{'type'} 
-             and $root->{'type'} eq 'empty_line_after_command') {
+             and $root->{'type'} eq 'empty_line_after_command'
+             and $root->{'extra'}->{'command'}) {
       my $command_name = $root->{'extra'}->{'command'}->{'cmdname'};
       
       if ($Texinfo::Common::format_raw_commands{$command_name} and 
@@ -577,50 +722,40 @@
         return '';
       }
     }
-    $result = $self->xml_protect_text($root->{'text'});
-    if (! defined($root->{'type'}) or $root->{'type'} ne 'raw') {
-      if (!$self->{'document_context'}->[-1]->{'monospace'}->[-1]) {
-        $result =~ s/``/&textldquo;/g;
-        $result =~ s/\'\'/&textrdquo;/g;
-        $result =~ s/---/&textmdash;/g;
-        $result =~ s/--/&textndash;/g;
-        $result =~ s/'/&textrsquo;/g;
-        $result =~ s/`/&textlsquo;/g;
-      }
-    }
+    $result = $self->format_text($root);
     return $result;
   }
   my @close_elements;
   if ($root->{'cmdname'}) {
-    if (defined($xml_commands_formatting{$root->{'cmdname'}})) {
+    if (defined($commands_formatting{$root->{'cmdname'}})) {
       if ($root->{'cmdname'} eq 'click' 
           and $root->{'extra'} 
           and defined($root->{'extra'}->{'clickstyle'})) {
-        return "<click command=\"$root->{'extra'}->{'clickstyle'}\"/>";
+        return $self->element('click', ['command', 
$root->{'extra'}->{'clickstyle'}]);;
       }
       if ($self->{'itemize_line'} and $root->{'type'} 
           and $root->{'type'} eq 'command_as_argument'
           and !$root->{'args'}) {
-        return "<formattingcommand command=\"$root->{'cmdname'}\"/>";
+        return $self->element('formattingcommand', ['command', 
$root->{'cmdname'}]);
       }
-      return $xml_commands_formatting{$root->{'cmdname'}};
-    } elsif ($xml_accent_types{$root->{'cmdname'}}) {
+      return $self->_format_command($root->{'cmdname'});
+    } elsif ($accent_types{$root->{'cmdname'}}) {
       if ($self->get_conf('ENABLE_ENCODING')) {
-        return $self->convert_accents($root, \&_texinfo_xml_accent);
+        return $self->convert_accents($root, \&_accent);
       } else {
-        my $attributes = '';
+        my $attributes = [];
         if (!$root->{'args'}) {
           $result = '';
         } else {
           $result = $self->_convert($root->{'args'}->[0]);
           if ($root->{'extra'} and $root->{'extra'}->{'spaces'}) {
-            $attributes .= " spaces=\"$root->{'extra'}->{'spaces'}\"";
+            push @$attributes,  ('spaces', $root->{'extra'}->{'spaces'});
           }
           if ($root->{'args'}->[0]->{'type'} eq 'following_arg') {
-             $attributes .= ' bracketed="off"';
+             push @$attributes, ('bracketed', 'off');
           }
         }
-        return $self->_texinfo_xml_accent($result, $root,  undef, $attributes);
+        return $self->_accent($result, $root,  undef, $attributes);
       }
     } elsif ($root->{'cmdname'} eq 'item' or $root->{'cmdname'} eq 'itemx'
              or $root->{'cmdname'} eq 'headitem' or $root->{'cmdname'} eq 
'tab') {
@@ -628,15 +763,15 @@
           and $root->{'parent'}->{'cmdname'}
           and ($root->{'parent'}->{'cmdname'} eq 'itemize'
                or $root->{'parent'}->{'cmdname'} eq 'enumerate')) {
-        $result .= "<listitem"._leading_spaces($root).">";
+        $result .= $self->open_element('listitem', [_leading_spaces($root)]);
         if ($root->{'parent'}->{'cmdname'} eq 'itemize'
             and $root->{'parent'}->{'extra'} 
             and $root->{'parent'}->{'extra'}->{'block_command_line_contents'}
             and 
$root->{'parent'}->{'extra'}->{'block_command_line_contents'}->[0]) {
-          $result .= "<prepend>"
+          $result .= $self->open_element('prepend')
             .$self->_convert({'contents' 
         => $root->{'parent'}->{'extra'}->{'block_command_line_contents'}->[0]})
-            ."</prepend>";
+            .$self->close_element('prepend');
         }
         unshift @close_elements, 'listitem';
       } elsif (($root->{'cmdname'} eq 'item' or $root->{'cmdname'} eq 'itemx')
@@ -644,17 +779,17 @@
                and $root->{'parent'}->{'type'} eq 'table_term') {
         my $table_command = $root->{'parent'}->{'parent'}->{'parent'};
         my $format_item_command;
-        my $attribute;
+        my $attribute = [];
         if ($table_command->{'extra'} 
             and $table_command->{'extra'}->{'command_as_argument'}) {
           $format_item_command 
             = $table_command->{'extra'}->{'command_as_argument'}->{'cmdname'};
           $attribute 
-           = 
$self->_infoenclose_attribute($table_command->{'extra'}->{'command_as_argument'});
+           = 
[$self->_infoenclose_attribute($table_command->{'extra'}->{'command_as_argument'})];
         }
-        $result .= "<$root->{'cmdname'}"._leading_spaces($root).">";
+        $result .= $self->open_element($root->{'cmdname'}, 
[_leading_spaces($root)]);
         if ($format_item_command) {
-          $result .= "<itemformat 
command=\"$format_item_command\"${attribute}>";
+          $result .=  $self->open_element('itemformat', ['command', 
$format_item_command, @$attribute]);
         }
         $result .= $self->_index_entry($root);
         my $in_code;
@@ -680,9 +815,9 @@
           if (defined($in_monospace_not_normal));
         chomp ($result);
         if ($format_item_command) {
-          $result .= "</itemformat>";
+          $result .= $self->close_element('itemformat');
         }
-        $result .= "</$root->{'cmdname'}>\n";
+        $result .= $self->close_element($root->{'cmdname'})."\n";
       } else {
         unless (($root->{'cmdname'} eq 'item' 
                      or $root->{'cmdname'} eq 'headitem'
@@ -693,22 +828,21 @@
             .Texinfo::Parser::_print_current($root);
         }
         
-        $result .= "<entry command=\"$root->{'cmdname'}\""
-                                  ._leading_spaces($root).">";
+        $result .= $self->open_element('entry', ['command', 
+               $root->{'cmdname'}, _leading_spaces($root)]);
         unshift @close_elements, 'entry';
       }
     } elsif ($root->{'type'} and $root->{'type'} eq 'index_entry_command') {
       my $element;
-      my $attribute;
+      my $attribute = [];
       if (exists $Texinfo::Common::misc_commands{$root->{'cmdname'}}) {
         $element = $root->{'cmdname'};
-        $attribute = '';
       } else {
-        $element = "indexcommand";
-        $attribute = " command=\"$root->{'cmdname'}\"";
+        $element = 'indexcommand';
+        $attribute = ['command', $root->{'cmdname'}];
       }
-      $attribute .= " 
index=\"$root->{'extra'}->{'index_entry'}->{'index_name'}\"";
-      $attribute .= _leading_spaces($root);
+      push @$attribute, ('index', 
$root->{'extra'}->{'index_entry'}->{'index_name'});
+      push @$attribute, _leading_spaces($root);
       my $end_line;
       if ($root->{'args'}->[0]) {
         $end_line = 
$self->_end_line_or_comment($root->{'args'}->[0]->{'contents'});
@@ -716,23 +850,25 @@
         # May that happen?
         $end_line = '';
       }
-      return 
"<$element${attribute}>".$self->_index_entry($root)."</$element>${end_line}";
-    } elsif (exists($xml_misc_commands{$root->{'cmdname'}})) {
+      return $self->open_element($element, ${attribute}).
+        $self->_index_entry($root).$self->close_element($element).${end_line};
+    } elsif (exists($misc_commands{$root->{'cmdname'}})) {
       my $command = $root->{'cmdname'};
-      my $type = $xml_misc_commands{$root->{'cmdname'}};
+      my $type = $misc_commands{$root->{'cmdname'}};
       if ($type eq 'text') {
         return '' if ($root->{'cmdname'} eq 'end');
-        my $attribute = '';
+        my $attribute;
         if ($misc_command_line_attributes{$root->{'cmdname'}}) {
           if ($root->{'extra'} and defined($root->{'extra'}->{'text_arg'})) {
-            $attribute = " 
$misc_command_line_attributes{$root->{'cmdname'}}=\""
-                . $self->xml_protect_text($root->{'extra'}->{'text_arg'}) 
."\"";
+            push @$attribute, 
($misc_command_line_attributes{$root->{'cmdname'}},
+                  $root->{'extra'}->{'text_arg'});
           }
         }
         my ($arg, $end_line)
             = $self->_convert_argument_and_end_line($root->{'args'}->[0]);
-        return "<$command${attribute}"._leading_spaces($root).
-                                          ">$arg</$command>$end_line";
+        push @$attribute, _leading_spaces($root);
+        return $self->open_element($command, $attribute).$arg
+                .$self->close_element($command).${end_line};
       } elsif ($type eq 'line') {
         if ($root->{'cmdname'} eq 'node') {
           my $nodename;
@@ -741,11 +877,13 @@
           } else {
             $nodename = '';
           }
-          $result .= "<node name=\"$nodename\""._leading_spaces($root).">";
+          # FIXME avoid protection, here?
+          $result .= $self->open_element('node', ['name', $nodename, 
_leading_spaces($root)]);
           push @{$self->{'document_context'}->[-1]->{'monospace'}}, 1;
-          $result .= 
"<nodename".$self->_trailing_spaces_arg($root->{'args'}->[0]).">".
-             $self->_convert({'contents' => 
$root->{'extra'}->{'node_content'}})
-             ."</nodename>";
+          $result .= $self->open_element('nodename', 
+            [$self->_trailing_spaces_arg($root->{'args'}->[0])])
+             .$self->_convert({'contents' => 
$root->{'extra'}->{'node_content'}})
+             .$self->close_element('nodename');
           # first arg is the node name.
           my $direction_index = 1;
           my $pending_empty_directions = '';
@@ -754,12 +892,12 @@
             if ($root->{'node_'.lc($direction)}) {
               my $node_direction = $root->{'node_'.lc($direction)};
               my $node_name = '';
-              my $attribute = '';
+              my $attribute = [];
               if (! 
defined($root->{'extra'}->{'nodes_manuals'}->[$direction_index])) {
-                $attribute = ' automatic="on"';
+                push @$attribute, ('automatic', 'on');
               }
               if ($root->{'args'}->[$direction_index]) {
-                $attribute .= $self->_leading_trailing_spaces_arg(
+                push @$attribute, $self->_leading_trailing_spaces_arg(
                                  $root->{'args'}->[$direction_index]);
               }
               if ($node_direction->{'extra'}->{'manual_content'}) {
@@ -772,14 +910,18 @@
                 $node_name .= 
Texinfo::Common::normalize_top_node_name($self->_convert({
                   'contents' => 
$node_direction->{'extra'}->{'node_content'}}));
               }
-              $result .= 
"$pending_empty_directions<$element${attribute}>$node_name</$element>";
+              $result .= "$pending_empty_directions".
+                $self->open_element($element, ${attribute}).$node_name.
+                $self->close_element($element);
               $pending_empty_directions = '';
             } else {
               if ($root->{'args'}->[$direction_index]) {
                 my $spaces_attribute = $self->_leading_trailing_spaces_arg(
                                  $root->{'args'}->[$direction_index]);
-                $pending_empty_directions .= "<$element${spaces_attribute}>".
-                                             "</$element>";
+                $pending_empty_directions .= $self->open_element($element,
+                    [$self->_leading_trailing_spaces_arg(
+                                 $root->{'args'}->[$direction_index])])
+                            .$self->close_element($element);
               }
             }
             $direction_index++;
@@ -791,32 +933,32 @@
           } else {
             $end_line = "\n";
           }
-          $result .= "</node>${end_line}";
+          $result .= $self->close_element('node').${end_line};
           pop @{$self->{'document_context'}->[-1]->{'monospace'}};
         } elsif ($Texinfo::Common::root_commands{$root->{'cmdname'}}) {
-          my $attribute;
+          my $attribute = [_leading_spaces($root)];
           $command = $self->_level_corrected_section($root);
           if ($command ne $root->{'cmdname'}) {
-            $attribute = " originalcommand=\"$root->{'cmdname'}\"";
-          } else {
-            $attribute = '';
+            unshift @$attribute, ('originalcommand', $root->{'cmdname'});
           }
-          $result .= "<$command${attribute}"._leading_spaces($root).">";
+          $result .= $self->open_element($command, $attribute);
           if ($root->{'args'} and $root->{'args'}->[0]) {
             my ($arg, $end_line)
               = $self->_convert_argument_and_end_line($root->{'args'}->[0]);
-            $result .= "<sectiontitle>$arg</sectiontitle>$end_line"
+            $result .= $self->open_element('sectiontitle').$arg
+                      .$self->close_element('sectiontitle').$end_line;
           }
         } else {
-          my $attribute = '';
+          my $attribute = [_leading_spaces($root)];
           if ($root->{'cmdname'} eq 'listoffloats' and $root->{'extra'} 
               and $root->{'extra'}->{'type'} 
               and defined($root->{'extra'}->{'type'}->{'normalized'})) {
-            $attribute = " 
type=\"$root->{'extra'}->{'type'}->{'normalized'}\"";
+            unshift @$attribute, ('type', 
$root->{'extra'}->{'type'}->{'normalized'});
           }
           my ($arg, $end_line)
             = $self->_convert_argument_and_end_line($root->{'args'}->[0]);
-          return 
"<$command${attribute}"._leading_spaces($root).">$arg</$command>$end_line";
+          return $self->open_element($command, ${attribute}).$arg
+               .$self->close_element($command).$end_line;
         }
       } elsif ($type eq 'skipline') {
         # the command associated with an element is closed at the end of the
@@ -828,75 +970,76 @@
             and !($root->{'parent'}->{'extra'} 
                   and $root->{'parent'}->{'extra'}->{'no_section'})) {
           #print STDERR "$root->{'parent'} $root->{'parent'}->{'type'}\n";
-          $self->{'pending_bye'} = "<$command></$command>\n";
+          $self->{'pending_bye'} = $self->open_element($command)
+                    .$self->close_element($command)."\n";
           return '';
         }
-        my $line;
+        my $attribute = [];
         if ($root->{'args'} and $root->{'args'}->[0] 
             and defined($root->{'args'}->[0]->{'text'})) {
-          $line = $root->{'args'}->[0]->{'text'};
+          my $line = $root->{'args'}->[0]->{'text'};
           chomp($line);
-          $line = " line=\"".$self->xml_protect_text($line)."\""
+          $attribute = ['line', $line]
              if ($line ne '');
-        } else {
-          $line = '';
         }
-        return "<$command${line}></$command>\n";
+        return $self->open_element($command, $attribute)
+                 .$self->close_element($command)."\n";
       } elsif ($type eq 'noarg' or $type eq 'skipspace') {
         my $spaces = '';
         $spaces = $root->{'extra'}->{'spaces_after_command'}->{'text'}
           if ($root->{'extra'} and $root->{'extra'}->{'spaces_after_command'}
               and $root->{'extra'}->{'spaces_after_command'}->{'type'} eq 
'empty_spaces_after_command');
-        return "<$command></$command>$spaces";
+        return $self->open_element($command)
+                .$self->close_element($command).$spaces;
       } elsif ($type eq 'special') {
         if ($root->{'cmdname'} eq 'clear' or $root->{'cmdname'} eq 'set') {
-          my $attribute = '';
+          my $attribute = [];
           if ($root->{'args'} and $root->{'args'}->[0]
               and defined($root->{'args'}->[0]->{'text'})) {
-            $attribute = " name=\""
-              .$self->xml_protect_text($root->{'args'}->[0]->{'text'})."\"";
+            push @$attribute, ('name', $root->{'args'}->[0]->{'text'});
           }
           my $value = '';
           if ($root->{'cmdname'} eq 'set' and $root->{'args'} and 
$root->{'args'}->[1]
               and defined($root->{'args'}->[1]->{'text'})) {
-            $value = $self->xml_protect_text($root->{'args'}->[1]->{'text'});
+            $value = $self->protect_text($root->{'args'}->[1]->{'text'});
           }
-          return "<${command}${attribute}".$self->_arg_line($root)
-                                        .">$value</${command}>\n";
+          push @$attribute, $self->_arg_line($root);
+          return $self->open_element($command, $attribute)
+                         .$value.$self->close_element($command)."\n";
         } elsif ($root->{'cmdname'} eq 'clickstyle') {
-          my $attribute = '';
+          my $attribute = [$self->_arg_line($root)];
           my $value = '';
           if ($root->{'args'} and $root->{'args'}->[0]
               and defined($root->{'args'}->[0]->{'text'})) {
             my $click_command = $root->{'args'}->[0]->{'text'};
             $click_command =~ s/^\@//;
-            $attribute = " 
command=\"".$self->xml_protect_text($click_command)."\"";
-            $value = $self->xml_protect_text($root->{'args'}->[0]->{'text'});
+            unshift @$attribute, ('command', $click_command);
+            $value = $self->protect_text($root->{'args'}->[0]->{'text'});
           };
-          return "<${command}${attribute}".$self->_arg_line($root).
-                                         ">$value</${command}>\n";
+          return $self->open_element($command, $attribute)
+                         .$value.$self->close_element($command)."\n";
         } else {
           # should only be unmacro
-          my $attribute = '';
+          my $attribute = [$self->_arg_line($root)];
           if ($root->{'args'} and $root->{'args'}->[0]
               and defined($root->{'args'}->[0]->{'text'})) {
-            $attribute = " name=\"".
-                $self->xml_protect_text($root->{'args'}->[0]->{'text'})."\"";
+            unshift @$attribute, ('name', $root->{'args'}->[0]->{'text'});
           }
-          return "<${command}${attribute}".
-                      $self->_arg_line($root)."></${command}>\n";
+          return $self->open_element($command, $attribute)
+                    .$self->close_element($command)."\n";
         }
       } elsif ($type eq 'lineraw') {
         if ($root->{'cmdname'} eq 'c' or $root->{'cmdname'} eq 'comment') {
-          return $self->xml_comment(" 
$root->{'cmdname'}".$root->{'args'}->[0]->{'text'})
+          return $self->format_comment(" 
$root->{'cmdname'}".$root->{'args'}->[0]->{'text'})
         } else {
           my $value = '';
           if ($root->{'args'} and $root->{'args'}->[0]
               and defined($root->{'args'}->[0]->{'text'})) {
-            $value = $self->xml_protect_text($root->{'args'}->[0]->{'text'});
+            $value = $self->protect_text($root->{'args'}->[0]->{'text'});
           }
           chomp ($value);
-          return "<${command}>$value</${command}>\n";
+          return $self->open_element($command).$value
+                    .$self->close_element($command)."\n";
         }
       } else {
         print STDERR "BUG: unknown misc_command style $type\n" if ($type !~ 
/^\d$/);
@@ -906,14 +1049,14 @@
         } else {
           $args_attributes = ['value'];
         }
-        my $attribute = '';
+        my $attribute = [];
         my $arg_index = 0;
         if (defined($root->{'extra'}) 
             and defined($root->{'extra'}->{'misc_args'})) {
           foreach my $arg_attribute (@{$args_attributes}) {
             if (defined ($root->{'extra'}->{'misc_args'}->[$arg_index])) {
-              $attribute .= " $arg_attribute=\""
-               
.$self->xml_protect_text($root->{'extra'}->{'misc_args'}->[$arg_index])."\"";
+              push @$attribute, ( $arg_attribute, 
+                        $root->{'extra'}->{'misc_args'}->[$arg_index]);
             }
             $arg_index++;
           }
@@ -922,11 +1065,12 @@
         if ($root->{'args'}->[0]) {
           $end_line = $self->_end_line_or_comment(
                                          $root->{'args'}->[0]->{'contents'});
-          $attribute .= $self->_texinfo_line($root->{'args'}->[0]);
+          push @$attribute, $self->_texinfo_line($root->{'args'}->[0]);
         } else {
           $end_line = "\n";
         }
-        return "<$command${attribute}></$command>$end_line";
+        return $self->open_element($command, $attribute)
+                    .$self->close_element($command).$end_line;
       }
     } elsif ($root->{'type'}
              and $root->{'type'} eq 'definfoenclose_command') {
@@ -941,9 +1085,9 @@
         $in_monospace_not_normal
           if (defined($in_monospace_not_normal));
       my $arg = $self->_convert($root->{'args'}->[0]);
-      $result .= "<infoenclose command=\"$root->{'cmdname'}\""
-         . $self->_infoenclose_attribute($root)
-        .">$arg</infoenclose>";
+      $result .= $self->open_element('infoenclose', ['command', 
$root->{'cmdname'},
+                                        $self->_infoenclose_attribute($root)])
+                 .$arg.$self->close_element('infoenclose');
       pop @{$self->{'document_context'}->[-1]->{'monospace'}}
         if (defined($in_monospace_not_normal));
     } elsif ($root->{'args'}
@@ -975,10 +1119,9 @@
       }
       # this is used for commands without args, or associated to the
       # first argument
-      my $attribute = '';
+      my $attribute = [];
       if ($root->{'cmdname'} eq 'verb') {
-        $attribute = " delimiter=\"".$self->xml_protect_text($root->{'type'})
-                       ."\"";
+        push @$attribute, ('delimiter', $root->{'type'});
       } elsif ($root->{'cmdname'} eq 'anchor') {
         my $anchor_name;
         if (defined($root->{'extra'}->{'normalized'})) {
@@ -986,7 +1129,7 @@
         } else {
           $anchor_name = '';
         }
-        $attribute = " name=\"$anchor_name\"";
+        push @$attribute, ('name', $anchor_name);
       }
       my $arg_index = 0;
       foreach my $element (@elements) {
@@ -1003,16 +1146,17 @@
               if (defined($in_monospace_not_normal));
           my $arg = $self->_convert($root->{'args'}->[$arg_index]);
           if ($arg_index > 0) {
-            $attribute .= 
+            push @$attribute, 
               $self->_leading_spaces_arg($root->{'args'}->[$arg_index]);
           }
-          if (!defined($command) or $arg ne '' or $attribute ne '') {
+          if (!defined($command) or $arg ne '' or scalar(@$attribute) > 0) {
             # ${attribute} is only set for @verb
-            $attribute .= _leading_spaces_before_argument($root)
+            push @$attribute, _leading_spaces_before_argument($root)
                if (!defined($command));
-            $result .= "<$element${attribute}>$arg</$element>";
+            $result .= $self->open_element($element, $attribute).$arg
+                      .$self->close_element($element);
           }
-          $attribute = '';
+          $attribute = [];
           pop @{$self->{'document_context'}->[-1]->{'monospace'}}
             if (defined($in_monospace_not_normal));
         } else {
@@ -1021,18 +1165,18 @@
         $arg_index++;
       }
       # This is for the main command
-      $attribute = '';
+      $attribute = [];
       if ($root->{'cmdname'} eq 'image') {
         if ($self->_is_inline($root)) {
-          $attribute = " where=\"inline\"";
+          push @$attribute, ('where', 'inline');
         }
       } elsif ($Texinfo::Common::ref_commands{$root->{'cmdname'}}) {
         if ($root->{'extra'}->{'brace_command_contents'}) {
           if ($root->{'extra'}->{'node_argument'}
               and $root->{'extra'}->{'node_argument'}->{'node_content'}
               and 
defined($root->{'extra'}->{'node_argument'}->{'normalized'})) {
-            $attribute = " label=\"".$self->xml_protect_text(
-                $root->{'extra'}->{'node_argument'}->{'normalized'})."\"";
+            push @$attribute, ('label', 
+                 $root->{'extra'}->{'node_argument'}->{'normalized'});
           }
           my $manual;
           my $manual_arg_index = 3;
@@ -1056,14 +1200,15 @@
             $manual_base =~ s/\.[^\.]*$//;
             $manual_base =~ s/^.*\///;
             
-            $attribute .= " 
manual=\"".$self->xml_protect_text($manual_base)."\"" 
+            push @$attribute, ('manual', $manual_base)
                   if ($manual_base ne '');
           }
         }
       }
       if (defined($command)) {
-        $attribute .= _leading_spaces_before_argument($root);
-        $result = "<$command${attribute}>$result</$command>";
+        push @$attribute, _leading_spaces_before_argument($root);
+        $result = $self->open_element($command, $attribute).$result
+                  .$self->close_element($command);
       }
       if ($Texinfo::Common::context_brace_commands{$root->{'cmdname'}}) {
         pop @{$self->{'document_context'}};
@@ -1073,55 +1218,55 @@
         push @{$self->{'document_context'}}, {'monospace' => [0]};
       }
       my $prepended_elements = '';
-      my $attribute = '';
+      my $attribute = [];
       $self->{'itemize_line'} = 1 if ($root->{'cmdname'} eq 'itemize');
       if ($root->{'extra'} and $root->{'extra'}->{'command_as_argument'}) {
         my $command_as_arg = $root->{'extra'}->{'command_as_argument'};
-        $attribute 
-         .= " commandarg=\"$command_as_arg->{'cmdname'}\""
-             .$self->_infoenclose_attribute($command_as_arg);
+        push @$attribute,
+         ('commandarg', $command_as_arg->{'cmdname'},
+             $self->_infoenclose_attribute($command_as_arg));
       } elsif ($root->{'extra'}
                and $root->{'extra'}->{'enumerate_specification'}) {
-        $attribute .= " first=\""
-          
.$self->xml_protect_text($root->{'extra'}->{'enumerate_specification'})
-          ."\"";
+        push @$attribute,('first', 
$root->{'extra'}->{'enumerate_specification'});
       } elsif ($root->{'cmdname'} eq 'float' and $root->{'extra'}) {
         if (defined($root->{'extra'}->{'normalized'})) {
-          $attribute .= " name=\"$root->{'extra'}->{'normalized'}\"";
+          push @$attribute, ('name', $root->{'extra'}->{'normalized'});
         }
         if ($root->{'extra'}->{'type'} and 
             defined($root->{'extra'}->{'type'}->{'normalized'})) {
-          $attribute .= " type=\"$root->{'extra'}->{'type'}->{'normalized'}\"";
+          push @$attribute, ('type', 
$root->{'extra'}->{'type'}->{'normalized'});
         }
       } elsif ($root->{'cmdname'} eq 'verbatim') {
-        $attribute = " xml:space=\"preserve\"";
+        push @$attribute, ('xml:space', 'preserve');
       } elsif ($root->{'cmdname'} eq 'macro' 
                or $root->{'cmdname'} eq 'rmacro') {
         if (defined($root->{'args'})) {
           my @args = @{$root->{'args'}};
           my $name_arg = shift @args;
           if (defined($name_arg) and defined($name_arg->{'text'})) {
-            $attribute .= " name=\"$name_arg->{'text'}\"";
+            push @$attribute, ('name', $name_arg->{'text'});
           }
           
           while (@args) {
             my $formal_arg = shift @args;
-            $prepended_elements .= "<formalarg>".
-                $self->xml_protect_text($formal_arg->{'text'})."</formalarg>";
+            $prepended_elements .= $self->open_element('formalarg')
+                .$self->protect_text($formal_arg->{'text'})
+                .$self->close_element('formalarg');
           }
         }
-        $attribute .= $self->_arg_line($root);
+        push @$attribute, $self->_arg_line($root);
       }
       if ($self->{'expanded_formats_hash'}->{$root->{'cmdname'}}) {
         $self->{'document_context'}->[-1]->{'raw'} = 1;
       } else {
         my $end_command = $root->{'extra'}->{'end_command'};
-        my $end_command_space = _leading_spaces($end_command);
-        if ($end_command_space ne '') {
-          $end_command_space =~ s/ spaces=/ endspaces=/;
-        }
-        $result .= "<$root->{'cmdname'}${attribute}"._leading_spaces($root)
-                             ."$end_command_space>${prepended_elements}";
+        my $end_command_space = [_leading_spaces($end_command)];
+        if (scalar(@$end_command_space)) {
+          $end_command_space->[0] = 'endspaces';
+        }
+        $result .= $self->open_element($root->{'cmdname'}, address@hidden, 
+                              _leading_spaces($root), @$end_command_space])
+                      .${prepended_elements};
         my $end_line = '';
         if ($root->{'args'}) {
           if ($commands_args_elements{$root->{'cmdname'}}) {
@@ -1142,13 +1287,14 @@
                 } else {
                   $arg = $self->_convert($root->{'args'}->[$arg_index]);
                 }
-                my $spaces = '';
+                my $spaces = [];
                 if ($arg_index != 0) {
-                  $spaces = $self->_leading_spaces_arg(
+                  push @$spaces, $self->_leading_spaces_arg(
                                               $root->{'args'}->[$arg_index]);
                 }
-                if ($arg ne '' or $spaces ne '') {
-                  $result .= "<$element${spaces}>$arg</$element>";
+                if ($arg ne '' or scalar(@$spaces)) {
+                  $result .= $self->open_element($element, $spaces).$arg
+                           .$self->close_element($element);
                 }
                 pop @{$self->{'document_context'}->[-1]->{'monospace'}} 
                   if ($in_code);
@@ -1160,10 +1306,10 @@
           } else {
             my $contents_possible_comment;
             # in that case the end of line is in the columnfractions line
-            # or in the <columnprototypes>.  
+            # or in the columnprototypes.  
             if ($root->{'cmdname'} eq 'multitable' and $root->{'extra'}) {
               if ($root->{'extra'}->{'prototypes_line'}) {
-                $result .= "<columnprototypes>";
+                $result .= $self->open_element('columnprototypes');
                 my $first_proto = 1;
                 foreach my $prototype 
(@{$root->{'extra'}->{'prototypes_line'}}) {
                   if ($prototype->{'text'} and $prototype->{'text'} !~ /\S/) {
@@ -1173,20 +1319,19 @@
                       $result .= $spaces;
                     }
                   } else {
-                    my $attribute;
+                    my $attribute = [];
                     if ($prototype->{'type'} 
                         and $prototype->{'type'} eq 'bracketed') {
-                      $attribute = ' bracketed="on"';
-                      $attribute .= 
_leading_spaces_before_argument($prototype);
-                    } else {
-                      $attribute = '';
+                      push @$attribute, ('bracketed', 'on');
+                      push @$attribute, 
_leading_spaces_before_argument($prototype);
                     }
-                    $result .= "<columnprototype${attribute}>".
-                           $self->_convert($prototype)."</columnprototype>";
+                    $result .= $self->open_element('columnprototype', 
$attribute)
+                           .$self->_convert($prototype)
+                           .$self->close_element('columnprototype');
                   }
                   $first_proto = 0;
                 }
-                $result .= "</columnprototypes>";
+                $result .= $self->close_element('columnprototypes');
                 $contents_possible_comment 
                   = $root->{'args'}->[-1]->{'contents'};
               } elsif ($root->{'extra'}->{'columnfractions'}) {
@@ -1198,12 +1343,14 @@
                     last;
                   }
                 }
-                my $attribute = $self->_texinfo_line($cmd->{'args'}->[0]);
-                $result .= "<columnfractions${attribute}>";
+                my $attribute = [$self->_texinfo_line($cmd->{'args'}->[0])];
+                $result .= $self->open_element('columnfractions', $attribute);
                 foreach my $fraction 
(@{$root->{'extra'}->{'columnfractions'}}) {
-                  $result .= "<columnfraction 
value=\"$fraction\"></columnfraction>";
+                  $result .= $self->open_element('columnfraction', 
+                                                ['value', $fraction])
+                             .$self->close_element('columnfraction');
                 }
-                $result .= "</columnfractions>";
+                $result .= $self->close_element('columnfractions');
                 $contents_possible_comment 
                   = 
$root->{'args'}->[-1]->{'contents'}->[-1]->{'args'}->[-1]->{'contents'}
                     if ($root->{'args'}->[-1]->{'contents'}
@@ -1237,26 +1384,25 @@
   }
   if ($root->{'type'}) {
     if (defined($type_elements{$root->{'type'}})) {
-      my $attribute = '';
+      my $attribute = [];
       if ($root->{'type'} eq 'preformatted') {
-        $attribute = ' xml:space="preserve"';
+        push @$attribute, ('xml:space', 'preserve');
       } elsif ($root->{'type'} eq 'menu_entry') {
-        $attribute .= ' leadingtext="'.$self->xml_protect_text(
-                              $self->_convert($root->{'args'}->[0])).'"';
+        push @$attribute, ('leadingtext', 
$self->_convert($root->{'args'}->[0]));
       } elsif (($root->{'type'} eq 'menu_entry_node' 
                 or $root->{'type'} eq 'menu_entry_name')
                and $self->{'pending_menu_entry_separator'}) {
-        $attribute .= ' separator="'.$self->xml_protect_text(
-               $self->_convert($self->{'pending_menu_entry_separator'})).'"';
+        push @$attribute, ('separator',
+               $self->_convert($self->{'pending_menu_entry_separator'}));
         delete $self->{'pending_menu_entry_separator'};
       }
-      $result .= "<$type_elements{$root->{'type'}}${attribute}>";
+      $result .= $self->open_element($type_elements{$root->{'type'}}, 
$attribute);
     }
     if ($root->{'type'} eq 'def_line') {
       if ($root->{'cmdname'}) {
-        $result .= "<$root->{'cmdname'}"._leading_spaces($root).">";
+        $result .= $self->open_element($root->{'cmdname'}, 
[_leading_spaces($root)]);
       }
-      $result .= "<definitionterm>";
+      $result .= $self->open_element('definitionterm');
       $result .= $self->_index_entry($root);
       push @{$self->{'document_context'}->[-1]->{'monospace'}}, 1;
       if ($root->{'extra'} and $root->{'extra'}->{'def_args'}) {
@@ -1275,11 +1421,9 @@
           if ($type eq 'spaces') {
             $result .= $content;
           } else {
-            my $attribute;
+            my $attribute = [];
             if ($type eq 'category' and $alias) {
-              $attribute = " automatic=\"on\"";
-            } else {
-              $attribute = "";
+              push @$attribute, ('automatic', 'on');
             }
             my $element;
             if ($type eq 'name') {
@@ -1293,17 +1437,18 @@
             }
             if ($arg->[1]->{'type'}
                 and $arg->[1]->{'type'} eq 'bracketed_def_content') {
-              $attribute .= ' bracketed="on"';
-              $attribute .= _leading_spaces_before_argument($arg->[1]);
+              push @$attribute, ('bracketed', 'on');
+              push @$attribute, _leading_spaces_before_argument($arg->[1]);
             }
-            $result .= "<def$element${attribute}>$content</def$element>";
+            $result .= $self->open_element("def$element", $attribute).$content
+                      .$self->close_element("def$element");
           }
         }
       }
       pop @{$self->{'document_context'}->[-1]->{'monospace'}};
-      $result .= "</definitionterm>";
+      $result .= $self->close_element('definitionterm');
       if ($root->{'cmdname'}) {
-        $result .= "</$root->{'cmdname'}>";
+        $result .= $self->close_element($root->{'cmdname'});
       }
       chomp ($result);
       $result .= "\n";
@@ -1353,7 +1498,7 @@
   }
   if ($root->{'type'}) {
     if (defined($type_elements{$root->{'type'}})) {
-      $result .= "</$type_elements{$root->{'type'}}>";
+      $result .= $self->close_element($type_elements{$root->{'type'}});
     }
   }
   $result = '{'.$result.'}' 
@@ -1362,7 +1507,7 @@
               ($root->{'parent'}->{'type'} ne 'block_line_arg'
                and $root->{'parent'}->{'type'} ne 'misc_line_arg')));
   foreach my $element (@close_elements) {
-    $result .= "</$element>";
+    $result .= $self->close_element($element);
   }
   if ($root->{'cmdname'} 
       and exists($Texinfo::Common::block_commands{$root->{'cmdname'}})) {
@@ -1403,7 +1548,7 @@
     my $command = $self->_level_corrected_section($root);
     if (!($root->{'section_childs'} and scalar(@{$root->{'section_childs'}}))
         or $command eq 'top') {
-      $result .= "</$command>\n";
+      $result .= $self->close_element($command)."\n";
       my $current = $root;
       while ($current->{'section_up'}
              # the most up element is a virtual sectioning root element, this
@@ -1412,7 +1557,7 @@
              and !$current->{'section_next'}
              and $self->_level_corrected_section($current->{'section_up'}) ne 
'top') {
         $current = $current->{'section_up'};
-        $result .= '</'.$self->_level_corrected_section($current) .">\n";
+        $result .= 
$self->close_element($self->_level_corrected_section($current)) ."\n";
       }
     }
     if ($self->{'pending_bye'}) {

Index: t/results/misc_commands/definfoenclose_with_empty_arg.pl
===================================================================
RCS file: 
/sources/texinfo/texinfo/tp/t/results/misc_commands/definfoenclose_with_empty_arg.pl,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -b -r1.4 -r1.5

Index: t/results/xtable/definfoenclose_on_table_line.pl
===================================================================
RCS file: 
/sources/texinfo/texinfo/tp/t/results/xtable/definfoenclose_on_table_line.pl,v
retrieving revision 1.21
retrieving revision 1.22
diff -u -b -r1.21 -r1.22



reply via email to

[Prev in Thread] Current Thread [Next in Thread]