agpl_1.0.0_b5da3320/src/dom-core-nodes-output.adb

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
 

with Agpl.Types.Ustrings;
with Agpl.Xml;

with Sax.Encodings; use Sax.Encodings;

with Ada.Strings.Unbounded.Text_Io;
with Ada.Text_Io;

package body Dom.Core.Nodes.Output is

   NL  : constant String  := (1 => Character'Val (10));
   Tab : constant Natural := 3;

   procedure Print_Whites (U : in out ASU.Unbounded_String; Whites : in Natural) is
      S : constant String (1 .. Whites) := (others => ' ');
   begin
      ASU.Append (U, S);
   end Print_Whites;

   ----------
   -- Sort --
   ----------

   procedure Sort (Map : in out Named_Node_Map) is
      Arr : Node_Array (0 .. Map.Last + 1) := (others => null);
      Index : Natural;
   begin
      --  ??? The algorithm is not efficient, we use Insertion_Sort.
      for J in 0 .. Map.Last loop
         Index := 0;
         loop
            if Arr (Index) = null then
               Arr (Index) := Map.Items (J);
               exit;
            end if;

            if Node_Name (Map.Items (J)) <= Node_Name (Arr (Index)) then
               Arr (Index + 1 .. Arr'Last) := Arr (Index .. Arr'Last - 1);
               Arr (Index) := Map.Items (J);
               exit;
            end if;
            Index := Index + 1;
         end loop;
      end loop;
      for J in 0 .. Map.Last loop
         Map.Items (J) := Arr (J);
      end loop;
   end Sort;

   -----------
   -- Print --
   -----------
   procedure Print
     (N              : Node;
      U              : in out ASU.Unbounded_string;
      Print_Comments : Boolean := False;
      Print_XML_PI   : Boolean := False;
      With_URI       : Boolean := False;
      Indent         : Natural := 0)
   is
   --  Print the contents of Node and its children in XML format.
   --  If Print_Comments is True, then nodes associated with comments are
   --  also displayed.
   --  The <?xml?> processing instruction is displayed only if Print_XML_PI
   --  By default, names are of the form  ns_prefix:local_name. However, if
   --  with_URI is True, names will be  ns_URI:local_name instead
      procedure Append (U : in out ASU.Unbounded_string; S : String)
         renames ASU.Append;
      procedure Print_Name (N : Node);
      --  Print the name of the node.

      ----------------
      -- Print_Name --
      ----------------

      procedure Print_Name (N : Node) is
      begin
         if With_URI then
            Append (U, Namespace_URI (N) & ':' & Agpl.Xml.Escape (Local_Name (N)));
         else
            Append (U, Agpl.Xml.Escape (Node_Name (N)));
         end if;
      end Print_Name;

   begin
      if N = null then
         return;
      end if;

      case N.Node_Type is
         when Element_Node =>
            Append (U, NL);
            Print_Whites (U, Indent);
            Append (U, "<");
            Print_Name (N);

            --  Sort the XML attributes as required for canonical XML
            Sort (N.Attributes);

            if N.Attributes.Last > 0 then
               for J in 0 .. N.Attributes.Last loop
                  Append (U, " ");
                  Print (N.Attributes.Items (J), U,
                         Print_Comments, Print_XML_PI, With_URI, Indent => Indent + Tab);
               end loop;
            elsif N.Attributes.Last = 0 then
               Append (U, " ");
               Print_Name (N.Attributes.Items (0));
               Append (U, "=""");
               Append (U, Node_Value (N.Attributes.Items (0)));
               Append (U, """");
            end if;

            Append (U, ">");

            if N.Children.Last >= 0 then
               Print (N.Children, U, Print_Comments, Print_XML_PI, With_URI, Indent => Indent + Tab);
            end if;

            if N.Attributes.Last >= 1 or else
               (N.Children.Last >= 0 and then N.Children.Items (N.Children.Last).Node_Type /= Text_Node) then
               Append (U, NL);
               Print_Whites (U, Indent);
            end if;

            Append (U, "</");
            Print_Name (N);
            Append (U, ">");

         when Attribute_Node =>
            Append (U, NL);
            Print_Whites (U, Indent);
            Print_Name (N);
            Append (U, "=""");
            Append (U, Agpl.Xml.Escape (Node_Value (N)));
            Append (U, """");

         when Processing_Instruction_Node =>
            if Print_XML_PI
              or else N.Target.all /= Xml_Sequence
            then
               Append (U, "<?" & N.Target.all);
               if N.Pi_Data'Length = 0
                 or else N.Pi_Data (N.Pi_Data'First) /= ' '
               then
                  Append (U, " ");
               end if;
               Append (U, N.Pi_Data.all & "?>");
            end if;

         when Comment_Node =>
            if Print_Comments then
               Append (U, Node_Value (N));
            end if;

         when Document_Node =>
            Print (N.Doc_Children, U,
                   Print_Comments, Print_XML_PI, With_URI);

         when Document_Fragment_Node =>
            Print (N.Doc_Frag_Children, U,
                   Print_Comments, Print_XML_PI, With_URI);

         when Document_Type_Node | Notation_Node =>
            null;

         when Text_Node =>
            Append (U, Node_Value (N));

         when others =>
            Append (U, Node_Value (N));
      end case;

      --  Lame hack:
      declare
         use Asu;
      begin
         if Slice (U, 1, 2) /= "<?" then
            U := "<?xml version='1.0' encoding='utf-8'?>" & Nl & U;
         end if;
      end;
   end Print;

   procedure Print
     (N              : Node;
      File           : String;
      Print_Comments : Boolean := False;
      Print_XML_PI   : Boolean := False;
      With_URI       : Boolean := False;
      Indent         : Natural := 0)
   is
      use Agpl.Types.Ustrings;
      Text : Ustring;
   begin
      Print (N, Text, Print_Comments, Print_Xml_Pi, With_Uri, Indent);

      declare
         use Ada.Strings.Unbounded.Text_Io;
         use Ada.Text_Io;
         F : File_Type;
      begin
         Create (F, Out_File, File);
         Put_Line (F, Text);
         Close (F);
      exception
         when others =>
            Close (F);
            raise;
      end;
   end Print;

   procedure Print
     (List           : Dom.Core.Node_List;
      U              : in out ASU.Unbounded_string;
      Print_Comments : Boolean := False;
      Print_XML_PI   : Boolean := False;
      With_URI       : Boolean := False;
      Indent         : Natural := 0)
   is
   --  Same as Print, but for all the nodes in the list.
   begin
      for J in 0 .. List.Last loop
         Print (List.Items (J), U, Print_Comments, Print_XML_PI, With_URI, Indent => Indent);
      end loop;
   end Print;

end Dom.Core.Nodes.Output;