/[pub]/suikawiki/script/lib/SuikaWiki/Markup/XML.pm
Suika

Contents of /suikawiki/script/lib/SuikaWiki/Markup/XML.pm

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7 - (hide annotations) (download)
Mon Jun 16 09:59:49 2003 UTC (22 years, 1 month ago) by wakaba
Branch: MAIN
Changes since 1.6: +128 -50 lines
Parser update

1 wakaba 1.1
2     =head1 NAME
3    
4     SuikaWiki::Markup::XML --- SuikaWiki: Simple well-formed document fragment generator
5    
6     =head1 DESCRIPTION
7    
8     This module can be used to generate the document fragment of XML, SGML or
9     other well-formed (in XML meaning) data formats with the object oriented manner.
10    
11     This module cannot be used to parse XML (or other marked-up) document (or its fragment)
12     by itself, nor is compatible with other huge packages such as XML::Parser. The only purpose
13     of this module is to make it easy for tiny perl scripts to GENERATE well-formed
14     markup constructures. (SuikaWiki is not "tiny"? Oh, yes, I see:-))
15    
16     =cut
17    
18     package SuikaWiki::Markup::XML;
19     use strict;
20 wakaba 1.7 our $VERSION = do{my @r=(q$Revision: 1.6 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
21 wakaba 1.2 use overload '""' => \&stringify,
22     fallback => 1;
23     use Char::Class::XML qw!InXML_NameStartChar InXMLNameChar InXML_NCNameStartChar InXMLNCNameChar!;
24 wakaba 1.1 our %Namespace_URI_to_prefix = (
25     'DAV:' => [qw/dav webdav/],
26     'http://greenbytes.de/2002/rfcedit' => [qw/ed/],
27     'http://icl.com/saxon' => [qw/saxon/],
28     'http://members.jcom.home.ne.jp/jintrick/2003/02/site-concept.xml#' => ['', qw/sitemap/],
29     'http://purl.org/dc/elements/1.1/' => [qw/dc dc11/],
30     'http://purl.org/rss/1.0/' => ['', qw/rss rss10/],
31     'http://suika.fam.cx/~wakaba/lang/rfc/translation/' => [qw/ja/],
32     'http://www.mozilla.org/xbl' => ['', qw/xbl/],
33 wakaba 1.3 'http://www.w3.org/1999/02/22-rdf-syntax-ns#' => [qw/rdf/],
34 wakaba 1.1 'http://www.w3.org/1999/xhtml' => ['', qw/h h1 xhtml xhtml1/],
35     'http://www.w3.org/1999/xlink' => [qw/l xlink/],
36     'http://www.w3.org/1999/XSL/Format' => [qw/fo xslfo xsl-fo xsl/],
37     'http://www.w3.org/1999/XSL/Transform' => [qw/t s xslt xsl/],
38     'http://www.w3.org/1999/XSL/TransformAlias' => [qw/axslt axsl xslt xsl/],
39     'http://www.w3.org/2000/01/rdf-schema#' => [qw/rdfs/],
40     'http://www.w3.org/2000/svg' => ['', qw/s svg/],
41     'http://www.w3.org/2002/06/hlink' => [qw/h hlink/],
42     'http://www.w3.org/2002/06/xhtml2' => ['', qw/h h2 xhtml xhtml2/],
43 wakaba 1.3 'http://www.w3.org/2002/07/owl' => [qw/owl/],
44 wakaba 1.6 'http://www.w3.org/2002/xforms/cr' => [qw/f xforms/],
45 wakaba 1.1 'http://www.w3.org/TR/REC-smil' => ['', qw/smil smil1/],
46 wakaba 1.3 'http://www.wapforum.org/2001/wml' => [qw/wap/],
47 wakaba 1.1 'http://xml.apache.org/xalan' => [qw/xalan/],
48     'mailto:julian.reschke@greenbytes.de?subject=rcf2629.xslt' => [qw/myns/],
49     'urn:schemas-microsoft-com:vml' => [qw/v vml/],
50     'urn:schemas-microsoft-com:xslt' => [qw/ms msxsl msxslt/],
51     'urn:x-suika-fam-cx:markup:ietf:html:3:draft:00' => ['', qw/H HTML HTML3/],
52 wakaba 1.7 'urn:x-suika-fam-cx:markup:ietf:rfc:2629' => ['', qw/rfc rfc2629/],
53 wakaba 1.1 );
54     my %Cache;
55 wakaba 1.7 my $NS_SGML = 'urn:x-suika-fam-cx:markup:sgml:'; # obsolete
56     my %NS = (
57     SGML => 'urn:x-suika-fam-cx:markup:sgml:',
58     );
59 wakaba 1.1
60     =head1 METHODS
61    
62     =over 4
63    
64     =item $x = SuikaWiki::Markup::XML->new (%options)
65    
66     Returns new instance of the module. It is itself a node.
67    
68 wakaba 1.4 Available options: C<data_type>, C<default_decl>, C<type> (default: C<#element>), C<local_name>, C<namespace_uri> and C<value>.
69 wakaba 1.1
70     =cut
71    
72     sub new ($;%) {
73     my $class = shift;
74     my $self = bless {@_}, $class;
75     $self->{type} ||= '#element';
76 wakaba 1.5 if ($self->{qname}) {
77     ($self->{namespace_prefix}, $self->{local_name}) = $self->_ns_parse_qname ($self->{qname});
78     $self->{_qname} = $self->{qname};
79     }
80     if (defined $self->{namespace_prefix}) {
81     $self->{namespace_prefix} .= ':' if $self->{namespace_prefix}
82     && substr ($self->{namespace_prefix}, -1) ne ':';
83     $self->{ns}->{$self->{namespace_prefix}||''} = $self->{namespace_uri} if defined $self->{namespace_uri};
84     }
85 wakaba 1.4 for (qw/local_name value/) {
86 wakaba 1.7 if (ref ($self->{$_}) && (ref ($self->{$_}->_CLASS_NAME) eq $self->_CLASS_NAME)) {
87 wakaba 1.2 $self->{$_}->{parent} = $self;
88     }
89     }
90 wakaba 1.1 $self->{node} ||= [];
91     $self;
92     }
93    
94 wakaba 1.5 sub _ns_parse_qname ($$) {
95     shift;
96     my $qname = shift;
97     if ($qname =~ /:/) {
98     return split /:/, $qname, 2;
99     } else {
100     return (undef, $qname);
101     }
102     }
103 wakaba 1.1
104     =item $x->append_node ($node)
105    
106     Appending given node to the object (as the last child).
107     If the type of given node is C<#fragment>, its all children, not the node
108     itself, are appended.
109    
110     This method returns the appended node unless the type of given node is C<#fragment>.
111     In such cases, this node (C<$x>) is returned.
112    
113 wakaba 1.2 Available options: C<node_or_text>.
114    
115 wakaba 1.1 =cut
116    
117 wakaba 1.2 sub append_node ($$;%) {
118 wakaba 1.1 my $self = shift;
119 wakaba 1.2 my ($new_node, %o) = @_;
120     unless (ref $new_node) {
121     if ($o{node_or_text}) {
122     return $self->append_text ($new_node);
123     } else {
124     die "append_node: Invalid node" unless ref $new_node;
125     }
126     }
127 wakaba 1.1 if ($new_node->{type} eq '#fragment') {
128     for (@{$new_node->{node}}) {
129     push @{$self->{node}}, $_;
130     $_->{parent} = $self;
131     }
132     $self;
133     } else {
134     push @{$self->{node}}, $new_node;
135     $new_node->{parent} = $self;
136     $new_node;
137     }
138     }
139    
140     =item $new_node = $x->append_new_node (%options)
141    
142     Appending a new node. The new node is returned.
143    
144     Available options: C<type>, C<namespace_uri>, C<local_name>, C<value>.
145    
146     =cut
147    
148     sub append_new_node ($;%) {
149     my $self = shift;
150     my %o = @_;
151     my $new_node = __PACKAGE__->new (%o);
152     push @{$self->{node}}, $new_node;
153     $new_node->{parent} = $self;
154     $new_node;
155     }
156    
157     =item $new_node = $x->append_text ($text)
158    
159     Appending given text as a new text node. The new text node is returned.
160    
161     =cut
162    
163     sub append_text ($$;%) {
164     my $self = shift;
165     my $s = shift;
166     #if (@{$self->{node}}[-1]->{type} eq '#text') {
167     # $self->{node}}[-1]->append_new_node (type => '#text', value => $s);
168     #} else {
169     $self->append_new_node (type => '#text', value => $s);
170     #}
171     }
172    
173 wakaba 1.2 sub append_baretext ($$;%) {
174     my $self = shift;
175     my $s = shift;
176     $self->append_new_node (type => '#xml', value => $s);
177     }
178    
179 wakaba 1.1 =item $attr_node = $x->get_attribute ($local_name, %options)
180    
181     Returns the attribute node whose local-name is C<$local_name>.
182    
183     Available options: C<namespace_uri>, C<make_new_node>.
184    
185     =cut
186    
187     sub get_attribute ($$;%) {
188     my $self = shift;
189     my ($name, %o) = @_;
190     for (@{$self->{node}}) {
191     if ($_->{type} eq '#attribute' && $_->{local_name} eq $name && $o{namespace_uri} eq $_->{namespace_uri}) {
192     return $_;
193     }
194     }
195     ## Node is not exist
196     if ($o{make_new_node}) {
197     return $self->append_new_node (type => '#attribute', local_name => $name, namespace_uri => $o{namespace_uri});
198     } else {
199     return undef;
200     }
201     }
202    
203     =item $attr_node = $x->set_attribute ($local_name => $value, %options)
204    
205     Set the value of the attribute. The attribute node is returned.
206    
207     Available options: C<namespace_uri>.
208    
209     =cut
210    
211     sub set_attribute ($$$;%) {
212     my $self = shift;
213     my ($name, $val, %o) = @_;
214 wakaba 1.7 if (ref ($val) eq 'ARRAY' || ref ($val) eq 'HASH' || ref ($val) eq 'CODE') {
215     ## TODO: common error handling
216     require Carp;
217     Carp::croak "set_attribute: new attribute value must be string or blessed object";
218     }
219 wakaba 1.1 for (@{$self->{node}}) {
220     if ($_->{type} eq '#attribute' && $_->{local_name} eq $name && $o{namespace_uri} eq $_->{namespace_uri}) {
221     $_->{value} = $val;
222     $_->{node} = [];
223     return $_;
224     }
225     }
226     return $self->append_new_node (type => '#attribute', local_name => $name, value => $val, namespace_uri => $o{namespace_uri});
227     }
228    
229     =item \@children = $x->child_nodes
230    
231     Returns an array reference to child nodes.
232    
233 wakaba 1.4 =item $local_name = $x->local_name ([$new_name])
234 wakaba 1.1
235 wakaba 1.4 Returns or set the local-name.
236    
237     =item $uri = $x->namespace_uri ([$new_uri])
238    
239     Returns or set namespace name (URI) of the element or the attribute
240 wakaba 1.1
241 wakaba 1.5 =item $uri = $x->namespace_prefix ([$new_prefix])
242    
243     Returns or set namespace prefix of the element or the attribute.
244     You may give C<$new_prefix> in form either 'foo' or 'foo:'.
245     To indicate "default" prefix, use '' (length == 0 string).
246    
247 wakaba 1.1 =item $type = $x->node_type
248    
249     Returns the node type.
250    
251     =item $node = $x->parent_node
252    
253     Returns the parent node. If there is no parent node, undef is returned.
254    
255     =cut
256    
257     sub child_nodes ($) { shift->{node} }
258 wakaba 1.4 sub local_name ($;$) {
259     my ($self, $newname) = @_;
260     if ($newname) {
261     $self->{local_name} = $newname;
262     }
263     if (ref $self->{local_name} && $self->{local_name}->{type} eq '#declaration') {
264     $self->{local_name}->{local_name};
265     } else {
266     $self->{local_name}
267     }
268     }
269 wakaba 1.1 sub node_type ($) { shift->{type} }
270     sub parent_node ($) { shift->{parent} }
271    
272 wakaba 1.4 ## TODO: obsolete
273     sub target_name ($;$) {
274     my ($self, $new) = @_;
275     if (defined $new) {
276     $self->{target_name} = $new;
277     }
278     $self->{target_name};
279     }
280    
281     sub namespace_uri ($;$) {
282     my ($self, $new_uri) = @_;
283     if (defined $new_uri) {
284     $self->{namespace_uri} = $new_uri;
285     }
286     $self->{namespace_uri};
287     }
288 wakaba 1.5 sub namespace_prefix ($;$) {
289     my ($self, $new_pfx) = @_;
290     if (defined $new_pfx && $self->{namespace_uri}) {
291     $new_pfx .= ':' if $new_pfx;
292     $self->{namespace_prefix} = $new_pfx;
293     $self->{ns}->{$new_pfx} = $self->{namespace_uri};
294     }
295     $self->_get_namespace_prefix ($self->{namespace_uri});
296     }
297 wakaba 1.4
298 wakaba 1.1 =item $i = $x->count
299    
300     Returns the number of child nodes.
301    
302     =cut
303    
304     # TODO: support counting by type
305     sub count ($;@) {
306 wakaba 1.2 my $self = shift;
307     (defined $self->{value} ? 1 : 0) + scalar @{$self->{node}};
308 wakaba 1.1 }
309    
310     # $prefix = $x->_get_namespace_prefix ($namespace_uri)
311     sub _get_namespace_prefix ($$;%) {
312     my ($self, $uri) = (shift, shift);
313     my %o = @_;
314     if (defined (my $p = $self->_uri_to_prefix ($uri, undef, %o))) {
315     return $p if $self->_prefix_to_uri ($p) eq $uri;
316     } if ($Namespace_URI_to_prefix{$uri}) {
317     for (@{$Namespace_URI_to_prefix{$uri}}) {
318     my $pfx = $_; $pfx .= ':' if $pfx;
319     if ($self->_check_namespace_prefix ($pfx) && !$self->_prefix_to_uri ($pfx)) {
320     return $self->_uri_to_prefix ($uri => $pfx, %o);
321     }
322     }
323     } else {
324     my ($u_r_i, $pfx) = ($uri);
325 wakaba 1.4 $u_r_i =~ s/[^0-9A-Za-z._-]+/ /g;
326     my @u_r_i = split / /, $u_r_i;
327     for (reverse @u_r_i) {
328     if (s/([A-Za-z][0-9A-Za-z._-]+)//) {
329     my $p_f_x = $1 . ':';
330     next if lc (substr ($p_f_x, 0, 3)) eq 'xml';
331     unless ($self->_prefix_to_uri ($p_f_x)) {
332     $pfx = $p_f_x;
333     last;
334     }
335 wakaba 1.1 }
336     }
337     if ($pfx) {
338     return $self->_uri_to_prefix ($uri => $pfx, %o);
339     } else {
340     while (1) {
341     my $pfx = 'ns'.(++$self->{ns}->{-anonymous}).':';
342     unless ($self->_prefix_to_uri ($pfx)) {
343     return $self->_uri_to_prefix ($uri => $pfx, %o);
344     }
345     }
346     }
347     }
348     }
349    
350 wakaba 1.4 sub _set_prefix_to_uri ($$$;%) {
351     my ($self, $prefix => $uri, %o) = @_;
352     return undef unless $self->_check_namespace_prefix ($prefix);
353     $self->{ns}->{$prefix} = $uri;
354     $self->_prefix_to_uri ($prefix);
355     }
356    
357     ## TODO: removing ns declare (1.1) support
358     # $uri or undef = $x->_prefix_to_uri ($prefix)
359 wakaba 1.1 sub _prefix_to_uri ($$;$%) {
360 wakaba 1.4 my ($self, $prefix, %o) = @_;
361 wakaba 1.1 return undef unless $self->_check_namespace_prefix ($prefix);
362     if (uc (substr $prefix, 0, 3) eq 'XML') {
363     return 'http://www.w3.org/XML/1998/namespace' if $prefix eq 'xml:';
364     return 'http://www.w3.org/2000/xmlns/' if $prefix eq 'xmlns:';
365 wakaba 1.2 }
366     if (defined $self->{ns}->{$prefix}) {
367 wakaba 1.1 $self->{ns}->{$prefix};
368     } elsif (ref $self->{parent}) {
369     shift; # $self
370     $self->{parent}->_prefix_to_uri (@_);
371     } else {
372     undef;
373     }
374     }
375    
376     # $prefix or undef = $x->_uri_to_prefix ($uri => [$new_prefix], %options)
377     # use_no_prefix (default: 1): Allow default namespace (no prefix).
378     sub _uri_to_prefix ($$;$%) {
379     my ($self, $uri, $new_prefix, %o) = @_;
380     if (defined $new_prefix && $self->_check_namespace_prefix ($new_prefix)) {
381     $self->{ns}->{$new_prefix} = $uri;
382     $new_prefix;
383     } else {
384     return 'xml:' if $uri eq 'http://www.w3.org/XML/1998/namespace';
385     return 'xmlns:' if $uri eq 'http://www.w3.org/2000/xmlns/';
386     for (keys %{$self->{ns}||{}}) {
387     next if ($_ eq '') && !(!defined $o{use_no_prefix} || $o{use_no_prefix});
388     return $_ if $self->{ns}->{$_} eq $uri;
389     }
390 wakaba 1.2 if (ref ($self->{parent}) && $self->{parent}->{type} ne '#declaration') {
391 wakaba 1.1 shift; # $self
392     $self->{parent}->_uri_to_prefix (@_);
393     } else {
394     undef;
395     }
396     }
397     }
398    
399     =item $x->define_new_namespace ($prefix => $uri)
400    
401     Defines a new XML Namespace. This method is useful for root or section-level
402     element node.
403    
404     Returned value is unspecified in this version of this module.
405    
406     =cut
407    
408 wakaba 1.4 ## TODO: structured URI (such as http://&server;/) support
409 wakaba 1.1 sub define_new_namespace ($$$) {
410     my ($self, $prefix, $uri) = @_;
411     if ($prefix eq '' || $self->_check_ncname ($prefix)) {
412     $prefix .= ':' if $prefix && substr ($prefix, -1) ne ':';
413 wakaba 1.4 $self->_set_prefix_to_uri ($prefix => $uri);
414 wakaba 1.1 } else {
415     undef;
416     }
417     }
418    
419 wakaba 1.4 =item $uri = $x->defined_namespace_prefix ($prefix)
420    
421     Query whether the namespace prefix is defined or not.
422     If defined, return namespace name (URI).
423    
424     =cut
425    
426     sub defined_namespace_prefix ($$) {
427     my ($self, $prefix) = @_;
428     $prefix .= ':' if $prefix;#Carp::carp join ",", ';',@_;
429     $self->_prefix_to_uri ($prefix);
430     }
431    
432 wakaba 1.1 =item $qname = $x->qname
433    
434     Returns QName ((namespace-)qualified name) of the element type.
435     Undef is retuened when the type does not have its QName
436     (ie. when type is neither C<#element> or C<#attribute>).
437    
438     =cut
439    
440     sub qname ($) {
441     my $self = shift;
442     if ($self->_check_ncname ($self->{local_name})) {
443     if ($self->{type} eq '#element') {
444     $self->{_qname} = $self->_get_namespace_prefix ($self->{namespace_uri}) . $self->{local_name}
445     unless $self->{_qname};
446     return $self->{_qname};
447     } elsif ($self->{type} eq '#attribute') {
448     return $self->attribute_name;
449     }
450     }
451     undef;
452     }
453    
454 wakaba 1.7 sub remove_references ($) {
455     my $self = shift;
456     my @node;
457     for (@{$self->{node}}) {
458     $_->remove_references;
459     }
460     for (@{$self->{node}}) {
461     if ($_->{type} ne '#reference'
462     || ($self->{type} eq '#declaration' && $_->{namespace_uri} eq $NS{SGML}.'entity')) {
463     push @node, $_;
464     } else {
465     if ($_->{namespace_uri} =~ /char/) {
466     my $e = ref ($_)->new (type => '#text', value => chr $_->{value});
467     $e->{parent} = $self;
468     push @node, $e;
469     } elsif ($_->{flag}->{smxp__ref_expanded}) {
470     for my $e (@{$_->{node}}) {
471     $e->{parent} = $self;
472     push @node, $e;
473     }
474     } else { ## reference is not expanded
475     push @node, $_;
476     }
477     }
478     }
479     $self->{node} = \@node;
480     }
481    
482 wakaba 1.1 =item $tag = $x->start_tag
483    
484 wakaba 1.4 Returns the start tag (or something that marks the start of something, such as '<!--'
485 wakaba 1.1 for C<#comment> nodes).
486    
487     =cut
488    
489     sub start_tag ($) {
490     my $self = shift;
491     if ($self->{type} eq '#element' && $self->_check_ncname ($self->{local_name})) {
492     my $r = '<';
493     $r .= $self->qname;
494     for (@{$self->{node}}) {
495     $r .= ' ' . $_->outer_xml if $_->node_type eq '#attribute';
496     }
497     for my $prefix (grep !/^-/, keys %{$self->{ns}||{}}) {
498     if ($prefix) {
499     $r .= ' xmlns:'.substr ($prefix, 0, length ($prefix)-1);
500     } else {
501     $r .= ' xmlns';
502     }
503     $r .= '="'.$self->_entitize ($self->{ns}->{$prefix}).'"';
504     }
505     $r .= '>';
506     $r;
507     } elsif ($self->{type} eq '#comment') {
508 wakaba 1.4 '<!--';
509     } elsif ($self->{type} eq '#pi' && $self->_check_ncname ($self->{local_name})) {
510     '<?' . ($self->{local_name});
511 wakaba 1.2 } elsif ($self->{type} eq '#reference') {
512     if ($self->{namespace_uri} eq 'urn:x-suika-fam-cx:markup:sgml:char:ref:hex') {
513     '&#x';
514     } elsif ($self->{namespace_uri} eq 'urn:x-suika-fam-cx:markup:sgml:char:ref') {
515     '&#';
516 wakaba 1.4 } elsif (ref $self->{local_name} && $self->{local_name}->{type} eq '#declaration') {
517     if ($self->{local_name}->{namespace_uri} eq 'urn:x-suika-fam-cx:markup:sgml:entity:parameter') {
518 wakaba 1.2 '%';
519     } else {
520     '&';
521     }
522 wakaba 1.4 } elsif ($self->_check_ncname ($self->{local_name})) {
523 wakaba 1.2 if ($self->{namespace_uri} eq 'urn:x-suika-fam-cx:markup:sgml:entity:parameter') {
524     '%';
525     } else {
526     '&';
527     }
528     } else { # error
529     '';
530     }
531 wakaba 1.4 } elsif ($self->{type} eq '#declaration' && $self->{namespace_uri}) {
532     '<!' . {
533     $NS_SGML.'attlist' => 'ATTLIST',
534     $NS_SGML.'doctype' => 'DOCTYPE',
535     $NS_SGML.'element' => 'ELEMENT',
536     $NS_SGML.'entity' => 'ENTITY',
537 wakaba 1.7 $NS_SGML.'entity:parameter' => 'ENTITY',
538 wakaba 1.4 $NS_SGML.'notation' => 'NOTATION',
539     $NS_SGML.'sgml' => 'SGML',
540 wakaba 1.7 }->{$self->{namespace_uri}} . ' ' . ($self->{namespace_uri} eq $NS{SGML}.'entity:parameter' ?
541     ($self->{flag}->{smxp__defined_with_param_ref}?'':'% '):'');
542 wakaba 1.1 } elsif ($self->{type} eq '#declaration' && $self->_check_ncname ($self->{local_name})) {
543     my $r = '<!' . $self->{local_name} . ' ';
544     if ($self->{local_name} eq 'DOCTYPE' && ref $self->{parent}) {
545     my $qname;
546     for (@{$self->{parent}->{node}}) {
547     if ($_->{type} eq '#element') {
548     $qname = $_->qname;
549     last if $qname;
550     }
551     }
552     $r .= ($qname ? $qname : '#IMPLIED') . ' ';
553 wakaba 1.2 }
554     $r;
555     } elsif ($self->{type} eq '#section') {
556     if (ref $self->{local_name} && $self->{local_name}->{type} eq '#reference') {
557     '<![' . $self->{local_name} . '[';
558     } elsif ($self->_check_ncname ($self->{local_name})) {
559     '<![' . $self->{local_name} . '[';
560     } else { # error
561     '';
562 wakaba 1.1 }
563     } else {
564     '';
565     }
566     }
567    
568     =item $tag = $x->end_tag
569    
570 wakaba 1.4 Returns the end tag (or something that marks the end of something, such as '-->'
571 wakaba 1.1 for C<#comment> nodes).
572    
573     =cut
574    
575     sub end_tag ($) {
576     my $self = shift;
577     if ($self->{type} eq '#element' && $self->_check_ncname ($self->{local_name})) {
578     '</' . $self->qname . '>';
579     } elsif ($self->{type} eq '#comment') {
580 wakaba 1.4 '-->';
581 wakaba 1.1 } elsif ($self->{type} eq '#pi' && $self->_check_ncname ($self->{local_name})) {
582     '?>';
583 wakaba 1.2 } elsif ($self->{type} eq '#reference') {
584     ';';
585 wakaba 1.4 } elsif ($self->{type} eq '#declaration' && $self->{namespace_uri}) {
586     '>';
587 wakaba 1.1 } elsif ($self->{type} eq '#declaration' && $self->_check_ncname ($self->{local_name})) {
588 wakaba 1.4 '>';
589 wakaba 1.2 } elsif ($self->{type} eq '#section') {
590     if (ref $self->{local_name} && $self->{local_name}->{type} eq '#reference') {
591     ']]>';
592     } elsif ($self->_check_ncname ($self->{local_name})) {
593     ']]>';
594     } else { # error
595     '';
596     }
597 wakaba 1.1 } else {
598     '';
599     }
600     }
601    
602     =item $tag = $x->attribute_name
603    
604     Returns the attribute name.
605    
606     =cut
607    
608     sub attribute_name ($) {
609     my $self = shift;
610     if ($self->{type} eq '#attribute' && $self->_check_ncname ($self->{local_name})) {
611     ($self->{namespace_uri} ?
612     (ref $self->{parent} ? $self->{parent} : $self)
613     ->_get_namespace_prefix ($self->{namespace_uri}, use_no_prefix => 0) : '')
614     .$self->{local_name};
615     } else {
616     '';
617     }
618     }
619    
620     =item $tag = $x->attribute_value
621    
622     Returns the attribute value.
623    
624     =cut
625    
626 wakaba 1.4 sub attribute_value ($;%) {
627 wakaba 1.1 my $self = shift;
628 wakaba 1.4 my %o = @_;
629 wakaba 1.1 if ($self->{type} eq '#attribute' && $self->_check_ncname ($self->{local_name})) {
630 wakaba 1.5 my $r = '"';
631 wakaba 1.7 if (ref ($self->{value}) && ($self->{value}->_CLASS_NAME eq $self->_CLASS_NAME)) {
632 wakaba 1.5 unshift @{$self->{node}}, $self->{value};
633     undef $self->{value};
634     } else {
635     $r .= $self->_entitize ($self->{value});
636     }
637 wakaba 1.4 for (@{$self->{node}}) {
638     my $nt = $_->node_type;
639     if ($nt eq '#reference' || $nt eq '#xml') {
640     $r .= $_->outer_xml;
641     } elsif ($nt ne '#attribute') {
642     $r .= $self->_entitize ($_->inner_text, percent => $o{escape_percent});
643     }
644     }
645     return $r . '"';
646     } else {
647     '';
648     }
649     }
650    
651     sub entity_value ($;%) {
652     my $self = shift;
653     my %o = @_;
654     my $_entitize = sub {
655     my $s = shift;
656 wakaba 1.7 $s =~ s/&/&#x26;/g;
657     $s =~ s/&#x26;(\p{InXML_NameStartChar}\p{InXMLNameChar}*);/&$1;/g;
658 wakaba 1.4 $s =~ s/%/&#x25;/g;
659 wakaba 1.7 $s =~ s/"/&#x22;/g;
660 wakaba 1.4 $s;
661     };
662     if ($self->{type} eq '#attribute' && $self->_check_ncname ($self->{local_name})) {
663     my $r = '"' . &$_entitize ($self->{value});
664     for (@{$self->{node}}) {
665     my $nt = $_->node_type;
666     if ($nt eq '#reference' || $nt eq '#xml') {
667     $r .= $_->outer_xml;
668     } elsif ($nt ne '#attribute') {
669     $r .= &$_entitize ($_->inner_text);
670 wakaba 1.1 }
671     }
672 wakaba 1.4 return $r . '"';
673 wakaba 1.1 } else {
674     '';
675     }
676     }
677    
678 wakaba 1.7 ## This method should be called only from SuikaWiki::Markup::XML::* family modules,
679     ## since this is NOT a FORMAL interface.
680     sub _entity_parameter_literal_value ($;%) {
681     my $self = shift;
682     my $r = $self->{value};
683     for (@{$self->{node}}) {
684     my $nt = $_->node_type;
685     if ($nt eq '#reference' || $nt eq '#xml') {
686     $r .= $_->outer_xml;
687     } elsif ($nt ne '#attribute') {
688     $r .= $_->inner_text;
689     }
690     }
691     return $r;
692     }
693    
694 wakaba 1.1 =item $tag = $x->attribute
695    
696     Returns the attribute (name and value pair).
697    
698     =cut
699    
700     sub attribute ($) {
701     my $self = shift;
702     if ($self->{type} eq '#attribute' && $self->_check_ncname ($self->{local_name})) {
703     $self->attribute_name . '=' . $self->attribute_value;
704     } else {
705     '';
706     }
707     }
708    
709 wakaba 1.2 sub external_id ($;%) {
710     my $self = shift;
711     my %o = @_;
712     my ($pubid, $sysid, $ndata);
713     for (@{$self->{node}}) {
714 wakaba 1.4 if ($_->{type} eq '#attribute' && !$_->{namespace_uri}) {
715 wakaba 1.2 if ($_->{local_name} eq 'PUBLIC') {
716 wakaba 1.4 $pubid = $_->inner_text;
717 wakaba 1.2 } elsif ($_->{local_name} eq 'SYSTEM') {
718 wakaba 1.4 $sysid = $_->inner_text;
719 wakaba 1.2 } elsif ($_->{local_name} eq 'NDATA') {
720 wakaba 1.4 $ndata = $_->inner_text;
721     undef $ndata unless $self->_check_ncname ($ndata);
722 wakaba 1.2 }
723     }
724     }
725     my $r = '';
726 wakaba 1.4 if (length $pubid) {
727     $pubid =~ s|([^\x0A\x0D\x20A-Za-z0-9'()+,./:=?;!*#\@\$_%-])|sprintf '%%%02X', ord $1|ges;
728     }
729     if (length $sysid) {
730     if ($sysid =~ /"/) {
731     if ($sysid =~ /'/) {
732     $sysid =~ s/"/&quot;/; $sysid = '"' . $sysid . '"';
733     } else {
734     $sysid = "'" . $sysid . "'";
735     }
736     } else {
737     $sysid = '"' . $sysid . '"';
738     }
739     }
740 wakaba 1.2 if ($pubid && $sysid) {
741 wakaba 1.4 $r = 'PUBLIC "' . $pubid . '" ' . $sysid;
742 wakaba 1.2 } elsif ($sysid) {
743 wakaba 1.4 $r = 'SYSTEM ' . $sysid;
744 wakaba 1.2 } elsif ($pubid && $o{allow_pubid_only}) {
745 wakaba 1.4 $r = 'PUBLIC "' . $pubid . '"';
746 wakaba 1.2 }
747     if ($r && $ndata && $o{use_ndata}) {
748 wakaba 1.4 $r .= ' NDATA ' . $ndata;
749 wakaba 1.2 }
750     $r;
751     }
752    
753     =item $s = $x->content_spec
754    
755     Generates contentspec of element type declaration (ex. C<(E1 | E2 | E3)>)
756     or AttDef of attribute declaration (ex. C<name CDATA #REQUIRED>).
757    
758     =cut
759    
760     sub content_spec ($) {
761     my $self = shift;
762     if ($self->{type} eq '#element') {
763     my $text = 0;
764     my $contentspec = join ' | ', map {$_->qname} grep {$text = 1 if $_->{type} eq '#text'; $_->{type} eq '#element'} @{$self->{node}};
765     $contentspec = '#PCDATA' . ($contentspec ? ' | ' . $contentspec : '') if $text;
766    
767     return $contentspec ? '(' . $contentspec . ')' : 'EMPTY';
768     } elsif ($self->{type} eq '#attribute') {
769     my $attdef = $self->qname . "\t" . ($self->{data_type} || 'CDATA') . "\t";
770     my $default = $self->{default_decl};
771     $default .= ' ' . $self->attribute_value if $default eq '#FIXED';
772     unless ($default) {
773     $default = defined $self->{value} ? $self->attribute_value : '#IMPLIED';
774     }
775     return $attdef . $default;
776     }
777     }
778    
779 wakaba 1.1 =item $tag = $x->inner_xml
780    
781     Returns the content of the node in XML syntax. (In case of the C<#element> nodes,
782     element content without start- and end-tags is returned.)
783    
784     Note that for not all node types the behavior of this method is defined.
785     For example, returned value of C<#attribute> might be unexpected one
786     in this version of this module.
787    
788     =cut
789    
790 wakaba 1.3 sub inner_xml ($;%) {
791 wakaba 1.1 my $self = shift;
792 wakaba 1.3 my %o = @_;
793 wakaba 1.1 my $r = '';
794     if ($self->{type} eq '#comment') {
795     $r = $self->inner_text;
796     $r =~ s/--/-&#x45;/g;
797     } elsif ($self->{type} eq '#pi') {
798     if (length $self->{value}) {
799     $r = ' ' . $self->{value};
800 wakaba 1.2 $r =~ s/\?>/? >/g; # Same replacement as of the recommendation of XSLT:p.i.
801 wakaba 1.1 }
802     for (@{$self->{node}}) {
803     if ($_->node_type eq '#attribute') {
804     $r .= ' ' . $_->attribute;
805     } else {
806     my $s = $_->inner_text;
807     $s =~ s/\?>/?&gt;/g;
808     $r .= ' ' . $s if length $s;
809     }
810     }
811 wakaba 1.2 } elsif ($self->{type} eq '#reference') {
812     if ($self->{namespace_uri} eq 'urn:x-suika-fam-cx:markup:sgml:char:ref:hex') {
813     $r = sprintf '%02X', $self->{value};
814     } elsif ($self->{namespace_uri} eq 'urn:x-suika-fam-cx:markup:sgml:char:ref') {
815     $r = sprintf '%02d', $self->{value};
816 wakaba 1.4 } elsif (ref $self->{local_name} && $self->{local_name}->{type} eq '#declaration') {
817     $r = $self->{local_name}->{local_name};
818     } elsif ($self->_check_ncname ($self->{local_name})) {
819     $r = ($self->{local_name});
820 wakaba 1.2 } else { # error
821     $r = '';
822     }
823 wakaba 1.1 } elsif ($self->{type} eq '#declaration') {
824 wakaba 1.7 if ($self->{namespace_uri} eq $NS_SGML.'doctype') {
825 wakaba 1.4 my $root = $self->get_attribute ('qname');
826     ref $root ? ($root = $root->inner_text) : (ref $self->{parent} ? (do {
827     for (@{$self->{parent}->{node}}) {
828     if ($_->{type} eq '#element') {
829     $root = $_->qname;
830     last if $root;
831     }
832     }
833     $root = '#IMPLIED';
834     }) : ($root = '#IMPLIED')); ## error!
835     my ($isub, $xid) = ('', $self->external_id);
836     for (@{$self->{node}}) {
837     $isub .= $_->outer_xml if $_->{type} ne '#attribute';
838 wakaba 1.2 }
839     if ($xid) {
840 wakaba 1.4 $r = $xid;
841     if ($isub) {
842 wakaba 1.7 $r .= " [" . $isub . "]";
843 wakaba 1.4 }
844     } else {
845     if ($isub) {
846 wakaba 1.7 $r = "[" . $isub . "]";
847 wakaba 1.4 } else {
848     $r = "[]";
849     }
850     }
851     $r = $root . ' ' . $r;
852     } elsif ($self->{namespace_uri} eq 'urn:x-suika-fam-cx:markup:sgml:entity'
853     || $self->{namespace_uri} eq 'urn:x-suika-fam-cx:markup:sgml:entity:parameter'
854     || $self->{namespace_uri} eq 'urn:x-suika-fam-cx:markup:sgml:notation') {
855     my %xid_opt;
856 wakaba 1.7 $r = $self->{local_name} . ' ' if !$self->{flag}->{smxp__defined_with_param_ref}
857     && $self->_check_ncname ($self->{local_name});
858 wakaba 1.4 if ($self->{namespace_uri} eq $NS_SGML.'entity:parameter') {
859     #$r = '% ' . $r;
860     } elsif ($self->{namespace_uri} eq $NS_SGML.'entity') {
861     $xid_opt{use_ndata} = 1;
862     } elsif ($self->{namespace_uri} eq $NS_SGML.'notation') {
863     $xid_opt{allow_pubid_only} = 1;
864     }
865    
866     my ($v, $xid) = ($self->{value}, $self->external_id (%xid_opt));
867 wakaba 1.7 undef $xid if $self->{flag}->{smxp__defined_with_param_ref};
868 wakaba 1.4 if ($xid) { ## External ID
869 wakaba 1.2 $r .= $xid;
870 wakaba 1.4 } else { ## EntityValue
871     my $entity_value = $self->get_attribute ('value');
872 wakaba 1.7 undef $entity_value if $self->{flag}->{smxp__defined_with_param_ref};
873 wakaba 1.4 if ($entity_value) { # <!ENTITY foo "bar">
874     $r .= $entity_value->entity_value;
875     } else { ## Parameter entity reference
876     $r .= $self->{value};
877     for (@{$self->{node}}) {
878 wakaba 1.7 $r .= $_->outer_xml unless $_->{type} eq '#attribute';
879 wakaba 1.4 }
880 wakaba 1.2 }
881 wakaba 1.1 }
882 wakaba 1.4 } elsif ($self->{namespace_uri} eq $NS_SGML.'element') {
883     my $qname = $self->get_attribute ('qname');
884     ref $qname ? $qname = $qname->inner_text : undef;
885     if ($qname && $self->_check_name ($qname)) {
886     ## Element type name is defined
887     $r = $qname . ' ';
888 wakaba 1.3 if ($o{output_tag_omit_declaration}) {
889 wakaba 1.4 $r .= ($self->{flag}->{element_tag_start_omitable} ? 'o ' : '- ')
890     .
891     ($self->{flag}->{element_tag_end_omitable} ? 'o ' : '- ');
892 wakaba 1.3 }
893 wakaba 1.4 my $rs = $self->inner_text (output_ref_as_is => 1);
894     $r .= $rs || 'ANY';
895 wakaba 1.2 } else {
896 wakaba 1.4 #if (ref $self->{node}->[0] && $self->{node}->[0]->{type} eq '#element') {
897     ### Element prototype is given
898     # $r = $self->{node}->[0]->qname . ' ' . &$to . $self->{node}->[0]->content_spec;
899     #} elsif () {
900     ### Element type name and contentspec is given
901     # $r = $self->{target_name} . ' ' . &$to . ($self->inner_text || 'ANY');
902     #} else {
903 wakaba 1.2 ## (Element type name and contetnspac) is given
904 wakaba 1.4 $r .= $self->inner_text (output_ref_as_is => 1);
905     # || 'Name ANY'; # error
906     #}
907 wakaba 1.2 }
908 wakaba 1.7 ## TODO: reform
909 wakaba 1.2 } elsif ($self->{local_name} eq 'ATTLIST') {
910     if ($self->_check_name ($self->{target_name})) {
911     $r = $self->{target_name};
912     }
913     my $t = $self->inner_text (output_ref_as_is => 1);
914     $r .= "\n\t" . $t if $t;
915     $r ||= 'Name'; # error!
916     for (@{$self->{node}}) {
917     if ($_->{type} eq '#attribute') {
918     $r .= "\n\t" . $_->content_spec;
919     }
920 wakaba 1.1 }
921 wakaba 1.2 } else { # unknown
922 wakaba 1.3 for (@{$self->{node}}) {
923     $r .= $_->outer_xml;
924     }
925 wakaba 1.1 }
926 wakaba 1.2 } elsif ($self->{type} eq '#section' && !ref $self->{local_name} && $self->{local_name} eq 'CDATA') {
927     $r = $self->inner_text;
928     $r =~ s/]]>/]]>]]<![CDATA[>/g;
929 wakaba 1.1 } else {
930     if ($self->{type} ne '#xml') {
931     $r = $self->_entitize ($self->{value});
932     } else {
933     $r = $self->{value};
934     }
935     for (@{$self->{node}}) {
936     my $nt = $_->node_type;
937 wakaba 1.4 if (($self->{option}->{indent}) && ($nt eq '#element' || $nt eq '#comment' || $nt eq '#pi' || $nt eq '#declaration')) {
938 wakaba 1.1 $r .= "\n";
939     }
940     $r .= $_->outer_xml unless $_->node_type eq '#attribute';
941     }
942     }
943     $r;
944     }
945    
946    
947     =item $tag = $x->outer_xml
948    
949     Returns the node in XML syntax.
950    
951     =cut
952    
953     sub outer_xml ($) {
954     my $self = shift;
955     if ($self->{type} eq '#attribute') {
956     $self->attribute;
957     } else {
958 wakaba 1.4 if ($self->{option}->{indent} && $self->{type} eq '#element') {
959 wakaba 1.1 my $r = $self->start_tag;
960     my $c = $self->inner_xml;
961 wakaba 1.4 if (!length $c && $self->{option}->{use_EmptyElemTag}) {
962     substr ($r, -1) = ' />';
963     } else {
964     if ($c) {
965     $c =~ s/\n/\n /g;
966     $r .= "\n " . $c . "\n";
967     }
968     $r .= $self->end_tag;
969 wakaba 1.1 }
970     $r;
971     } else {
972 wakaba 1.4 my $r = $self->start_tag;
973     my $c = $self->inner_xml;
974     if ($self->{type} eq '#element' && !length $c && $self->{option}->{use_EmptyElemTag}) {
975     substr ($r, -1) = ' />';
976     } else {
977     $r .= $c . $self->end_tag;
978     #$r .= "\n" if $self->{type} eq '#declaration';
979     }
980 wakaba 1.2 $r;
981     #'{'.$self->{type}.': '.$r.'}'; # for debug
982 wakaba 1.1 }
983     }
984     }
985    
986     =item $tag = $x->inner_text
987    
988     Returns the text content of the node. (In many case the returned value is same
989     as WinIE DOM C<inner_text ()> function's or XPath C<text()> function's.
990     But some classes that inherits this module might implement to return other
991     value (eg. to return the value of the alt attribute of html:img element).
992    
993 wakaba 1.2 Available options: C<output_ref_as_is>.
994    
995 wakaba 1.1 =cut
996    
997 wakaba 1.2 sub inner_text ($;%) {
998 wakaba 1.1 my $self = shift;
999 wakaba 1.2 my %o = @_;
1000 wakaba 1.5 my $r = '';
1001 wakaba 1.7 if ($self->{type} eq '#reference' && #) {
1002     #if (
1003     $self->{namespace_uri} eq $NS{SGML}.'char:ref' ||
1004     $self->{namespace_uri} eq $NS{SGML}.'char:ref:hex') {
1005     $r = chr $self->{value};
1006     #} else { # general entity ref. or parameter entity ref.
1007     # ## TODO: how implement? is this ok?
1008     # my $em = $self->_get_entity_manager;
1009     # $r = $em->get_entity_value ($self->{local_name}, namespace_uri => $self->{namespace_uri});
1010     #}
1011     } elsif ($self->{type} eq '#declaration'
1012     && ($self->{namespace_uri} eq $NS{SGML}.'entity'
1013     || $self->{namespace_uri} eq $NS{SGML}.'entity:parameter')) {
1014     ## TODO:
1015     $r = $self->get_attribute ('value')->inner_text;
1016     } else { # not #reference nor #declaration(ENTITY)
1017     if (ref ($self->{value}) && $self->{value}->_CLASS_NAME eq $self->_CLASS_NAME) {
1018     unshift @{$self->{node}}, $self->{value};
1019     undef $self->{value};
1020     } else {
1021     $r = $self->{value};
1022     }
1023     if ($o{output_ref_as_is}) { ## output as if RCDATA
1024     $r =~ s/&/&amp;/g;
1025     for my $node (@{$self->{node}}) {
1026     my $nt = $node->node_type;
1027     if ($nt eq '#reference' || $nt eq '#xml') {
1028     $r .= $node->outer_xml;
1029     } elsif ($nt ne '#attribute') {
1030     $r .= map {s/&/&amp;/g; $_} $node->inner_text;
1031     }
1032     }
1033     } else {
1034     for (@{$self->{node}}) {
1035     $r .= $_->inner_text unless $_->node_type eq '#attribute';
1036 wakaba 1.2 }
1037     }
1038 wakaba 1.1 }
1039     $r;
1040     }
1041    
1042     {no warnings; # prototype mismatch
1043     *stringify = \&outer_xml;
1044     }
1045    
1046 wakaba 1.7 sub _get_entity_manager ($) {
1047     my $self = shift;
1048     if ($self->{type} eq '#document') {
1049     unless ($self->{flag}->{smx__entity_manager}) {
1050     require SuikaWiki::Markup::XML::EntityManager;
1051     $self->{flag}->{smx__entity_manager} = SuikaWiki::Markup::XML::EntityManager->new ($self);
1052     }
1053     return $self->{flag}->{smx__entity_manager};
1054     } elsif (ref $self->{parent}) {
1055     return $self->{parent}->_get_entity_manager;
1056     } else {
1057     unless ($self->{flag}->{smx__entity_manager}) {
1058     require SuikaWiki::Markup::XML::EntityManager;
1059     $self->{flag}->{smx__entity_manager} = SuikaWiki::Markup::XML::EntityManager->new ($self);
1060     }
1061     return $self->{flag}->{smx__entity_manager};
1062     }
1063     }
1064    
1065 wakaba 1.5 sub _CLASS_NAME ($) {
1066     'SuikaWiki::Markup::XML';
1067     }
1068    
1069 wakaba 1.1 # $s = $x->_entitize ($s)
1070 wakaba 1.4 sub _entitize ($$;%) {
1071     my ($self, $s, %o) = (shift, shift, @_);
1072 wakaba 1.1 $s =~ s/&/&amp;/g;
1073     $s =~ s/</&lt;/g;
1074     $s =~ s/>/&gt;/g;
1075     $s =~ s/"/&quot;/g;
1076 wakaba 1.4 $s =~ s/%/&#x25;/g if $o{percent};
1077     $s =~ s/'/&#x27;/g if $o{apos};
1078 wakaba 1.7 $s =~ s/([\x00-\x08\x0B\x0C\x0E-\x1F])/sprintf '&amp;#%d;', ord $1/ge;
1079 wakaba 1.1 $s;
1080     }
1081    
1082 wakaba 1.2 # 1/0 = $x->_check_name ($s)
1083     sub _check_name ($$) {
1084     my $self = shift;
1085     my $s = shift;
1086     return $Cache{name}->{$s} if defined $Cache{name}->{$s};
1087     if ($s =~ /^\p{InXML_NameStartChar}/ && $s !~ /\P{InXMLNameChar}/) {
1088     # \p{...}('*'/'+'/'{n,}') does not work...
1089     $Cache{name}->{$s} = 1;
1090     1;
1091     } else {
1092     $Cache{name}->{$s} = 0;
1093     0;
1094     }
1095     }
1096 wakaba 1.1 # 1/0 = $x->_check_ncname ($s)
1097     sub _check_ncname ($$) {
1098     my $self = shift;
1099     my $s = shift;
1100     return $Cache{ncname}->{$s} if defined $Cache{ncname}->{$s};
1101     if ($s =~ /^\p{InXML_NCNameStartChar}/ && $s !~ /\P{InXMLNCNameChar}/) {
1102     # \p{...}('*'/'+'/'{n,}') does not work...
1103     $Cache{ncname}->{$s} = 1;
1104     1;
1105     } else {
1106     $Cache{ncname}->{$s} = 0;
1107     0;
1108     }
1109     }
1110    
1111     # 1/0 = $x->_check_namespace_prefix ($s)
1112     sub _check_namespace_prefix ($$) {
1113     my $self = shift;
1114     my $s = shift;
1115     return 0 unless defined $s;
1116     return 1 if $s eq '';
1117     substr ($s, -1, 1) = '' if substr ($s, -1, 1) eq ':';
1118     $self->_check_ncname ($s);
1119     }
1120    
1121 wakaba 1.2 ## TODO: cleaning $self->{node} before outputing, to ensure nodes not to have
1122     ## multiple parents.
1123     ## TODO: normalize namespace URI (removing non URI chars)
1124    
1125     sub flag ($$;$) {
1126     my ($self, $name, $value) = @_;
1127     if (defined $value) {
1128     $self->{flag}->{$name} = $value;
1129     }
1130     $self->{flag}->{$name};
1131     }
1132    
1133 wakaba 1.3 sub option ($$;$) {
1134     my ($self, $name, $value) = @_;
1135     if (defined $value) {
1136     $self->{option}->{$name} = $value;
1137     }
1138     $self->{option}->{$name};
1139     }
1140    
1141 wakaba 1.1 =back
1142    
1143 wakaba 1.2 =head1 NODE TYPES
1144    
1145     =over 4
1146    
1147     =item #attribute
1148    
1149     Attribute. Its XML representation takes the form of NAME="VALUE".
1150    
1151     =item #comment
1152    
1153     Comment declarement. <!-- -->
1154    
1155     =item #declarement
1156    
1157     SGML's declarements, such as SGML, DOCTYPE, ENTITY, etc.
1158     <!SGML ...>, <!DOCTYPE root []>, <!ENTITY % name "value">
1159    
1160     =item #element
1161    
1162     Element. Its XML representation consists of start tag, content and end tag,
1163     like <TYPE>content</TYPE>.
1164    
1165     =item #fragment
1166    
1167     Fragment of nodes. It's similar to DOM's fragment node.
1168    
1169     =item #pi
1170    
1171     Prosessing instruction. <?NAME VALUE?>
1172    
1173     =item #reference
1174    
1175     Character reference or general or parameter entity reference.
1176     &#nnnn;, &#xhhhh;, &name;, %name;.
1177    
1178     =item #section
1179    
1180     Markup section. CDATA, INCLUDE and IGNORE are supported by XML.
1181     <![%type;[...]]>
1182    
1183     =item #text
1184    
1185     Text.
1186    
1187     =item #xml
1188    
1189     Preformatted XML text.
1190    
1191     =cut
1192    
1193 wakaba 1.4 =head1 RESTRICTIONS
1194    
1195     =over 4
1196    
1197     =item XML without XML Namespace is not supported.
1198    
1199     =item Before default namespace without bounded URI (xmlns="") is outputed, it must be declared.
1200    
1201     For example, next code generates invalid (non-well-formed) XML Namespace document.
1202    
1203     my $x = SuikaWiki::Markup::XML->new (local_name => 'elementType');
1204     print $x # <ns1:elementType xmlns:ns1=""></ns1:elementType>
1205    
1206     So you must write like:
1207    
1208     my $x = SuikaWiki::Markup::XML->new (local_name => 'elementType');
1209     $x->define_new_namespace ('' => '');
1210     print $x; # <elementType xmlns=""></elementType>
1211    
1212     =back
1213    
1214 wakaba 1.1 =head1 LICENSE
1215    
1216     Copyright 2003 Wakaba <w@suika.fam.cx>
1217    
1218     This program is free software; you can redistribute it and/or
1219     modify it under the same terms as Perl itself.
1220    
1221     =cut
1222    
1223 wakaba 1.7 1; # $Date: 2003/05/31 07:01:46 $

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24