/[suikacvs]/markup/tool/mkdtds.pl
Suika

Contents of /markup/tool/mkdtds.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.6 - (hide annotations) (download)
Mon Jul 5 13:57:21 2004 UTC (20 years, 5 months ago) by wakaba
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +99 -9 lines
File MIME type: text/plain
Typo fix and ...

1 wakaba 1.3 #!/usr/bin/perl
2 wakaba 1.1 use strict;
3 wakaba 1.3 our $SCRIPT_NAME = 'mkdtds';
4 wakaba 1.6 our $VERSION = do{my @r=(q$Revision: 1.5 $=~/\d+/g);sprintf "%d."."%02d" x $#r,@r};
5 wakaba 1.3 {require Message::Markup::SuikaWikiConfig20::Parser;
6 wakaba 1.1
7 wakaba 1.3 my $parser = new Message::Markup::SuikaWikiConfig20::Parser;
8 wakaba 1.1 local $/ = undef;
9     my $src = $parser->parse_text (scalar <>);
10     my $Info = {};
11    
12     for my $src ($src->get_attribute ('ModuleSet')
13     || $src->get_attribute ('DocumentType')) {
14 wakaba 1.4 for (qw/Description/) {
15 wakaba 1.1 $Info->{$_} = $src->get_attribute_value ($_);
16     }
17 wakaba 1.4 for (qw/Name ID Copyright BaseURI Version/) {
18     $Info->{$_} = normalize_wsp ($src->get_attribute_value ($_));
19     }
20     $Info->{realname} = $Info->{Name};
21 wakaba 1.3 $Info->{Name} .= ' ' . $Info->{Version} if length $Info->{Version};
22 wakaba 1.1 $Info->{ns} = $src->get_attribute ('Namespace');
23     }
24    
25     for (@{$src->child_nodes}) {
26     if ($_->local_name eq 'Attribute') {
27     attrib_module ($_, $Info);
28     } elsif ($_->local_name eq 'Datatype') {
29     datatype_module ($_, $Info);
30     } elsif ($_->local_name eq 'Notation') {
31     notation_module ($_, $Info);
32     } elsif ($_->local_name eq 'Module') {
33     submodule ($_, $Info);
34     } elsif ($_->local_name eq 'Model') {
35     model_module ($_, $Info);
36 wakaba 1.2 $Info->{has_model} = 1;
37 wakaba 1.1 } elsif ($_->local_name eq 'Driver') {
38     dtd_driver ($_, $Info);
39     }
40     }
41    
42     if (ref $src->get_attribute ('ModuleSet')) {
43     qname_module ($src->get_attribute ('ModuleSet'), $Info);
44     }
45     exit}
46    
47 wakaba 1.4 sub normalize_wsp ($;%) {
48     my $s = shift;
49     $s =~ s/\s+/ /g;
50     $s =~ s/^ +//;
51     $s =~ s/ +$//;
52     $s;
53     }
54 wakaba 1.3 sub make_paragraphs ($;%) {
55     my ($para, %opt) = @_;
56     join "\n\n", map {
57     my $s = $_;
58     $s =~ s/\n+$//g;
59     $s =~ s/\n/\n$opt{indent}/g;
60     $opt{indent}.$s;
61     } grep {length} @$para;
62     }
63    
64     sub dot_padding ($%) {
65     my ($s, %opt) = @_;
66     if ($opt{length} - length $s > 0) {
67     return $s . ( ($opt{dot} or q(.)) x ($opt{length} - length $s) );
68     } else {
69     return $s;
70     }
71     }
72    
73 wakaba 1.1 sub submodule_id_of ($$;%) {
74     my ($src, $Info, %opt) = @_;
75     my $id = $src->get_attribute_value ('ID') || $opt{default};
76     unless ($id) {
77     die "$0: Submodule identifier not specified";
78     }
79     $id;
80     }
81     sub xml_datatype_of ($$;%) {
82     my ($src, $Info, %opt) = @_;
83     my $type = $src->get_attribute_value ('XMLType') || $opt{default};
84     $type =~ s/\s+//g;
85     $type;
86     }
87 wakaba 1.2 sub system_id_of ($$;%) {
88     my ($src, $Info, %opt) = @_;
89     my $sysid = $src->get_attribute_value ('SYSTEM');
90     if ($sysid =~ /<([^>]+)>/) {
91     return $1;
92     } else {
93     return $opt{base}.($sysid || $opt{default});
94     }
95     }
96 wakaba 1.1 sub external_id_of ($$;%) {
97     my ($src, $Info, %opt) = @_;
98 wakaba 1.2 my $sysid = system_id_of ($src, $Info, %opt);
99 wakaba 1.1 my $pubid = $src->get_attribute_value ('PUBLIC');
100     if ($pubid) {
101     if ($sysid) {
102     return qq(PUBLIC "$pubid"\n\t "$sysid");
103     } else {
104     return qq(PUBLIC "$pubid");
105     }
106     } else {
107     return qq(SYSTEM "$sysid");
108     }
109     }
110     sub name_of ($$;%) {
111     my ($src, $Info, %opt) = @_;
112     unless (ref $src) {require Carp; Carp::croak ('$src undefined')}
113     my $name = $src->get_attribute_value ($opt{key} || 'Name');
114     if ($name =~ /^:(.+)/) { ## Global namespace
115     return $1;
116     } elsif ($name =~ /([^:]+):(.+)/) { ## Named space
117     return $1.($opt{delim}||'.').$2;
118     } else { ## Default namespace
119     return $Info->{ID}.($opt{delim}||'.').$name;
120     }
121     }
122     sub local_name_of ($$;%) {
123     my ($src, $Info, %opt) = @_;
124     my $name = $src->get_attribute_value ($opt{key} || 'Name');
125     if ($name =~ /^:(.+)/) { ## Global namespace
126     return $1;
127     } elsif ($name =~ /[^:]+:(.+)/) { ## Named space
128     return $1;
129     } else { ## Default namespace
130     return $name;
131     }
132     }
133     sub set_name_of ($$;%) {
134     my ($src, $Info, %opt) = @_;
135     my $name = $src->get_attribute_value ($opt{key} || 'Name');
136     if ($name =~ /^:.+/) { ## Global namespace
137     return 'XHTML';
138     } elsif ($name =~ /([^:]+):.+/) { ## Named space
139     return $1;
140     } else { ## Default namespace
141     return $Info->{ID};
142     }
143     }
144     sub class_name_of ($$;%) {
145     my ($src, $Info, %opt) = @_;
146     my $name = name_of ($src, $Info, %opt);
147     unless ($name =~ /\.(class|mix|content|datatype)$/) {
148     $name .= '.class';
149     }
150     $name;
151     }
152     sub convert_content_model ($$;%) {
153     my ($src, $Info, %opt) = @_;
154     my $model = $src->get_attribute_value ($opt{key} || 'Content') || $opt{default};
155     $model =~ s/\s//g;
156     my $nonsymbol = qr/[^%#?,\$;()+*|:]/;
157     $model =~ s/(?<![%#.])((?:\$|\b)$nonsymbol+(?::$nonsymbol+)?|\$?:$nonsymbol+|"[^"]+")/get_model_token ($1, $Info)/ge;
158     $model;
159     }
160 wakaba 1.2 sub sparalit ($) {
161     my $s = paralit (shift);
162     $s =~ s/&/&#x26;/g;
163     $s =~ s/%/&#x25;/g;
164     $s;
165     }
166 wakaba 1.1 sub paralit ($) {
167     my $s = shift;
168     if ($s =~ /"/) {
169     if ($s =~ /'/) {
170     $s =~ s/'/&#x27;/g;
171     return qq("$s");
172     } else {
173     return qq('$s');
174     }
175     } else {
176     return qq("$s");
177     }
178     }
179     sub description ($$;%) {
180     my ($src, $Info, %opt) = @_;
181     my $desc = $src->get_attribute_value ('Description');
182     $desc =~ s/\n/\n /g;
183     unless ($desc) {
184     $desc = {
185     load_module => {
186     AttributeModule => q/Common Attributes Module/,
187     DatatypeModule => q/Datatypes Module/,
188     NotationModule => q/Notation Module/,
189     QNameModule => q/QName Module/,
190     },
191     }->{$opt{context}}->{$opt{id} || $src->get_attribute_value ($opt{id_key}||'ID')};
192     }
193     $desc = qq(<!-- $desc -->\n) if $desc;
194     $desc;
195     }
196 wakaba 1.3 sub xml_condition_section ($$;%) {
197     my ($condition, $content, %opt) = @_;
198     qq(<![%$condition;[\n)
199     . $content
200     . qq(<!-- end of $condition -->]]>\n);
201     }
202     sub xml_parameter_ENTITY ($%) {
203     my ($name, %opt) = @_;
204     qq(<!ENTITY % $name @{[paralit $opt{value}]}>\n);
205     }
206 wakaba 1.1
207 wakaba 1.2 sub entity_declaration ($$;%) {
208     my ($src, $Info, %opt) = @_;
209     my $val;
210     if ($src->get_attribute_value ('ID')
211     || $src->get_attribute_value ('SYSTEM')
212     || $src->get_attribute_value ('PUBLIC')) {
213     $val = "\n\t".external_id_of ($src, $Info, default => $src->get_attribute_value ('ID'));
214     } elsif (ref $src->get_attribute ('Declaration')) {
215     $val = "\n\t".sparalit submodule_declarations ($src->get_attribute ('Declaration'), $Info);
216     } else {
217     $val = paralit $src->get_attribute_value ('EntityValue');
218     }
219     my $s = <<EOH;
220     @{[description ($src, $Info)]}<!ENTITY @{[$opt{param}?'% ':'']}@{[$src->get_attribute_value ('Name')]} $val>
221    
222     EOH
223     $s;
224     }
225 wakaba 1.1
226 wakaba 1.6 sub parameter_entity_declaration ($$%) {
227     my ($src, $Info, %opt) = @_;
228     my $name = name_of $src, $Info, %opt;
229     if (my $sysid = $src->get_attribute_value ('SYSTEM')) {
230     if ($sysid =~ /^\s*<([^<>]+)>\s*$/) {
231     $sysid = $1;
232     $sysid =~ s/([%"])/sprintf '&#x%02X;', ord $1/ge;
233     } elsif ($sysid =~ /^([^:]*):(.*)$/) {
234     my $ns = $1;
235     $sysid = $2;
236     $sysid =~ s/([%"])/sprintf '&#x%02X;', ord $1/ge;
237     $sysid = '%' . ($ns ? $ns . '.' : '') . 'sysid.base;' . $sysid;
238     } else {
239     $sysid = '%XHTML.sysid.base;' . $sysid;
240     }
241     my $r;
242     if (my $pubid = $src->get_attribute_value ('PUBLIC')) {
243     $r = qq{<!ENTITY % $name.sysid "$sysid">\n} .
244     qq{<!ENTITY % $name.fpi "$pubid">\n} .
245     qq{<!ENTITY % $name.fpi.defined "INCLUDE">\n};
246     } else {
247     $r = qq{<!ENTITY % $name.sysid "$sysid">\n} .
248     qq{<!ENTITY % $name.fpi "">\n} .
249     qq{<!ENTITY % $name.fpi.defined "IGNORE">\n};
250     }
251     return <<EOH;
252     @{[get_desc ($src, $Info, prefix => qq(%$name: ),
253     padding_length => 51, padding_dot => q(.),
254     default => qq(%$name))
255     ]}$r
256     <![%$name.fpi.defined;[
257     <!ENTITY % $name.decl
258     \t'PUBLIC "%$name.fpi;"
259     \t\t"%$name.sysid;"'>
260     ]]>
261     <!ENTITY % $name.decl
262     \t'SYSTEM "%$name.sysid;"'>
263     <!ENTITY % $name %$name.decl;>
264     <!-- @{[dot_padding qq<%$name >, length => 51, dot => q<.>]} -->
265     EOH
266     } else {
267     my $s = get_desc ($src, $Info);
268     $s .= qq{<!ENTITY % $name } .
269     paralit $src->get_attribute_value ('EntityValue');
270     $s .= ">\n";
271     return $s;
272     }
273     }
274    
275 wakaba 1.1 sub dtd_driver ($$) {
276     my ($src, $Info) = @_;
277     my $s = '';
278     my %s;
279     my @module_set;
280     for my $src (@{$src->child_nodes}) {
281     if ($src->local_name eq 'Module') {
282     $s .= dtd_driver_load_module ($src, $Info);
283 wakaba 1.2 } elsif ($src->local_name eq 'DTD') {
284     $s .= dtd_driver_load_dtd ($src, $Info);
285 wakaba 1.1 } elsif ($src->local_name eq 'ModuleSet') {
286     push @module_set, $src;
287     } elsif ($src->local_name =~ /^(?:QName|Attribute|Datatype|Notation)Module/) {
288     $s{$src->local_name} .= dtd_driver_load_module ($src, $Info);
289 wakaba 1.6
290 wakaba 1.1 } elsif ($src->local_name eq 'IfModuleSet') {
291 wakaba 1.6 my $ms = name_of $src, $Info, key => $src->get_attribute_value ('ID') ?
292     'ID' : 'ModuleSet';
293     $s .= qq(<![%$ms.module;[\n);
294     $s .= submodule_declarations ($src, $Info);
295     $s .= qq(<!-- end of $ms -->]]>\n\n);
296    
297     } elsif ($src->local_name eq 'IfModule') {
298     my $ms = name_of $src, $Info, key => 'ID';
299     $s .= qq(<![%$ms.module;[\n);
300 wakaba 1.1 $s .= submodule_declarations ($src, $Info);
301 wakaba 1.6 $s .= qq(<!-- end of $ms -->]]>\n\n);
302     } elsif ($src->local_name eq 'ElementSwitch') {
303     $s .= qq(<!ENTITY % @{[name_of ($src, $Info)]}.element "@{[$src->get_attribute_value ('Use')>0?'INCLUDE':'IGNORE']}">\n);
304     } elsif ($src->local_name eq 'AttributeSwitch') {
305     $s .= qq(<!ENTITY % @{[name_of ($src, $Info)]}.attlist "@{[$src->get_attribute_value ('Use')>0?'INCLUDE':'IGNORE']}">\n);
306     } elsif ($src->local_name eq 'ModuleSwitch') {
307     $s .= qq(<!ENTITY % @{[name_of ($src, $Info)]}.module "@{[$src->get_attribute_value ('Use')>0?'INCLUDE':'IGNORE']}">\n);
308     } elsif ($src->local_name eq 'Switch') {
309     $s .= qq(<!ENTITY % @{[name_of ($src, $Info)]} "@{[$src->get_attribute_value ('Use')>0?'INCLUDE':'IGNORE']}">\n);
310 wakaba 1.1 } elsif ($src->local_name eq 'GeneralEntity') {
311 wakaba 1.2 $s .= entity_declaration ($src, $Info, param => 0);
312 wakaba 1.1 } elsif ($src->local_name eq 'ParameterEntity') {
313 wakaba 1.6 $s .= parameter_entity_declaration ($src, $Info);
314 wakaba 1.1 }
315     }
316    
317 wakaba 1.2 $s{ModelModule} = $src->get_attribute_value ('NoModelModule') ? '' :
318     $Info->{has_model} ? <<EOH : '';
319 wakaba 1.1 <!-- Document Model module -->
320     <!ENTITY % $Info->{ID}-model.module "INCLUDE">
321     <![%$Info->{ID}-model.module;[
322     <!ENTITY % $Info->{ID}-model.decl
323     'SYSTEM "$Info->{ID}-model.mod"'>
324     <!ENTITY % $Info->{ID}-model.mod %$Info->{ID}-model.decl;>
325     %$Info->{ID}-model.mod;]]>
326    
327     EOH
328    
329     $s = dtd_driver_module_sets (\@module_set, $Info)
330     . $s{QNameModule}.$s{DatatypeModule}.$s{NotationModule}.$s{AttributeModule}
331     . $s{ModelModule}
332     .$s;
333     make_dtd ($src, $Info, $src->get_attribute_value ('ID'), $s);
334     }
335    
336     sub dtd_driver_module_sets ($$) {
337     my ($srces, $Info) = @_;
338     my @src = map {{src => $_}} @$srces;
339     my $s = qq(<!-- Switchers to include/ignore each vocabulary -->\n);
340     for my $module_set (@src) {
341     $module_set->{ID} = $module_set->{src}->get_attribute_value ('ID') || 'XHTML';
342     $s .= qq(<!ENTITY % $module_set->{ID}.module "@{[$module_set->{src}->get_attribute_value ('Default') > 0 ? 'INCLUDE' : 'IGNORE']}">\n);
343     }
344     $s .= qq(\n<!-- Namespace names -->\n);
345     for my $module_set (@src) {
346     $module_set->{ns} = $module_set->{src}->get_attribute ('Namespace');
347     $s .= qq(<!ENTITY % $module_set->{ID}.xmlns "@{[$module_set->{ns}->get_attribute_value ('Name')]}">\n);
348     }
349     $s .= qq(\n<!-- Base URIs for the relavant DTD modules -->\n);
350     for my $module_set (@src) {
351     $s .= qq(<!ENTITY % $module_set->{ID}.sysid.base "@{[$module_set->{src}->get_attribute_value ('BaseURI')]}">\n);
352     }
353     $s .= qq(\n<!-- Namespace prefix -->\n);
354     $s .= qq(<!ENTITY % NS.prefixed "@{[$Info->{ns}->get_attribute_value ('UsePrefix') > 0 ? 'INCLUDE' : 'IGNORE']}">\n);
355     for my $module_set (@src) {
356     $s .= qq(<!ENTITY % $module_set->{ID}.prefix "@{[$module_set->{ns}->get_attribute_value ('DefaultPrefix')]}">\n);
357     $s .= qq(<!ENTITY % $module_set->{ID}.prefixed "@{[$module_set->{ns}->get_attribute_value ('UsePrefix') > 0 ? 'INCLUDE' : $module_set->{ns}->get_attribute_value ('UsePrefix') < 0 ? 'IGNORE' : '%NS.prefixed;']}">\n);
358     }
359     $s .= qq(\n<!-- a URI reference -->\n<!ENTITY % URI.datatype "CDATA">\n);
360     $s .= qq(\n<!-- Placefolders for foreign namespace declarations -->\n);
361     for my $module_set (@src) {
362     $s .= qq(<!ENTITY % $module_set->{ID}.xmlns.extra.attrib "">\n);
363     }
364     $s .= qq(\n<!-- Namespace declarations -->\n);
365     for my $module_set (@src) {
366     $s .= qq(<![%$module_set->{ID}.module;[
367     <![%$module_set->{ID}.prefixed;[
368     <!ENTITY % $module_set->{ID}.xmlns.decl.attrib
369     "xmlns:%$module_set->{ID}.prefix; %URI.datatype; #FIXED '%$module_set->{ID}.xmlns;'">
370     ]]>
371     <!ENTITY % $module_set->{ID}.xmlns.decl.attrib
372     "xmlns %URI.datatype; #FIXED '%$module_set->{ID}.xmlns;'">
373     ]]>
374     <!ENTITY % $module_set->{ID}.xmlns.decl.attrib "">\n\n);
375     }
376 wakaba 1.4 $s .= <<EOH;
377     <!-- Declare a parameter entity %XSI.prefix as a prefix to use for
378     XML Schema Instance attributes. -->
379     <!ENTITY % XSI.prefix "xsi">
380    
381     <!ENTITY % XSI.pfx "%XSI.prefix;:">
382    
383     <!ENTITY % XSI.xmlns "http://www.w3.org/2001/XMLSchema-instance">
384    
385     <!-- Declare a parameter entity %XSI.xmlns.attrib as support for
386     the schemaLocation attribute. -->
387     <!ENTITY % XSI.xmlns.attrib
388     "xmlns:%XSI.prefix; %URI.datatype; #FIXED '%XSI.xmlns;'">
389     EOH
390 wakaba 1.1 $s .= qq(\n<!ENTITY % NS.decl.attrib
391     ").join ("\n\t", (map {qq(%$_->{ID}.xmlns.decl.attrib;)} @src),
392 wakaba 1.4 map {qq(%$_->{ID}.xmlns.extra.attrib;)} @src)
393     .qq(\n\t%XSI.xmlns.attrib;">\n);
394 wakaba 1.1 $s .= qq(\n);
395     for my $module_set (@src) {
396     $s .= qq(<!ENTITY % $module_set->{ID}.xmlns.attrib "%NS.decl.attrib;">\n);
397     }
398     $s .= qq(\n\n);
399     $s;
400     }
401    
402     sub dtd_driver_load_module ($$) {
403     my ($src, $Info) = @_;
404     my $module_name = name_of ($src, $Info, key => 'ID');
405     my $module_hyphen_name = name_of ($src, $Info, key => 'ID', delim => '-');
406     my $module_set_name = set_name_of ($src, $Info, key => 'ID');
407     my $module_id = local_name_of ($src, $Info, key => 'ID');
408    
409     my $s .= <<EOH;
410     @{[description ($src, $Info, context => 'load_module', id => $src->local_name)]}<![%$module_set_name.module;[
411 wakaba 1.2 <!ENTITY % $module_name.module "@{[$src->get_attribute_value ('Default') >= 0 ? 'INCLUDE' : 'IGNORE']}">
412 wakaba 1.1 <![%$module_name.module;[
413     @{[submodule_declarations ($src, $Info)]}<!ENTITY % $module_name.decl
414     @{[paralit external_id_of ($src, $Info, default => qq($module_hyphen_name.mod), base => qq(%$module_set_name.sysid.base;))]}>
415     <!ENTITY % $module_name.mod %$module_name.decl;>
416     %$module_name.mod;]]>
417     ]]>
418    
419     EOH
420     $s;
421     }
422 wakaba 1.2
423     sub dtd_driver_load_dtd ($$) {
424     my ($src, $Info) = @_;
425     my $module_set_name = $src->get_attribute_value ('ID');
426    
427     my $s .= <<EOH;
428     @{[description ($src, $Info)]}<![%$module_set_name.module;[
429     @{[submodule_declarations ($src, $Info)]}<!ENTITY % $module_set_name.dtd.sysid "@{[system_id_of ($src, $Info, default => $src->get_attribute_value ('ID').'.dtd', base => qq(%$module_set_name.sysid.base;))]}">
430     @{[do{
431     my $pubid = $src->get_attribute_value ('PUBLIC');
432     if ($pubid) {
433     qq(<!ENTITY % $module_set_name.dtd.fpi "$pubid">\n<!ENTITY % $module_set_name.dtd.fpi.defined "INCLUDE">\n);
434     } else {
435     qq(<!ENTITY % $module_set_name.dtd.fpi "">\n<!ENTITY % $module_set_name.dtd.fpi.defined "IGNORE">\n);
436     }
437     }]}
438     <![%$module_set_name.dtd.fpi.defined;[
439     <!ENTITY % $module_set_name.dtd.decl
440     'PUBLIC "%$module_set_name.dtd.fpi;"
441     "%$module_set_name.dtd.sysid;"'>
442     ]]>
443     <!ENTITY % $module_set_name.dtd.decl
444     'SYSTEM "%$module_set_name.dtd.sysid;"'>
445     <!ENTITY % $module_set_name.dtd %$module_set_name.dtd.decl;>
446     %$module_set_name.dtd;]]>
447    
448     EOH
449     $s;
450     }
451    
452 wakaba 1.1 sub model_module ($$) {
453     my ($src, $Info) = @_;
454     my $s = '';
455     for my $src (@{$src->child_nodes}) {
456     if ($src->local_name eq 'Class') {
457 wakaba 1.2 $s .= qq(@{[description ($src, $Info)]}<!ENTITY % @{[class_name_of ($src, $Info)]} @{[paralit convert_content_model ($src, $Info)]}>\n\n);
458 wakaba 1.1 } elsif ($src->local_name eq 'Content') {
459     $s .= element_content_def ($src, $Info);
460     }
461     }
462     make_module ($src, $Info, submodule_id_of ($src, $Info, default => 'model'), $s);
463     }
464    
465     sub datatype_module ($$) {
466     my ($src, $Info) = @_;
467     my $s = '';
468     for my $src (@{$src->child_nodes}) {
469     if ($src->local_name eq 'Type') {
470     $s .= qq(@{[get_desc ($src, $Info)]}<!ENTITY % @{[name_of ($src, $Info)]}.datatype "@{[xml_datatype_of ($src, $Info, default => 'CDATA')]}">\n\n);
471     }
472     }
473     make_module ($src, $Info, submodule_id_of ($src, $Info, default => 'datatype'), $s);
474     }
475    
476     sub notation_module ($$) {
477     my ($src, $Info) = @_;
478     my $s = '';
479     for my $src (@{$src->child_nodes}) {
480     if ($src->local_name eq 'Notation') {
481     $s .= qq(@{[get_desc ($src, $Info)]}<!NOTATION @{[name_of ($src, $Info)]} @{[external_id_of ($src, $Info)]}>\n\n);
482     }
483     }
484     make_module ($src, $Info, submodule_id_of ($src, $Info, default => 'notation'), $s);
485     }
486    
487     sub qname_module ($$) {
488     my ($src, $Info) = @_;
489     my $ID = $Info->{ID};
490     my $ns = $src->get_attribute ('Namespace');
491     my $s = <<EOH;
492 wakaba 1.5 <!ENTITY % sgml.tag.minimizable "IGNORE">
493    
494 wakaba 1.1 <!ENTITY % NS.prefixed "@{[$ns->get_attribute_value ('UsePrefix')==1?
495     q(INCLUDE):q(IGNORE)]}">
496 wakaba 1.2
497 wakaba 1.3 <!-- Section A: XML Namespace Framework :::::::::::::::::::::::::: -->
498    
499 wakaba 1.4 <!-- 1. Declare a %$ID.prefixed; conditional section keyword, used
500     to activate namespace prefixing. -->
501 wakaba 1.1 <!ENTITY % $ID.prefixed "@{[$ns->get_attribute_value ('UsePrefix')==1?
502     q(INCLUDE):
503     $ns->get_attribute_value ('UsePrefix')==-1?
504     q(IGNORE):
505     q(%NS.prefixed;)]}">
506 wakaba 1.2
507 wakaba 1.4 <!ENTITY % $ID.global.attrs.prefixed "@{[$ns->get_attribute_value ('UsePrefix')==1?
508     q(INCLUDE):
509     $ns->get_attribute_value ('UsePrefix')==-1?
510     q(IGNORE):
511     q(%NS.prefixed;)]}">
512    
513     <!ENTITY % $ID.xsi.attrs "INCLUDE">
514    
515     <!-- 2. Declare a parameter entity %$ID.xmlns; containing
516     the URI reference used to identity the namespace. -->
517 wakaba 1.1 <!ENTITY % $ID.xmlns "@{[$ns->get_attribute_value ('Name')]}">
518 wakaba 1.2
519 wakaba 1.4 <!-- 3. Declare parameter entity %$ID.prefix; containing
520     the default namespace prefix string to use when prefixing
521     is enabled. This may be overridden in the DTD driver or the
522     internal subset of a document instance.
523    
524     NOTE: As specified in XML Namespace speficications, the namespace
525     prefix serves as a proxy for the URI reference, and is not in itself
526     significant. -->
527 wakaba 1.1 <!ENTITY % $ID.prefix "@{[$ns->get_attribute_value ('DefaultPrefix')]}">
528 wakaba 1.2
529 wakaba 1.4 <!-- 4. Declare parameter entity %$ID.pfx; containing the
530     colonized prefix (e.g, '%$ID.prefix;:') used when
531     prefixing is active, an empty string when it is not. -->
532 wakaba 1.1 <![%$ID.prefixed;[
533     <!ENTITY % $ID.pfx "%$ID.prefix;:">
534     ]]>
535     <!ENTITY % $ID.pfx "">
536 wakaba 1.2
537 wakaba 1.4 <!-- declare qualified name extensions here ............ -->
538 wakaba 1.2 <!ENTITY % ${ID}-qname-extra.mod "">
539     %${ID}-qname-extra.mod;
540    
541 wakaba 1.4 <!-- 5. The parameter entity %$ID.xmlns.extra.attrib; may be
542     redeclared to contain any foreign namespace declaration
543     attributes for namespaces embedded. The default
544     is an empty string. -->
545 wakaba 1.1 <!ENTITY % $ID.xmlns.extra.attrib "">
546    
547 wakaba 1.4 <!-- The parameter entity %URI.datatype; should already be defined in
548     Datatype module. -->
549 wakaba 1.6 <!ENTITY % URI.datatype "CDATA">
550 wakaba 1.4
551 wakaba 1.1 <![%$ID.prefixed;[
552     <!ENTITY % $ID.xmlns.decl.attrib
553     "xmlns:%$ID.prefix; %URI.datatype; #FIXED '%$ID.xmlns;'">
554     ]]>
555     <!ENTITY % $ID.xmlns.decl.attrib
556     "xmlns %URI.datatype; #FIXED '%$ID.xmlns;'">
557    
558 wakaba 1.4 <!-- Declare a parameter entity %XSI.prefix as a prefix to use for
559     XML Schema Instance attributes. -->
560     <!ENTITY % XSI.prefix "xsi">
561    
562     <!ENTITY % XSI.pfx "%XSI.prefix;:">
563    
564     <!ENTITY % XSI.xmlns "http://www.w3.org/2001/XMLSchema-instance">
565    
566     <!-- Declare a parameter entity %XSI.xmlns.attrib as support for
567     the schemaLocation attribute. -->
568     <!ENTITY % XSI.xmlns.attrib
569     "xmlns:%XSI.prefix; %URI.datatype; #FIXED '%XSI.xmlns;'">
570    
571 wakaba 1.1 <![%$ID.prefixed;[
572     <!ENTITY % NS.decl.attrib
573     "%$ID.xmlns.decl.attrib;
574 wakaba 1.4 %$ID.xmlns.extra.attrib;
575     %XSI.xmlns.attrib;">
576 wakaba 1.1 ]]>
577     <!ENTITY % NS.decl.attrib
578 wakaba 1.4 "%$ID.xmlns.extra.attrib;
579     %XSI.xmlns.attrib;">
580 wakaba 1.1
581 wakaba 1.2 <!-- Declare a parameter entity containing all XML namespace declaration
582     attributes used, including a default xmlns declaration when prefixing
583     is inactive. -->
584 wakaba 1.1 <![%$ID.prefixed;[
585     <!ENTITY % $ID.xmlns.attrib
586     "%NS.decl.attrib;">
587     ]]>
588     <!ENTITY % $ID.xmlns.attrib
589     "%$ID.xmlns.decl.attrib;
590     %NS.decl.attrib;">
591    
592 wakaba 1.4 <!-- @{[dot_padding qq(Section B: $Info->{realname} Qualified Names ),
593     length => 71-9, dot => q(:)]} -->
594 wakaba 1.3
595     <!-- placeholder for qualified name redeclarations -->
596 wakaba 1.4 <!ENTITY % ${ID}-qname.redecl "">
597     %${ID}-qname.redecl;
598 wakaba 1.3
599 wakaba 1.4 <!-- 6. This section declare parameter entities used to provide
600     namespace-qualified names for all element types and global
601     attribute names. -->
602 wakaba 1.1 EOH
603 wakaba 1.3 for my $lname (sort keys %{$Info->{QName}}) {
604     $s .= qq(<!ENTITY % )
605     . (dot_padding qq($Info->{ID}.$lname.qname),
606     length => 15 + length ($Info->{ID}), dot => ' ')
607     . qq( "%$Info->{ID}.pfx;$lname">\n);
608 wakaba 1.1 }
609     $s .= qq(\n);
610 wakaba 1.3 for my $lname (sort keys %{$Info->{QNameA}}) {
611     $s .= qq(<!ENTITY % )
612     . (dot_padding qq($Info->{ID}.$lname.attrib.qname),
613     length => 15 + length ($Info->{ID}), dot => ' ')
614     . qq( "%$Info->{ID}.prefix;:$lname">\n);
615 wakaba 1.1 }
616     $s .= qq(\n);
617 wakaba 1.3 for my $lname (sort keys %{$Info->{QNameB}}) {
618     $s .= qq(<!ENTITY % )
619     . (dot_padding qq($Info->{ID}.$lname.attribute.qname),
620     length => 15 + length ($Info->{ID}), dot => ' ')
621     . qq( "%$Info->{ID}.pfx;$lname">\n);
622 wakaba 1.1 }
623 wakaba 1.3 make_module ($src->get_attribute ('QName', make_new_node => 1), $Info, 'qname', $s);
624 wakaba 1.1 }
625    
626     sub get_name ($$;$) {
627     my ($src, $Info, $key) = @_;
628     my $name = $src->get_attribute_value ($key || 'Name');
629     if ($name =~ /^:(.+)/) {
630     $name = $1;
631     } elsif ($name =~ /([^:]+):(.+)/) {
632     $name = qq($1.$2);
633     } else {
634     $name = qq($Info->{ID}.$name);
635     }
636     $name;
637     }
638    
639     sub get_qname ($$) {
640     my ($src, $Info) = @_;
641     my $name = $src->get_attribute_value ('Name');
642     if ($name =~ /"([^"]+)"/) {
643     $name = qq($1);
644     } elsif ($name =~ /^:(.+)/) {
645     $name = qq(%$1.qname;);
646     } elsif ($name =~ /([^:]+):(.+)/) {
647     $name = qq(%$1.$2.qname;);
648     } elsif ($name =~ /\{([^{}]+)\}/) {
649     $Info->{QNameB}->{$1} = 1;
650     $name = qq(%$Info->{ID}.$1.attribute.qname;);
651     } else {
652     $Info->{QNameA}->{$name} = 1;
653     $name = qq(%$Info->{ID}.$name.attrib.qname;);
654     }
655     $name;
656     }
657    
658     sub get_atype ($$) {
659     my ($src, $Info) = @_;
660     my $name = $src->get_attribute_value ('Type');
661     if ($name =~ /^:(.+)/) {
662     $name = qq(%$1.datatype;);
663     } elsif ($name =~ /([^:]+):(.+)/) {
664     $name = qq(%$1.$2.datatype;);
665     } elsif ($name =~ /"([^"]+)"/) {
666     $name = qq($1);
667     } else {
668     $name = qq(%$Info->{ID}.$name.datatype;);
669     }
670     $name;
671     }
672    
673     sub get_adefault ($$) {
674     my ($src, $Info) = @_;
675     my $name = $src->get_attribute_value ('Default');
676     if (defined $name) {
677     } else {
678     $name = qq(#IMPLIED);
679     }
680     $name;
681     }
682    
683 wakaba 1.3 sub get_desc ($$;%) {
684     my ($src, $Info, %opt) = @_;
685 wakaba 1.4 my $desc = $src->get_attribute_value ('Description');
686 wakaba 1.6 $desc =~ s/--/- - /g;
687 wakaba 1.4 $desc =~ s/\n/\n /g;
688 wakaba 1.3 if (length $desc) {
689     $desc = qq($opt{prefix}$desc);
690     $desc .= q( ) if $opt{padding_length};
691     $desc = q(<!-- ).(dot_padding $desc, length => $opt{padding_length},
692     dot => $opt{padding_dot}).qq( -->\n);
693 wakaba 1.4 } elsif (length $opt{default}) {
694     $desc = $opt{default};
695     $desc .= q( ) if $opt{padding_length};
696     $desc = q(<!-- ).(dot_padding $desc, length => $opt{padding_length},
697     dot => $opt{padding_dot}).qq( -->\n);
698 wakaba 1.3 }
699 wakaba 1.1 $desc;
700     }
701    
702     sub attset_def ($$) {
703     my ($src, $Info) = @_;
704     my $name = get_name ($src, $Info);
705     my $s .= qq(@{[get_desc ($src, $Info)]}<!ENTITY % $name.attrib\n\t);
706     my @s;
707     if ($name eq qq($Info->{ID}.common)) {
708     push @s, qq(%$Info->{ID}.common.extra.attrib;);
709     push @s, qq(%$Info->{ID}.xmlns.attrib;);
710     }
711     for my $src (@{$src->child_nodes}) {
712     ## Attribute Definition
713     if ($src->local_name eq 'Attribute') {
714     push @s, attrib_def ($src, $Info);
715     ## Reference to Attribute Definition
716     } elsif ($src->local_name eq 'ref') {
717     push @s, attrib_ref ($src, $Info);
718     } elsif ($src->local_name eq 'REF') {
719     push @s, attrib_REF ($src, $Info);
720     }
721     }
722     $s .= paralit join "\n\t", @s;
723     $s .= qq(>\n\n);
724     $s;
725     }
726    
727     sub attrib_module ($$) {
728     my ($src, $Info) = @_;
729     my $s = <<EOH;
730     <!ENTITY % $Info->{ID}.common.extra.attrib "">
731    
732     EOH
733     my $output_common = 0;
734     for my $src (@{$src->child_nodes}) {
735     ## Attributes Set
736     if ($src->local_name eq 'Attribute' or $src->local_name eq 'AttributeSet') {
737     $s .= attset_def ($src, $Info);
738     $output_common = 1 if get_name ($src, $Info) eq qq($Info->{ID}.common);
739     }
740     }
741     unless ($output_common) {
742     $s .= <<EOH;
743     <!ENTITY % $Info->{ID}.common.attrib
744     "%$Info->{ID}.common.extra.attrib;
745     %$Info->{ID}.xmlns.attrib;">
746    
747     EOH
748     }
749     make_module ($src, $Info, ($src->get_attribute_value ('ID') || 'attribs'), $s);
750     }
751    
752     sub attrib_def ($$) {
753     my ($src, $Info) = @_;
754     my $s = qq(@{[get_qname ($src, $Info)]} @{[get_atype ($src, $Info)]} @{[get_adefault ($src, $Info)]});
755     $s;
756     }
757    
758     sub attrib_ref ($$) {
759     my ($src, $Info) = @_;
760     my $name = $src->value;
761     if ($name =~ /^:(.+)/) {
762     $name = $1;
763     } elsif ($name =~ /([^:]+):(.+)/) {
764     $name = qq($1.$2);
765     } else {
766     $name = qq($Info->{ID}.$name);
767     }
768     qq(%$name.attrib;);
769     }
770    
771     sub attrib_REF ($$) {
772     my ($src, $Info) = @_;
773     {
774     'xml:base' => q<xml:base %URI.datatype; #IMPLIED>,
775     'xml:lang' => q<xml:lang %LanguageCode.datatype; #IMPLIED>,
776     'xml:space' => q<xml:space (default|preserve) #IMPLIED>,
777 wakaba 1.4 'xsi:nil' => q<%XSI.prefix;:nil (true|false|1|0) #IMPLIED>,
778     'xsi:noNamespaceSchemaLocation' => q<%XSI.prefix;:noNamespaceSchemaLocation CDATA #IMPLIED>,
779     'xsi:schemaLocation' => q<%XSI.prefix;:schemaLocation CDATA #IMPLIED>,
780     'xsi:type' => q<%XSI.prefix;:type NMTOKEN #IMPLIED>,
781 wakaba 1.1 }->{$src->value};
782     }
783    
784     sub submodule ($$) {
785     my ($src, $Info) = @_;
786 wakaba 1.3 local $Info->{elements} = [];
787 wakaba 1.1 my $s = submodule_declarations ($src, $Info);
788     make_module ($src, $Info, $src->get_attribute_value ('ID'), $s);
789     }
790    
791     sub submodule_declarations ($$) {
792     my ($src, $Info) = @_;
793     my $s = '';
794     for my $src (@{$src->child_nodes}) {
795     if ($src->local_name eq 'Element') {
796     $s .= element_def ($src, $Info);
797     } elsif ($src->local_name eq 'Attribute') {
798     $s .= attlist_def ($src, $Info);
799     } elsif ($src->local_name eq 'AttributeSet') {
800     $s .= attset_def ($src, $Info);
801 wakaba 1.2 } elsif ($src->local_name eq 'Class') {
802     $s .= qq(@{[description ($src, $Info)]}<!ENTITY % @{[class_name_of ($src, $Info)]} @{[paralit convert_content_model ($src, $Info)]}>\n\n);
803 wakaba 1.1 } elsif ($src->local_name eq 'Content') {
804     $s .= element_content_def ($src, $Info);
805     } elsif ($src->local_name eq 'IfModuleSet') {
806 wakaba 1.6 my $ms = name_of $src, $Info, key => $src->get_attribute_value ('ID') ?
807     'ID' : 'ModuleSet';
808     $s .= qq(<![%$ms.module;[\n);
809 wakaba 1.1 $s .= submodule_declarations ($src, $Info);
810 wakaba 1.6 $s .= qq(<!-- end of $ms -->]]>\n\n);
811    
812     } elsif ($src->local_name eq 'IfModule') {
813     my $ms = name_of $src, $Info, key => 'ID';
814     $s .= qq(<![%$ms.module;[\n);
815     $s .= submodule_declarations ($src, $Info);
816     $s .= qq(<!-- end of $ms -->]]>\n\n);
817 wakaba 1.1 } elsif ($src->local_name eq 'ElementSwitch') {
818     $s .= qq(<!ENTITY % @{[name_of ($src, $Info)]}.element "@{[$src->get_attribute_value ('Use')>0?'INCLUDE':'IGNORE']}">\n);
819     } elsif ($src->local_name eq 'AttributeSwitch') {
820     $s .= qq(<!ENTITY % @{[name_of ($src, $Info)]}.attlist "@{[$src->get_attribute_value ('Use')>0?'INCLUDE':'IGNORE']}">\n);
821 wakaba 1.2 } elsif ($src->local_name eq 'ModuleSwitch') {
822     $s .= qq(<!ENTITY % @{[name_of ($src, $Info)]}.module "@{[$src->get_attribute_value ('Use')>0?'INCLUDE':'IGNORE']}">\n);
823 wakaba 1.6 } elsif ($src->local_name eq 'Switch') {
824     $s .= qq(<!ENTITY % @{[name_of ($src, $Info)]} "@{[$src->get_attribute_value ('Use')>0?'INCLUDE':'IGNORE']}">\n);
825 wakaba 1.2 } elsif ($src->local_name eq 'GeneralEntity') {
826     $s .= entity_declaration ($src, $Info, param => 0);
827 wakaba 1.1 } elsif ($src->local_name eq 'ParameterEntity') {
828 wakaba 1.6 $s .= parameter_entity_declaration ($src, $Info);
829     } elsif ($src->local_name eq 'Module') {
830     $s .= dtd_driver_load_module ($src, $Info);
831     } elsif ($src->local_name eq 'DTD') {
832     $s .= dtd_driver_load_dtd ($src, $Info);
833 wakaba 1.1 }
834     }
835     $s;
836     }
837    
838     sub element_content_def ($$) {
839     my ($src, $Info) = @_;
840     qq(<!ENTITY % @{[name_of ($src, $Info, key => 'ElementType')]}.content @{[paralit convert_content_model ($src, $Info, default => 'EMPTY')]}>\n);
841     }
842    
843     sub element_def ($$) {
844     my ($src, $Info) = @_;
845     my $name = get_name ($src, $Info);
846     my $mname = $name =~ /^\Q$Info->{ID}.\E/ ? $name : qq($Info->{ID}.$name);
847 wakaba 1.3 my $short_name = $name;
848     if ($name =~ /^\Q$Info->{ID}\E\.(.+)/) {
849     $Info->{QName}->{$1} = 1;
850     push @{$Info->{elements}}, $1;
851     $short_name = $1;
852     }
853     my $s = get_desc $src, $Info, prefix => qq($short_name: ),
854 wakaba 1.4 padding_length => 51, padding_dot => q(.),
855     default => qq($short_name);
856 wakaba 1.3 $s .= "\n";
857     $s .= xml_parameter_ENTITY qq($mname.element), value => 'INCLUDE';
858 wakaba 1.5 my $cm = convert_content_model ($src, $Info, default => 'EMPTY');
859 wakaba 1.3 $s .= xml_condition_section (qq($mname.element) =>
860 wakaba 1.5 xml_parameter_ENTITY (qq($name.content), value => $cm)
861 wakaba 1.3 . xml_parameter_ENTITY (qq($name.qname), value => $short_name)
862 wakaba 1.5 . xml_parameter_ENTITY (qq($name.tagmin.start), value => q<->)
863     . xml_parameter_ENTITY (qq($name.tagmin.end), value => $cm eq 'EMPTY' ? q<o> : q<->)
864     . xml_condition_section (qq(sgml.tag.minimizable) =>
865     xml_parameter_ENTITY (qq($name.tagmin),
866     value => qq"%$name.tagmin.start; %$name.tagmin.end;"))
867     . xml_parameter_ENTITY (qq($name.tagmin), value => q"")
868     . qq(<!ELEMENT %$name.qname; %$name.tagmin; %$name.content;>\n));
869 wakaba 1.3 $s .= "\n";
870 wakaba 1.1 $s .= attlist_def (scalar $src->get_attribute ('Attribute', make_new_node => 1), $Info, $mname);
871     $s;
872     }
873    
874     sub get_model_token ($$) {
875     my ($name, $Info) = @_;
876     my $suffix = '.qname';
877     if ($name =~ s/^\$//) {
878     $suffix = $name =~ /\.(?:mix|class|content|datatype)$/ ? '' : '.class';
879     }
880     if ($name =~ /^:(.+)/) {
881     $name = qq(%$1$suffix;);
882     } elsif ($name =~ /([^:]+):(.+)/) {
883     $name = qq(%$1.$2$suffix;);
884     } elsif ($name =~ /"([^"]+)"/) {
885     $name = qq($1);
886     } else {
887     $name = qq(%$Info->{ID}.$name$suffix;);
888     }
889     $name;
890     }
891    
892     sub attlist_def ($$;$) {
893     my ($src, $Info, $name) = @_;
894     $name ||= get_name ($src, $Info, 'ElementType');
895     my $mname = get_name ($src, $Info);
896     $mname = ($name =~ /^\Q$Info->{ID}.\E/ ? $name : qq($Info->{ID}.$name))
897     if $mname eq "$Info->{ID}.";
898     $Info->{QName}->{$1} = 1 if $name =~ /^\Q$Info->{ID}\E\.(.+)/;
899 wakaba 1.3 my $s = qq(<!ATTLIST %$name.qname;);
900 wakaba 1.1 for my $src (@{$src->child_nodes}) {
901     ## Attribute Definition
902     if ($src->local_name eq 'Attribute') {
903     $s .= "\n\t". attrib_def ($src, $Info);
904     ## Reference to Attribute Definition
905     } elsif ($src->local_name eq 'ref') {
906     $s .= "\n\t". attrib_ref ($src, $Info);
907     } elsif ($src->local_name eq 'REF') {
908     $s .= "\n\t". attrib_REF ($src, $Info);
909     }
910     }
911     if ($_[2]) {
912     $s .= qq(\n\t%$Info->{ID}.common.attrib;);
913     }
914 wakaba 1.3 $s .= qq(>\n);
915     qq(@{[description ($src, $Info)]}<!ENTITY % $mname.attlist "INCLUDE">\n)
916     . xml_condition_section (qq($mname.attlist) => $s)
917     . "\n";
918 wakaba 1.1 }
919    
920 wakaba 1.3 sub make_module ($$$$;%) {
921     my ($src, $Info, $id, $s, %opt) = @_;
922 wakaba 1.1 my $name = $src->get_attribute_value ('Name')
923 wakaba 1.3 || {arch => q/Base Architecture/,
924     attribs => q/Common Attributes/,
925     blkphras => q/Block Phrasal/,
926     blkpres => q/Block Presentation/,
927     blkstruct => q/Block Structural/,
928     charent => q/Character Entities/,
929 wakaba 1.1 datatype => q/Datatypes/,
930 wakaba 1.3 framework => q/Modular Framework/,
931     inlphras => q/Inline Phrasal/,
932     inlpres => q/Inline Presentation/,
933     inlstruct => q/Inline Structural/,
934     legacy => q/Legacy Markup/,
935     list => q/Lists/,
936     meta => q/Metainformation/,
937 wakaba 1.1 model => q/Document Model/,
938 wakaba 1.3 notations => q/Notations/,
939     pres => q/Presentation/,
940     qname => q/QName (Qualified Name)/,
941     struct => q/Document Structure/,
942     text => q/Text/,
943 wakaba 1.1 }->{$id}
944     || $id;
945 wakaba 1.2 return unless $s;
946 wakaba 1.1
947     my $r = <<EOH;
948 wakaba 1.3 <!-- ...................................................................... -->
949     <!-- @{[do{
950     my $s = qq($Info->{Name} $name Module );
951     if (70 - length $s > 0) {
952     $s = dot_padding $s, length => 70, dot => q(.);
953     } else {
954     $s = qq( $name Module );
955     $s = qq($Info->{Name}\n ) . dot_padding $s, length => 70, dot => q(.);
956     }
957     $s;
958     }]} -->
959     <!-- file: $Info->{ID}-$id.mod
960 wakaba 1.1
961 wakaba 1.4 @{[make_paragraphs [$Info->{Description}], indent => q< >]}
962    
963 wakaba 1.3 Copyright @{[(gmtime)[5]+1900]} $Info->{Copyright}, All Rights Reserved.
964 wakaba 1.4
965     Permission to use, copy, modify and distribute this DTD and its
966     accompanying documentation for any purpose and without fee is hereby
967     granted in perpetuity, provided that the above copyright notice and
968     this paragraph appear in all copies. The copyright holders make no
969     representation about the suitability of the DTD for any purpose.
970    
971     It is provided "as is" without expressed or implied warranty.
972    
973 wakaba 1.1 Revision: @{[sprintf '%04d-%02d-%02dT%02d:%02d:%02d+00:00',
974 wakaba 1.3 (gmtime)[5]+1900, (gmtime)[4]+1, (gmtime)[3,2,1,0]
975     ]} (Generated by $SCRIPT_NAME/$VERSION)
976    
977     This DTD module is identified by the SYSTEM identifier:
978 wakaba 1.1
979 wakaba 1.3 SYSTEM "$Info->{BaseURI}$Info->{ID}-$id.mod"
980    
981     ...................................................................... -->
982    
983     EOH
984     ## TODO: Support PUBLIC identifier.
985 wakaba 1.1
986 wakaba 1.3 ## Module description
987     my @para = ({
988     arch => (join "\n",
989     q!This optional module includes declarations that enable to be used!,
990     q!as a base architecture according to the 'Architectural Forms Definition!,
991     q!Requirements' (Annex A.3, ISO/IEC 10744, 2nd edition). For more!,
992     q!information on use of architectural forms, see the HyTime web site at!,
993     q!<http://www.hytime.org/>.!),
994     attribs => q/This module declares many of the common attributes./,
995     blkphras => qq/This module declares the element types and their attributes used\n/.
996     q/to support block-level phrasal markup./,
997     blkpres => qq/This module declares the element types and their attributes used\n/.
998     q/to support block-level presentational markup./,
999     blkstruct => qq/This module declares the element types and their attributes used\n/.
1000     q/to support block-level structural markup./,
1001     charent => q/This module declares the set of character entities./,
1002     datatype => q/This module defines containers for the datatypes./,
1003     framework => qq/This module imstantiates the modules needed to support\n/.
1004     q/the modularization model./,
1005     inlphras => qq/This module declares the element types and their attributes used\n/.
1006     q/to support inline phrasal markup./,
1007     inlpres => qq/This module declares the element types and their attributes used\n/.
1008     q/to support inline presentational markup./,
1009     inlstruct => qq/This module declares the element types and their attributes used\n/.
1010     q/to support inline structural markup./,
1011     legacy => q/This module declares additional markup that is considered obsolete./,
1012     list => qq/This module declares the list-oriented element types\n/.
1013     q/and their attributes./,
1014     meta => qq/This module declares the element types and their attributes\n/.
1015     q/to support metainformation markup./,
1016     model => qq/This model describes the groupings of element types that\n/.
1017     q/make up common content models./,
1018     pres => qq/This module declares the element types and their attributes used\n/.
1019     q/to support presentational markup./,
1020     qname => (join "\n",
1021     q!This module is contained in two parts, labeled Section 'A' and 'B':!,
1022     q!!,
1023     q! Section A declares parameter entities to support namespace-qualified!,
1024     q! names, namespace declarations, and name prefixing.!,
1025     q!!,
1026     q! Section B declares parameter entities used to provide namespace-qualified!,
1027     q! names for all element types and global attribute names.!),
1028     struct => qq/This module defines the major structural element types and\n/.
1029     q/their attributes./,
1030     }->{$id}, $src->get_attribute_value ('Description'));
1031     unshift @para, ' '.join ', ', sort @{$Info->{elements}||[]} if @{$Info->{elements}||[]};
1032     if (@para) {
1033 wakaba 1.4 $name = qq($Info->{realname} QName (Qualified Name) Module)
1034     if $id eq 'qname';
1035 wakaba 1.3 $r .= <<EOH;
1036     <!-- $name
1037    
1038     @{[make_paragraphs \@para, indent => ' ']}
1039     -->
1040    
1041 wakaba 1.1 EOH
1042 wakaba 1.3 }
1043 wakaba 1.1
1044     $r .= $s;
1045    
1046     $r .= qq(\n<!-- end of $Info->{ID}-$id.mod -->\n);
1047    
1048     my $file = qq"$Info->{ID}-$id.mod";
1049     open FILE, '>', $file or die "$0: $file: $!";
1050     print FILE $r;
1051     close FILE;
1052     print STDERR "$0: $file created\n";
1053     }
1054    
1055     sub make_dtd ($$$$) {
1056     my ($src, $Info, $id, $s) = @_;
1057     $id = "-$id" if $id;
1058    
1059     my $r = <<EOH;
1060 wakaba 1.3 <!-- ....................................................................... -->
1061 wakaba 1.6 <!-- @{[do{
1062     my $s = qq($Info->{Name} DTD );
1063     if (70 - length $s > 0) {
1064     $s = dot_padding $s, length => 70, dot => q(.);
1065     } else {
1066     $s = qq( $Info->{Version} DTD );
1067     $s = qq($Info->{realname}\n ) . dot_padding $s, length => 70, dot => q(.);
1068     }
1069     $s;
1070     }]} -->
1071 wakaba 1.3 <!-- file: $Info->{ID}.dtd
1072     -->
1073    
1074     <!-- $Info->{Name} DTD
1075    
1076 wakaba 1.4 @{[make_paragraphs [$Info->{Description}], indent => q< >]}
1077 wakaba 1.3
1078     Copyright @{[(gmtime)[5]+1900]} $Info->{Copyright}, All Rights Reserved.
1079    
1080     Permission to use, copy, modify and distribute this DTD and its
1081     accompanying documentation for any purpose and without fee is hereby
1082     granted in perpetuity, provided that the above copyright notice and
1083     this paragraph appear in all copies. The copyright holders make no
1084     representation about the suitability of the DTD for any purpose.
1085    
1086     It is provided "as is" without expressed or implied warranty.
1087    
1088     Revision: @{[sprintf '%04d-%02d-%02dT%02d:%02d:%02d+00:00',
1089     (gmtime)[5]+1900, (gmtime)[4]+1, (gmtime)[3,2,1,0]]}
1090    
1091     -->
1092     <!-- This is the driver file for the $Info->{Name} DTD.
1093    
1094     This DTD is identified by the SYSTEM identifier:
1095    
1096 wakaba 1.1 SYSTEM "$Info->{BaseURI}$Info->{ID}$id.dtd"
1097 wakaba 1.3 -->
1098    
1099 wakaba 1.1 EOH
1100    
1101     $r .= $s;
1102    
1103     $r .= qq(\n<!-- end of $Info->{ID}$id.dtd -->\n);
1104    
1105     my $file = qq"$Info->{ID}$id.dtd";
1106     open FILE, '>', $file or die "$0: $file: $!";
1107     print FILE $r;
1108     close FILE;
1109     print STDERR "$0: $file created\n";
1110     }
1111    
1112    
1113     =head1 NAME
1114    
1115 wakaba 1.3 mkdtds.pl - Modularized XML Document Type Definition (DTD) Generator
1116 wakaba 1.1
1117     =head1 DESCRIPTION
1118    
1119 wakaba 1.3 This script generates XML DTD module implementations and/or DTD drivers,
1120     that can be used with modularized XHTML DTDs.
1121 wakaba 1.1
1122     =head1 USAGE
1123    
1124     $ perl mkdtds.pl driver.dds
1125     mkdtds.pl: driver.dtd created
1126     mkdtds.pl: driver-model.mod created
1127    
1128     $ perl mkdtds.pl moduleset.dms
1129     mkdtds.pl: moduleset-datatype.mod created
1130     mkdtds.pl: moduleset-attrib.mod created
1131     mkdtds.pl: moduleset-module1.mod created
1132    
1133     =head1 DTD SOURCE FORMAT
1134    
1135     (((See examples on <http://suika.fam.cx/gate/cvs/markup/>)))
1136    
1137 wakaba 1.3 =head1 REQUIRED MODULES
1138 wakaba 1.1
1139 wakaba 1.3 This script uses C<Message::Markup::SuikaWikiConfig20::Node> and
1140     C<Message::Markup::SuikaWikiConfig20::Parser>. Please retrive it from
1141     <http://suika.fam.cx/gate/cvs/messaging/manakai/lib/Message/Markup/SuikaWikiConfig20/>
1142     and put into your C<lib> directory.
1143 wakaba 1.1
1144     =head1 AUTHOR
1145    
1146     Wakaba <w@suika.fam.cx>
1147    
1148     =head1 LICENSE
1149    
1150 wakaba 1.3 Copyright 2003-2004 Wakaba <w@suika.fam.cx>
1151 wakaba 1.1
1152     This program is free software; you can redistribute it and/or
1153     modify it under the same terms as Perl itself.
1154    
1155 wakaba 1.3 Note that author claims no copyright with regard to DTD modules/drivers generated
1156     by this script. Author(s) of DTD modules/drivers should explicily state their
1157     license terms in them and their documentation (if any).
1158 wakaba 1.1
1159     =cut

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24