1XML::Generator(3)     User Contributed Perl Documentation    XML::Generator(3)
2
3
4

NAME

6       XML::Generator - Perl extension for generating XML
7

SYNOPSIS

9         use XML::Generator ':pretty';
10
11         print foo(bar({ baz => 3 }, bam()),
12                   bar([ 'qux' => 'http://qux.com/' ],
13                         "Hey there, world"));
14
15         # OR
16
17         require XML::Generator;
18
19         my $X = XML::Generator->new(':pretty');
20
21         print $X->foo($X->bar({ baz => 3 }, $X->bam()),
22                       $X->bar([ 'qux' => 'http://qux.com/' ],
23                                 "Hey there, world"));
24
25       Either of the above yield:
26
27          <foo xmlns:qux="http://qux.com/">
28            <bar baz="3">
29              <bam />
30            </bar>
31            <qux:bar>Hey there, world</qux:bar>
32          </foo>
33

DESCRIPTION

35       In general, once you have an XML::Generator object, you then simply
36       call methods on that object named for each XML tag you wish to
37       generate.
38
39       XML::Generator can also arrange for undefined subroutines in the
40       caller's package to generate the corresponding XML, by exporting an
41       "AUTOLOAD" subroutine to your package.  Just supply an ':import'
42       argument to your "use XML::Generator;" call.  If you already have an
43       "AUTOLOAD" defined then XML::Generator can be configured to cooperate
44       with it.  See "STACKABLE AUTOLOADs".
45
46       Say you want to generate this XML:
47
48          <person>
49            <name>Bob</name>
50            <age>34</age>
51            <job>Accountant</job>
52          </person>
53
54       Here's a snippet of code that does the job, complete with pretty
55       printing:
56
57          use XML::Generator;
58          my $gen = XML::Generator->new(':pretty');
59          print $gen->person(
60                   $gen->name("Bob"),
61                   $gen->age(34),
62                   $gen->job("Accountant")
63                );
64
65       The only problem with this is if you want to use a tag name that Perl's
66       lexer won't understand as a method name, such as "shoe-size".
67       Fortunately, since you can store the name of a method in a variable,
68       there's a simple work-around:
69
70          my $shoe_size = "shoe-size";
71          $xml = $gen->$shoe_size("12 1/2");
72
73       Which correctly generates:
74
75          <shoe-size>12 1/2</shoe-size>
76
77       You can use a hash ref as the first parameter if the tag should include
78       atributes.  Normally this means that the order of the attributes will
79       be unpredictable, but if you have the Tie::IxHash module, you can use
80       it to get the order you want, like this:
81
82         use Tie::IxHash;
83         tie my %attr, 'Tie::IxHash';
84
85         %attr = (name => 'Bob',
86                  age  => 34,
87                  job  => 'Accountant',
88           'shoe-size' => '12 1/2');
89
90         print $gen->person(\%attr);
91
92       This produces
93
94         <person name="Bob" age="34" job="Accountant" shoe-size="12 1/2" />
95
96       An array ref can also be supplied as the first argument to indicate a
97       namespace for the element and the attributes.
98
99       If there is one element in the array, it is considered the URI of the
100       default namespace, and the tag will have an xmlns="URI" attribute added
101       automatically.  If there are two elements, the first should be the tag
102       prefix to use for the namespace and the second element should be the
103       URI.  In this case, the prefix will be used for the tag and an
104       xmlns:PREFIX attribute will be automatically added.  Prior to version
105       0.99, this prefix was also automatically added to each attribute name.
106       Now, the default behavior is to leave the attributes alone (although
107       you may always explicitly add a prefix to an attribute name).  If the
108       prior behavior is desired, use the constructor option
109       "qualified_attributes".
110
111       If you specify more than two elements, then each pair should correspond
112       to a tag prefix and the corresponding URL.  An xmlns:PREFIX attribute
113       will be added for each pair, and the prefix from the first such pair
114       will be used as the tag's namespace.  If you wish to specify a default
115       namespace, use '#default' for the prefix.  If the default namespace is
116       first, then the tag will use the default namespace itself.
117
118       If you want to specify a namespace as well as attributes, you can make
119       the second argument a hash ref.  If you do it the other way around, the
120       array ref will simply get stringified and included as part of the
121       content of the tag.
122
123       Here's an example to show how the attribute and namespace parameters
124       work:
125
126          $xml = $gen->account(
127                   $gen->open(['transaction'], 2000),
128                   $gen->deposit(['transaction'], { date => '1999.04.03'}, 1500)
129                 );
130
131       This generates:
132
133          <account>
134            <open xmlns="transaction">2000</open>
135            <deposit xmlns="transaction" date="1999.04.03">1500</deposit>
136          </account>
137
138       Because default namespaces inherit, XML::Generator takes care to output
139       the xmlns="URI" attribute as few times as strictly necessary.  For
140       example,
141
142          $xml = $gen->account(
143                   $gen->open(['transaction'], 2000),
144                   $gen->deposit(['transaction'], { date => '1999.04.03'},
145                     $gen->amount(['transaction'], 1500)
146                   )
147                 );
148
149       This generates:
150
151          <account>
152            <open xmlns="transaction">2000</open>
153            <deposit xmlns="transaction" date="1999.04.03">
154              <amount>1500</amount>
155            </deposit>
156          </account>
157
158       Notice how "xmlns="transaction"" was left out of the "<amount"> tag.
159
160       Here is an example that uses the two-argument form of the namespace:
161
162           $xml = $gen->widget(['wru' => 'http://www.widgets-r-us.com/xml/'],
163                               {'id'  => 123}, $gen->contents());
164
165           <wru:widget xmlns:wru="http://www.widgets-r-us.com/xml/" id="123">
166             <contents />
167           </wru:widget>
168
169       Here is an example that uses multiple namespaces.  It generates the
170       first example from the RDF primer (<http://www.w3.org/TR/rdf-primer/>).
171
172           my $contactNS = [contact => "http://www.w3.org/2000/10/swap/pim/contact#"];
173           $xml = $gen->xml(
174                    $gen->RDF([ rdf     => "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
175                                @$contactNS ],
176                       $gen->Person($contactNS, { 'rdf:about' => "http://www.w3.org/People/EM/contact#me" },
177                         $gen->fullName($contactNS, 'Eric Miller'),
178                         $gen->mailbox($contactNS, {'rdf:resource' => "mailto:em@w3.org"}),
179                         $gen->personalTitle($contactNS, 'Dr.'))));
180
181           <?xml version="1.0" standalone="yes"?>
182           <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
183                    xmlns:contact="http://www.w3.org/2000/10/swap/pim/contact#">
184             <contact:Person rdf:about="http://www.w3.org/People/EM/contact#me">
185               <contact:fullName>Eric Miller</contact:fullName>
186               <contact:mailbox rdf:resource="mailto:em@w3.org" />
187               <contact:personalTitle>Dr.</contact:personalTitle>
188             </Person>
189           </rdf:RDF>
190

CONSTRUCTOR

192       XML::Generator->new(':option', ...);
193
194       XML::Generator->new(option => 'value', ...);
195
196       (Both styles may be combined)
197
198       The following options are available:
199
200   :std, :standard
201       Equivalent to
202
203               escape      => 'always',
204               conformance => 'strict',
205
206   :strict
207       Equivalent to
208
209               conformance => 'strict',
210
211   :pretty[=N]
212       Equivalent to
213
214               escape      => 'always',
215               conformance => 'strict',
216               pretty      => N         # N defaults to 2
217
218   namespace
219       This value of this option must be an array reference containing one or
220       two values.  If the array contains one value, it should be a URI and
221       will be the value of an 'xmlns' attribute in the top-level tag.  If
222       there are two or more elements, the first of each pair should be the
223       namespace tag prefix and the second the URI of the namespace.  This
224       will enable behavior similar to the namespace behavior in previous
225       versions; the tag prefix will be applied to each tag.  In addition, an
226       xmlns:NAME="URI" attribute will be added to the top-level tag.  Prior
227       to version 0.99, the tag prefix was also automatically added to each
228       attribute name, unless overridden with an explicit prefix.  Now, the
229       attribute names are left alone, but if the prior behavior is desired,
230       use the constructor option "qualified_attributes".
231
232       The value of this option is used as the global default namespace.  For
233       example,
234
235           my $html = XML::Generator->new(
236                        pretty    => 2,
237                        namespace => [HTML => "http://www.w3.org/TR/REC-html40"]);
238           print $html->html(
239                   $html->body(
240                     $html->font({ face => 'Arial' },
241                                 "Hello, there")));
242
243       would yield
244
245           <HTML:html xmlns:HTML="http://www.w3.org/TR/REC-html40">
246             <HTML:body>
247               <HTML:font face="Arial">Hello, there</HTML:font>
248             </HTML:body>
249           </HTML:html>
250
251       Here is the same example except without all the prefixes:
252
253           my $html = XML::Generator->new(
254                        pretty    => 2,
255                        namespace => ["http://www.w3.org/TR/REC-html40"]);
256           print $html->html(
257                   $html->body(
258                     $html->font({ 'face' => 'Arial' },
259                                   "Hello, there")));
260
261       would yield
262
263          <html xmlns="http://www.w3.org/TR/REC-html40">
264            <body>
265               <font face="Arial">Hello, there</font>
266            </body>
267          </html>
268
269   qualifiedAttributes, qualified_attributes
270       Set this to a true value to emulate the attribute prefixing behavior of
271       XML::Generator prior to version 0.99.  Here is an example:
272
273           my $foo = XML::Generator->new(
274                       namespace => [foo => "http://foo.com/"],
275                       qualifiedAttributes => 1);
276           print $foo->bar({baz => 3});
277
278       yields
279
280           <foo:bar xmlns:foo="http://foo.com/" foo:baz="3" />
281
282   escape
283       The contents and the values of each attribute have any illegal XML
284       characters escaped if this option is supplied.  If the value is
285       'always', then &, < and > (and " within attribute values) will be
286       converted into the corresponding XML entity, although & will not be
287       converted if it looks like it could be part of a valid entity (but see
288       below).  If the value is 'unescaped', then the escaping will be turned
289       off character-by-character if the character in question is preceded by
290       a backslash, or for the entire string if it is supplied as a scalar
291       reference.  So, for example,
292
293               use XML::Generator escape => 'always';
294
295               one('<');      # <one>&lt;</one>
296               two('\&');     # <two>\&amp;</two>
297               three(\'<f>'); # <three><f></three> (scalar refs always allowed)
298               four('&lt;');  # <four>&lt;</four> (looks like an entity)
299               five('&#34;'); # <five>&#34;</five> (looks like an entity)
300
301       but
302
303               use XML::Generator escape => 'unescaped';
304
305               one('<');     # <one>&lt;</one>
306               two('\&');    # <two>&</two>
307               three(\'<f>');# <three><f></three>  (scalar refs always allowed)
308               four('&lt;'); # <four>&amp;lt;</four> (no special case for entities)
309
310       By default, high-bit data will be passed through unmodified, so that
311       UTF-8 data can be generated with pre-Unicode perls.  If you know that
312       your data is ASCII, use the value 'high-bit' for the escape option and
313       bytes with the high bit set will be turned into numeric entities.  You
314       can combine this functionality with the other escape options by comma-
315       separating the values:
316
317         my $a = XML::Generator->new(escape => 'always,high-bit');
318         print $a->foo("<\242>");
319
320       yields
321
322         <foo>&lt;&#162;&gt;</foo>
323
324       Because XML::Generator always uses double quotes ("") around attribute
325       values, it does not escape single quotes.  If you want single quotes
326       inside attribute values to be escaped, use the value 'apos' along with
327       'always' or 'unescaped' for the escape option.  For example:
328
329           my $gen = XML::Generator->new(escape => 'always,apos');
330           print $gen->foo({'bar' => "It's all good"});
331
332           <foo bar="It&apos;s all good" />
333
334       If you actually want & to be converted to &amp; even if it looks like
335       it could be part of a valid entity, use the value 'even-entities' along
336       with 'always'.  Supplying 'even-entities' to the 'unescaped' option is
337       meaningless as entities are already escaped with that option.
338
339   pretty
340       To have nice pretty printing of the output XML (great for config files
341       that you might also want to edit by hand), supply an integer for the
342       number of spaces per level of indenting, eg.
343
344          my $gen = XML::Generator->new(pretty => 2);
345          print $gen->foo($gen->bar('baz'),
346                          $gen->qux({ tricky => 'no'}, 'quux'));
347
348       would yield
349
350          <foo>
351            <bar>baz</bar>
352            <qux tricky="no">quux</qux>
353          </foo>
354
355       You may also supply a non-numeric string as the argument to 'pretty',
356       in which case the indents will consist of repetitions of that string.
357       So if you want tabbed indents, you would use:
358
359            my $gen = XML::Generator->new(pretty => "\t");
360
361       Pretty printing does not apply to CDATA sections or Processing
362       Instructions.
363
364   conformance
365       If the value of this option is 'strict', a number of syntactic checks
366       are performed to ensure that generated XML conforms to the formal XML
367       specification.  In addition, since entity names beginning with 'xml'
368       are reserved by the W3C, inclusion of this option enables several
369       special tag names: xmlpi, xmlcmnt, xmldecl, xmldtd, xmlcdata, and xml
370       to allow generation of processing instructions, comments, XML
371       declarations, DTD's, character data sections and "final" XML documents,
372       respectively.
373
374       Invalid characters (http://www.w3.org/TR/xml11/#charsets) will be
375       filtered out.  To disable this behavior, supply the
376       'filter_invalid_chars' option with the value 0.
377
378       See "XML CONFORMANCE" and "SPECIAL TAGS" for more information.
379
380   filterInvalidChars, filter_invalid_chars
381       Set this to a 1 to enable filtering of invalid characters, or to 0 to
382       disable the filtering.  See http://www.w3.org/TR/xml11/#charsets for
383       the set of valid characters.
384
385   allowedXMLTags, allowed_xml_tags
386       If you have specified 'conformance' => 'strict' but need to use tags
387       that start with 'xml', you can supply a reference to an array
388       containing those tags and they will be accepted without error.  It is
389       not an error to supply this option if 'conformance' => 'strict' is not
390       supplied, but it will have no effect.
391
392   empty
393       There are 5 possible values for this option:
394
395          self    -  create empty tags as <tag />  (default)
396          compact -  create empty tags as <tag/>
397          close   -  close empty tags as <tag></tag>
398          ignore  -  don't do anything (non-compliant!)
399          args    -  use count of arguments to decide between <x /> and <x></x>
400
401       Many web browsers like the 'self' form, but any one of the forms
402       besides 'ignore' is acceptable under the XML standard.
403
404       'ignore' is intended for subclasses that deal with HTML and other SGML
405       subsets which allow atomic tags.  It is an error to specify both
406       'conformance' => 'strict' and 'empty' => 'ignore'.
407
408       'args' will produce <x /> if there are no arguments at all, or if there
409       is just a single undef argument, and <x></x> otherwise.
410
411   version
412       Sets the default XML version for use in XML declarations.  See
413       "xmldecl" below.
414
415   encoding
416       Sets the default encoding for use in XML declarations.
417
418   dtd
419       Specify the dtd.  The value should be an array reference with three
420       values; the type, the name and the uri.
421
422   xml
423       This is an hash ref value that should contain the version, encoding and
424       dtd values (same as above). This is used in case "conformance" is set
425       to "loose", but you still want to use the xml declaration or prolog.
426

IMPORT ARGUMENTS

428       use XML::Generator ':option';
429
430       use XML::Generator option => 'value';
431
432       (Both styles may be combined)
433
434   :import
435       Cause "use XML::Generator;" to export an "AUTOLOAD" to your package
436       that makes undefined subroutines generate XML tags corresponding to
437       their name.  Note that if you already have an "AUTOLOAD" defined, it
438       will be overwritten.
439
440   :stacked
441       Implies :import, but if there is already an "AUTOLOAD" defined, the
442       overriding "AUTOLOAD" will still give it a chance to run.  See
443       "STACKABLE AUTOLOADs".
444
445   ANYTHING ELSE
446       If you supply any other options, :import is implied and the
447       XML::Generator object that is created to generate tags will be
448       constructed with those options.
449

XML CONFORMANCE

451       When the 'conformance' => 'strict' option is supplied, a number of
452       syntactic checks are enabled.  All entity and attribute names are
453       checked to conform to the XML specification, which states that they
454       must begin with either an alphabetic character or an underscore and may
455       then consist of any number of alphanumerics, underscores, periods or
456       hyphens.  Alphabetic and alphanumeric are interpreted according to the
457       current locale if 'use locale' is in effect and according to the
458       Unicode standard for Perl versions >= 5.6.  Furthermore, entity or
459       attribute names are not allowed to begin with 'xml' (in any case),
460       although a number of special tags beginning with 'xml' are allowed (see
461       "SPECIAL TAGS"). Note that you can also supply an explicit list of
462       allowed tags with the 'allowed_xml_tags' option.
463
464       Also, the filter_invalid_chars option is automatically set to 1 unless
465       it is explicitly set to 0.
466

SPECIAL TAGS

468       The following special tags are available when running under strict
469       conformance (otherwise they don't act special):
470
471   xmlpi
472       Processing instruction; first argument is target, remaining arguments
473       are attribute, value pairs.  Attribute names are syntax checked, values
474       are escaped.
475
476   xmlcmnt
477       Comment.  Arguments are concatenated and placed inside <!-- ... -->
478       comment delimiters.  Any occurences of '--' in the concatenated
479       arguments are converted to '&#45;&#45;'
480
481   xmldecl (@args)
482       Declaration.  This can be used to specify the version, encoding, and
483       other XML-related declarations (i.e., anything inside the <?xml?> tag).
484       @args can be used to control what is output, as keyword-value pairs.
485
486       By default, the version is set to the value specified in the
487       constructor, or to 1.0 if it was not specified.  This can be overridden
488       by providing a 'version' key in @args.  If you do not want the version
489       at all, explicitly provide undef as the value in @args.
490
491       By default, the encoding is set to the value specified in the
492       constructor; if no value was specified, the encoding will be left out
493       altogether.  Provide an 'encoding' key in @args to override this.
494
495       If a dtd was set in the constructor, the standalone attribute of the
496       declaration will be set to 'no' and the doctype declaration will be
497       appended to the XML declartion, otherwise the standalone attribute will
498       be set to 'yes'.  This can be overridden by providing a 'standalone'
499       key in @args.  If you do not want the standalone attribute to show up,
500       explicitly provide undef as the value.
501
502   xmldtd
503       DTD <!DOCTYPE> tag creation. The format of this method is different
504       from others. Since DTD's are global and cannot contain namespace
505       information, the first argument should be a reference to an array; the
506       elements are concatenated together to form the DTD:
507
508          print $xml->xmldtd([ 'html', 'PUBLIC', $xhtml_w3c, $xhtml_dtd ])
509
510       This would produce the following declaration:
511
512          <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
513               "DTD/xhtml1-transitional.dtd">
514
515       Assuming that $xhtml_w3c and $xhtml_dtd had the correct values.
516
517       Note that you can also specify a DTD on creation using the new()
518       method's dtd option.
519
520   xmlcdata
521       Character data section; arguments are concatenated and placed inside
522       <![CDATA[ ... ]]> character data section delimiters.  Any occurences of
523       ']]>' in the concatenated arguments are converted to ']]&gt;'.
524
525   xml
526       "Final" XML document.  Must be called with one and exactly one
527       XML::Generator-produced XML document.  Any combination of
528       XML::Generator-produced XML comments or processing instructions may
529       also be supplied as arguments.  Prepends an XML declaration, and re-
530       blesses the argument into a "final" class that can't be embedded.
531

CREATING A SUBCLASS

533       For a simpler way to implement subclass-like behavior, see "STACKABLE
534       AUTOLOADs".
535
536       At times, you may find it desireable to subclass XML::Generator. For
537       example, you might want to provide a more application-specific
538       interface to the XML generation routines provided. Perhaps you have a
539       custom database application and would really like to say:
540
541          my $dbxml = new XML::Generator::MyDatabaseApp;
542          print $dbxml->xml($dbxml->custom_tag_handler(@data));
543
544       Here, custom_tag_handler() may be a method that builds a recursive XML
545       structure based on the contents of @data. In fact, it may even be named
546       for a tag you want generated, such as authors(), whose behavior changes
547       based on the contents (perhaps creating recursive definitions in the
548       case of multiple elements).
549
550       Creating a subclass of XML::Generator is actually relatively
551       straightforward, there are just three things you have to remember:
552
553          1. All of the useful utilities are in XML::Generator::util.
554
555          2. To construct a tag you simply have to call SUPER::tagname,
556             where "tagname" is the name of your tag.
557
558          3. You must fully-qualify the methods in XML::Generator::util.
559
560       So, let's assume that we want to provide a custom HTML table() method:
561
562          package XML::Generator::CustomHTML;
563          use base 'XML::Generator';
564
565          sub table {
566              my $self = shift;
567
568              # parse our args to get namespace and attribute info
569              my($namespace, $attr, @content) =
570                 $self->XML::Generator::util::parse_args(@_)
571
572              # check for strict conformance
573              if ( $self->XML::Generator::util::config('conformance') eq 'strict' ) {
574                 # ... special checks ...
575              }
576
577              # ... special formatting magic happens ...
578
579              # construct our custom tags
580              return $self->SUPER::table($attr, $self->tr($self->td(@content)));
581          }
582
583       That's pretty much all there is to it. We have to explicitly call
584       SUPER::table() since we're inside the class's table() method. The
585       others can simply be called directly, assuming that we don't have a
586       tr() in the current package.
587
588       If you want to explicitly create a specific tag by name, or just want a
589       faster approach than AUTOLOAD provides, you can use the tag() method
590       directly. So, we could replace that last line above with:
591
592              # construct our custom tags
593              return $self->XML::Generator::util::tag('table', $attr, ...);
594
595       Here, we must explicitly call tag() with the tag name itself as its
596       first argument so it knows what to generate. These are the methods that
597       you might find useful:
598
599       XML::Generator::util::parse_args()
600           This parses the argument list and returns the namespace (arrayref),
601           attributes (hashref), and remaining content (array), in that order.
602
603       XML::Generator::util::tag()
604           This does the work of generating the appropriate tag. The first
605           argument must be the name of the tag to generate.
606
607       XML::Generator::util::config()
608           This retrieves options as set via the new() method.
609
610       XML::Generator::util::escape()
611           This escapes any illegal XML characters.
612
613       Remember that all of these methods must be fully-qualified with the
614       XML::Generator::util package name. This is because AUTOLOAD is used by
615       the main XML::Generator package to create tags. Simply calling
616       parse_args() will result in a set of XML tags called <parse_args>.
617
618       Finally, remember that since you are subclassing XML::Generator, you do
619       not need to provide your own new() method. The one from XML::Generator
620       is designed to allow you to properly subclass it.
621

STACKABLE AUTOLOADs

623       As a simpler alternative to traditional subclassing, the "AUTOLOAD"
624       that "use XML::Generator;" exports can be configured to work with a
625       pre-defined "AUTOLOAD" with the ':stacked' option.  Simply ensure that
626       your "AUTOLOAD" is defined before "use XML::Generator ':stacked';"
627       executes.  The "AUTOLOAD" will get a chance to run first; the
628       subroutine name will be in your $AUTOLOAD as normal.  Return an empty
629       list to let the default XML::Generator "AUTOLOAD" run or any other
630       value to abort it.  This value will be returned as the result of the
631       original method call.
632
633       If there is no "import" defined, XML::Generator will create one.  All
634       that this "import" does is export AUTOLOAD, but that lets your package
635       be used as if it were a subclass of XML::Generator.
636
637       An example will help:
638
639               package MyGenerator;
640
641               my %entities = ( copy => '&copy;',
642                                nbsp => '&nbsp;', ... );
643
644               sub AUTOLOAD {
645                 my($tag) = our $AUTOLOAD =~ /.*::(.*)/;
646
647                 return $entities{$tag} if defined $entities{$tag};
648                 return;
649               }
650
651               use XML::Generator qw(:pretty :stacked);
652
653       This lets someone do:
654
655               use MyGenerator;
656
657               print html(head(title("My Title", copy())));
658
659       Producing:
660
661               <html>
662                 <head>
663                   <title>My Title&copy;</title>
664                 </head>
665               </html>
666

AUTHORS

668       Benjamin Holzman <bholzman@earthlink.net>
669           Original author and maintainer
670
671       Bron Gondwana <perlcode@brong.net>
672           First modular version
673
674       Nathan Wiger <nate@nateware.com>
675           Modular rewrite to enable subclassing
676

LICENSE

678       This library is free software, you can redistribute it and/or modify it
679       under the same terms as Perl itself.
680

SEE ALSO

682       The XML::Writer module
683           http://search.cpan.org/search?mode=module&query=XML::Writer
684
685
686
687perl v5.38.0                      2023-07-21                 XML::Generator(3)
Impressum