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

Contents of /markup/tool/mkdtds.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.1 - (show annotations) (download)
Fri Oct 24 11:21:28 2003 UTC (20 years, 6 months ago) by wakaba
Branch: MAIN
File MIME type: text/plain
New

1 use strict;
2 {require SuikaWiki::Markup::SuikaWikiConfig20::Parser;
3
4 my $parser = new SuikaWiki::Markup::SuikaWikiConfig20::Parser;
5 local $/ = undef;
6 my $src = $parser->parse_text (scalar <>);
7 my $Info = {};
8
9 for my $src ($src->get_attribute ('ModuleSet')
10 || $src->get_attribute ('DocumentType')) {
11 for (qw/ID Copyright BaseURI/) {
12 $Info->{$_} = $src->get_attribute_value ($_);
13 }
14 $Info->{Name} = $src->get_attribute_value ('Name')
15 .' '.$src->get_attribute_value ('Version');
16 $Info->{ns} = $src->get_attribute ('Namespace');
17 }
18
19 for (@{$src->child_nodes}) {
20 if ($_->local_name eq 'Attribute') {
21 attrib_module ($_, $Info);
22 } elsif ($_->local_name eq 'Datatype') {
23 datatype_module ($_, $Info);
24 } elsif ($_->local_name eq 'Notation') {
25 notation_module ($_, $Info);
26 } elsif ($_->local_name eq 'Module') {
27 submodule ($_, $Info);
28 } elsif ($_->local_name eq 'Model') {
29 model_module ($_, $Info);
30 } elsif ($_->local_name eq 'Driver') {
31 dtd_driver ($_, $Info);
32 }
33 }
34
35 if (ref $src->get_attribute ('ModuleSet')) {
36 qname_module ($src->get_attribute ('ModuleSet'), $Info);
37 }
38 exit}
39
40 sub submodule_id_of ($$;%) {
41 my ($src, $Info, %opt) = @_;
42 my $id = $src->get_attribute_value ('ID') || $opt{default};
43 unless ($id) {
44 die "$0: Submodule identifier not specified";
45 }
46 $id;
47 }
48 sub xml_datatype_of ($$;%) {
49 my ($src, $Info, %opt) = @_;
50 my $type = $src->get_attribute_value ('XMLType') || $opt{default};
51 $type =~ s/\s+//g;
52 $type;
53 }
54 sub external_id_of ($$;%) {
55 my ($src, $Info, %opt) = @_;
56 my $sysid = $opt{base}.($src->get_attribute_value ('SYSTEM') || $opt{default});
57 my $pubid = $src->get_attribute_value ('PUBLIC');
58 if ($pubid) {
59 if ($sysid) {
60 return qq(PUBLIC "$pubid"\n\t "$sysid");
61 } else {
62 return qq(PUBLIC "$pubid");
63 }
64 } else {
65 return qq(SYSTEM "$sysid");
66 }
67 }
68 sub name_of ($$;%) {
69 my ($src, $Info, %opt) = @_;
70 unless (ref $src) {require Carp; Carp::croak ('$src undefined')}
71 my $name = $src->get_attribute_value ($opt{key} || 'Name');
72 if ($name =~ /^:(.+)/) { ## Global namespace
73 return $1;
74 } elsif ($name =~ /([^:]+):(.+)/) { ## Named space
75 return $1.($opt{delim}||'.').$2;
76 } else { ## Default namespace
77 return $Info->{ID}.($opt{delim}||'.').$name;
78 }
79 }
80 sub local_name_of ($$;%) {
81 my ($src, $Info, %opt) = @_;
82 my $name = $src->get_attribute_value ($opt{key} || 'Name');
83 if ($name =~ /^:(.+)/) { ## Global namespace
84 return $1;
85 } elsif ($name =~ /[^:]+:(.+)/) { ## Named space
86 return $1;
87 } else { ## Default namespace
88 return $name;
89 }
90 }
91 sub set_name_of ($$;%) {
92 my ($src, $Info, %opt) = @_;
93 my $name = $src->get_attribute_value ($opt{key} || 'Name');
94 if ($name =~ /^:.+/) { ## Global namespace
95 return 'XHTML';
96 } elsif ($name =~ /([^:]+):.+/) { ## Named space
97 return $1;
98 } else { ## Default namespace
99 return $Info->{ID};
100 }
101 }
102 sub class_name_of ($$;%) {
103 my ($src, $Info, %opt) = @_;
104 my $name = name_of ($src, $Info, %opt);
105 unless ($name =~ /\.(class|mix|content|datatype)$/) {
106 $name .= '.class';
107 }
108 $name;
109 }
110 sub convert_content_model ($$;%) {
111 my ($src, $Info, %opt) = @_;
112 my $model = $src->get_attribute_value ($opt{key} || 'Content') || $opt{default};
113 $model =~ s/\s//g;
114 my $nonsymbol = qr/[^%#?,\$;()+*|:]/;
115 $model =~ s/(?<![%#.])((?:\$|\b)$nonsymbol+(?::$nonsymbol+)?|\$?:$nonsymbol+|"[^"]+")/get_model_token ($1, $Info)/ge;
116 $model;
117 }
118 sub paralit ($) {
119 my $s = shift;
120 if ($s =~ /"/) {
121 if ($s =~ /'/) {
122 $s =~ s/'/&#x27;/g;
123 return qq("$s");
124 } else {
125 return qq('$s');
126 }
127 } else {
128 return qq("$s");
129 }
130 }
131 sub description ($$;%) {
132 my ($src, $Info, %opt) = @_;
133 my $desc = $src->get_attribute_value ('Description');
134 $desc =~ s/\n/\n /g;
135 unless ($desc) {
136 $desc = {
137 load_module => {
138 AttributeModule => q/Common Attributes Module/,
139 DatatypeModule => q/Datatypes Module/,
140 NotationModule => q/Notation Module/,
141 QNameModule => q/QName Module/,
142 },
143 }->{$opt{context}}->{$opt{id} || $src->get_attribute_value ($opt{id_key}||'ID')};
144 }
145 $desc = qq(<!-- $desc -->\n) if $desc;
146 $desc;
147 }
148
149
150 sub dtd_driver ($$) {
151 my ($src, $Info) = @_;
152 my $s = '';
153 my %s;
154 my @module_set;
155 for my $src (@{$src->child_nodes}) {
156 if ($src->local_name eq 'Module') {
157 $s .= dtd_driver_load_module ($src, $Info);
158 } elsif ($src->local_name eq 'ModuleSet') {
159 push @module_set, $src;
160 } elsif ($src->local_name =~ /^(?:QName|Attribute|Datatype|Notation)Module/) {
161 $s{$src->local_name} .= dtd_driver_load_module ($src, $Info);
162 } elsif ($src->local_name eq 'IfModuleSet') {
163 $s .= qq(<![%@{[$src->get_attribute_value ('ModuleSet')]}.module;[\n);
164 $s .= submodule_declarations ($src, $Info);
165 $s .= qq(]]>\n);
166 } elsif ($src->local_name eq 'GeneralEntity') {
167 $s .= qq(@{[description ($src, $Info)]}<!ENTITY @{[$src->get_attribute_value ('Name')]} @{[paralit $src->get_attribute_value ('EntityValue')]}>\n\n);
168 } elsif ($src->local_name eq 'ParameterEntity') {
169 $s .= qq(@{[description ($src, $Info)]}<!ENTITY % @{[$src->get_attribute_value ('Name')]} @{[paralit $src->get_attribute_value ('EntityValue')]}>\n\n);
170 }
171 }
172
173 $s{ModelModule} = <<EOH;
174 <!-- Document Model module -->
175 <!ENTITY % $Info->{ID}-model.module "INCLUDE">
176 <![%$Info->{ID}-model.module;[
177 <!ENTITY % $Info->{ID}-model.decl
178 'SYSTEM "$Info->{ID}-model.mod"'>
179 <!ENTITY % $Info->{ID}-model.mod %$Info->{ID}-model.decl;>
180 %$Info->{ID}-model.mod;]]>
181
182 EOH
183
184 $s = dtd_driver_module_sets (\@module_set, $Info)
185 . $s{QNameModule}.$s{DatatypeModule}.$s{NotationModule}.$s{AttributeModule}
186 . $s{ModelModule}
187 .$s;
188 make_dtd ($src, $Info, $src->get_attribute_value ('ID'), $s);
189 }
190
191 sub dtd_driver_module_sets ($$) {
192 my ($srces, $Info) = @_;
193 my @src = map {{src => $_}} @$srces;
194 my $s = qq(<!-- Switchers to include/ignore each vocabulary -->\n);
195 for my $module_set (@src) {
196 $module_set->{ID} = $module_set->{src}->get_attribute_value ('ID') || 'XHTML';
197 $s .= qq(<!ENTITY % $module_set->{ID}.module "@{[$module_set->{src}->get_attribute_value ('Default') > 0 ? 'INCLUDE' : 'IGNORE']}">\n);
198 }
199 $s .= qq(\n<!-- Namespace names -->\n);
200 for my $module_set (@src) {
201 $module_set->{ns} = $module_set->{src}->get_attribute ('Namespace');
202 $s .= qq(<!ENTITY % $module_set->{ID}.xmlns "@{[$module_set->{ns}->get_attribute_value ('Name')]}">\n);
203 }
204 $s .= qq(\n<!-- Base URIs for the relavant DTD modules -->\n);
205 for my $module_set (@src) {
206 $s .= qq(<!ENTITY % $module_set->{ID}.sysid.base "@{[$module_set->{src}->get_attribute_value ('BaseURI')]}">\n);
207 }
208 $s .= qq(\n<!-- Namespace prefix -->\n);
209 $s .= qq(<!ENTITY % NS.prefixed "@{[$Info->{ns}->get_attribute_value ('UsePrefix') > 0 ? 'INCLUDE' : 'IGNORE']}">\n);
210 for my $module_set (@src) {
211 $s .= qq(<!ENTITY % $module_set->{ID}.prefix "@{[$module_set->{ns}->get_attribute_value ('DefaultPrefix')]}">\n);
212 $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);
213 }
214 $s .= qq(\n<!-- a URI reference -->\n<!ENTITY % URI.datatype "CDATA">\n);
215 $s .= qq(\n<!-- Placefolders for foreign namespace declarations -->\n);
216 for my $module_set (@src) {
217 $s .= qq(<!ENTITY % $module_set->{ID}.xmlns.extra.attrib "">\n);
218 }
219 $s .= qq(\n<!-- Namespace declarations -->\n);
220 for my $module_set (@src) {
221 $s .= qq(<![%$module_set->{ID}.module;[
222 <![%$module_set->{ID}.prefixed;[
223 <!ENTITY % $module_set->{ID}.xmlns.decl.attrib
224 "xmlns:%$module_set->{ID}.prefix; %URI.datatype; #FIXED '%$module_set->{ID}.xmlns;'">
225 ]]>
226 <!ENTITY % $module_set->{ID}.xmlns.decl.attrib
227 "xmlns %URI.datatype; #FIXED '%$module_set->{ID}.xmlns;'">
228 ]]>
229 <!ENTITY % $module_set->{ID}.xmlns.decl.attrib "">\n\n);
230 }
231 $s .= qq(\n<!ENTITY % NS.decl.attrib
232 ").join ("\n\t", (map {qq(%$_->{ID}.xmlns.decl.attrib;)} @src),
233 map {qq(%$_->{ID}.xmlns.extra.attrib;)} @src).qq(">\n);
234 $s .= qq(\n);
235 for my $module_set (@src) {
236 $s .= qq(<!ENTITY % $module_set->{ID}.xmlns.attrib "%NS.decl.attrib;">\n);
237 }
238 $s .= qq(\n\n);
239 $s;
240 }
241
242 sub dtd_driver_load_module ($$) {
243 my ($src, $Info) = @_;
244 my $module_name = name_of ($src, $Info, key => 'ID');
245 my $module_hyphen_name = name_of ($src, $Info, key => 'ID', delim => '-');
246 my $module_set_name = set_name_of ($src, $Info, key => 'ID');
247 my $module_id = local_name_of ($src, $Info, key => 'ID');
248
249 my $s .= <<EOH;
250 @{[description ($src, $Info, context => 'load_module', id => $src->local_name)]}<![%$module_set_name.module;[
251 <!ENTITY % $module_name.module "INCLUDE">
252 <![%$module_name.module;[
253 @{[submodule_declarations ($src, $Info)]}<!ENTITY % $module_name.decl
254 @{[paralit external_id_of ($src, $Info, default => qq($module_hyphen_name.mod), base => qq(%$module_set_name.sysid.base;))]}>
255 <!ENTITY % $module_name.mod %$module_name.decl;>
256 %$module_name.mod;]]>
257 ]]>
258
259 EOH
260 $s;
261 }
262 sub model_module ($$) {
263 my ($src, $Info) = @_;
264 my $s = '';
265 for my $src (@{$src->child_nodes}) {
266 if ($src->local_name eq 'Class') {
267 $s .= qq(@{[get_desc ($src, $Info)]}<!ENTITY % @{[class_name_of ($src, $Info)]} @{[paralit convert_content_model ($src, $Info)]}>\n\n);
268 } elsif ($src->local_name eq 'Content') {
269 $s .= element_content_def ($src, $Info);
270 }
271 }
272 make_module ($src, $Info, submodule_id_of ($src, $Info, default => 'model'), $s);
273 }
274
275 sub datatype_module ($$) {
276 my ($src, $Info) = @_;
277 my $s = '';
278 for my $src (@{$src->child_nodes}) {
279 if ($src->local_name eq 'Type') {
280 $s .= qq(@{[get_desc ($src, $Info)]}<!ENTITY % @{[name_of ($src, $Info)]}.datatype "@{[xml_datatype_of ($src, $Info, default => 'CDATA')]}">\n\n);
281 }
282 }
283 make_module ($src, $Info, submodule_id_of ($src, $Info, default => 'datatype'), $s);
284 }
285
286 sub notation_module ($$) {
287 my ($src, $Info) = @_;
288 my $s = '';
289 for my $src (@{$src->child_nodes}) {
290 if ($src->local_name eq 'Notation') {
291 $s .= qq(@{[get_desc ($src, $Info)]}<!NOTATION @{[name_of ($src, $Info)]} @{[external_id_of ($src, $Info)]}>\n\n);
292 }
293 }
294 make_module ($src, $Info, submodule_id_of ($src, $Info, default => 'notation'), $s);
295 }
296
297 sub qname_module ($$) {
298 my ($src, $Info) = @_;
299 my $ID = $Info->{ID};
300 my $ns = $src->get_attribute ('Namespace');
301 my $s = <<EOH;
302 <!ENTITY % NS.prefixed "@{[$ns->get_attribute_value ('UsePrefix')==1?
303 q(INCLUDE):q(IGNORE)]}">
304 <!ENTITY % $ID.prefixed "@{[$ns->get_attribute_value ('UsePrefix')==1?
305 q(INCLUDE):
306 $ns->get_attribute_value ('UsePrefix')==-1?
307 q(IGNORE):
308 q(%NS.prefixed;)]}">
309 <!ENTITY % $ID.xmlns "@{[$ns->get_attribute_value ('Name')]}">
310 <!ENTITY % $ID.prefix "@{[$ns->get_attribute_value ('DefaultPrefix')]}">
311 <![%$ID.prefixed;[
312 <!ENTITY % $ID.pfx "%$ID.prefix;:">
313 ]]>
314 <!ENTITY % $ID.pfx "">
315 <!ENTITY % $ID.xmlns.extra.attrib "">
316
317 <![%$ID.prefixed;[
318 <!ENTITY % $ID.xmlns.decl.attrib
319 "xmlns:%$ID.prefix; %URI.datatype; #FIXED '%$ID.xmlns;'">
320 ]]>
321 <!ENTITY % $ID.xmlns.decl.attrib
322 "xmlns %URI.datatype; #FIXED '%$ID.xmlns;'">
323
324 <![%$ID.prefixed;[
325 <!ENTITY % NS.decl.attrib
326 "%$ID.xmlns.decl.attrib;
327 %$ID.xmlns.extra.attrib;">
328 ]]>
329 <!ENTITY % NS.decl.attrib
330 "%$ID.xmlns.extra.attrib;">
331
332 <![%$ID.prefixed;[
333 <!ENTITY % $ID.xmlns.attrib
334 "%NS.decl.attrib;">
335 ]]>
336 <!ENTITY % $ID.xmlns.attrib
337 "%$ID.xmlns.decl.attrib;
338 %NS.decl.attrib;">
339
340 EOH
341 for my $lname (keys %{$Info->{QName}}) {
342 $s .= qq(<!ENTITY % $Info->{ID}.$lname.qname "%$Info->{ID}.pfx;$lname">\n);
343 }
344 $s .= qq(\n);
345 for my $lname (keys %{$Info->{QNameA}}) {
346 $s .= qq(<!ENTITY % $Info->{ID}.$lname.attrib.qname "%$Info->{ID}.prefix;:$lname">\n);
347 }
348 $s .= qq(\n);
349 for my $lname (keys %{$Info->{QNameB}}) {
350 $s .= qq(<!ENTITY % $Info->{ID}.$lname.attribute.qname "%$Info->{ID}.pfx;$lname">\n);
351 }
352 make_module ($src, $Info, 'qname', $s);
353 }
354
355 sub get_name ($$;$) {
356 my ($src, $Info, $key) = @_;
357 my $name = $src->get_attribute_value ($key || 'Name');
358 if ($name =~ /^:(.+)/) {
359 $name = $1;
360 } elsif ($name =~ /([^:]+):(.+)/) {
361 $name = qq($1.$2);
362 } else {
363 $name = qq($Info->{ID}.$name);
364 }
365 $name;
366 }
367
368 sub get_qname ($$) {
369 my ($src, $Info) = @_;
370 my $name = $src->get_attribute_value ('Name');
371 if ($name =~ /"([^"]+)"/) {
372 $name = qq($1);
373 } elsif ($name =~ /^:(.+)/) {
374 $name = qq(%$1.qname;);
375 } elsif ($name =~ /([^:]+):(.+)/) {
376 $name = qq(%$1.$2.qname;);
377 } elsif ($name =~ /\{([^{}]+)\}/) {
378 $Info->{QNameB}->{$1} = 1;
379 $name = qq(%$Info->{ID}.$1.attribute.qname;);
380 } else {
381 $Info->{QNameA}->{$name} = 1;
382 $name = qq(%$Info->{ID}.$name.attrib.qname;);
383 }
384 $name;
385 }
386
387 sub get_atype ($$) {
388 my ($src, $Info) = @_;
389 my $name = $src->get_attribute_value ('Type');
390 if ($name =~ /^:(.+)/) {
391 $name = qq(%$1.datatype;);
392 } elsif ($name =~ /([^:]+):(.+)/) {
393 $name = qq(%$1.$2.datatype;);
394 } elsif ($name =~ /"([^"]+)"/) {
395 $name = qq($1);
396 } else {
397 $name = qq(%$Info->{ID}.$name.datatype;);
398 }
399 $name;
400 }
401
402 sub get_adefault ($$) {
403 my ($src, $Info) = @_;
404 my $name = $src->get_attribute_value ('Default');
405 if (defined $name) {
406 } else {
407 $name = qq(#IMPLIED);
408 }
409 $name;
410 }
411
412 sub get_desc ($$) {
413 my ($src, $Info) = @_;
414 my $desc = $src->get_attribute_value ('Description');
415 $desc =~ s/\n/\n /g;
416 $desc = qq(<!-- $desc -->\n) if $desc;
417 $desc;
418 }
419
420 sub attset_def ($$) {
421 my ($src, $Info) = @_;
422 my $name = get_name ($src, $Info);
423 my $s .= qq(@{[get_desc ($src, $Info)]}<!ENTITY % $name.attrib\n\t);
424 my @s;
425 if ($name eq qq($Info->{ID}.common)) {
426 push @s, qq(%$Info->{ID}.common.extra.attrib;);
427 push @s, qq(%$Info->{ID}.xmlns.attrib;);
428 }
429 for my $src (@{$src->child_nodes}) {
430 ## Attribute Definition
431 if ($src->local_name eq 'Attribute') {
432 push @s, attrib_def ($src, $Info);
433 ## Reference to Attribute Definition
434 } elsif ($src->local_name eq 'ref') {
435 push @s, attrib_ref ($src, $Info);
436 } elsif ($src->local_name eq 'REF') {
437 push @s, attrib_REF ($src, $Info);
438 }
439 }
440 $s .= paralit join "\n\t", @s;
441 $s .= qq(>\n\n);
442 $s;
443 }
444
445 sub attrib_module ($$) {
446 my ($src, $Info) = @_;
447 my $s = <<EOH;
448 <!ENTITY % $Info->{ID}.common.extra.attrib "">
449
450 EOH
451 my $output_common = 0;
452 for my $src (@{$src->child_nodes}) {
453 ## Attributes Set
454 if ($src->local_name eq 'Attribute' or $src->local_name eq 'AttributeSet') {
455 $s .= attset_def ($src, $Info);
456 $output_common = 1 if get_name ($src, $Info) eq qq($Info->{ID}.common);
457 }
458 }
459 unless ($output_common) {
460 $s .= <<EOH;
461 <!ENTITY % $Info->{ID}.common.attrib
462 "%$Info->{ID}.common.extra.attrib;
463 %$Info->{ID}.xmlns.attrib;">
464
465 EOH
466 }
467 make_module ($src, $Info, ($src->get_attribute_value ('ID') || 'attribs'), $s);
468 }
469
470 sub attrib_def ($$) {
471 my ($src, $Info) = @_;
472 my $s = qq(@{[get_qname ($src, $Info)]} @{[get_atype ($src, $Info)]} @{[get_adefault ($src, $Info)]});
473 $s;
474 }
475
476 sub attrib_ref ($$) {
477 my ($src, $Info) = @_;
478 my $name = $src->value;
479 if ($name =~ /^:(.+)/) {
480 $name = $1;
481 } elsif ($name =~ /([^:]+):(.+)/) {
482 $name = qq($1.$2);
483 } else {
484 $name = qq($Info->{ID}.$name);
485 }
486 qq(%$name.attrib;);
487 }
488
489 sub attrib_REF ($$) {
490 my ($src, $Info) = @_;
491 {
492 'xml:base' => q<xml:base %URI.datatype; #IMPLIED>,
493 'xml:lang' => q<xml:lang %LanguageCode.datatype; #IMPLIED>,
494 'xml:space' => q<xml:space (default|preserve) #IMPLIED>,
495 }->{$src->value};
496 }
497
498 sub submodule ($$) {
499 my ($src, $Info) = @_;
500 my $s = submodule_declarations ($src, $Info);
501 make_module ($src, $Info, $src->get_attribute_value ('ID'), $s);
502 }
503
504 sub submodule_declarations ($$) {
505 my ($src, $Info) = @_;
506 my $s = '';
507 for my $src (@{$src->child_nodes}) {
508 if ($src->local_name eq 'Element') {
509 $s .= element_def ($src, $Info);
510 } elsif ($src->local_name eq 'Attribute') {
511 $s .= attlist_def ($src, $Info);
512 } elsif ($src->local_name eq 'AttributeSet') {
513 $s .= attset_def ($src, $Info);
514 } elsif ($src->local_name eq 'Content') {
515 $s .= element_content_def ($src, $Info);
516 } elsif ($src->local_name eq 'IfModuleSet') {
517 $s .= qq(<![%@{[$src->get_attribute_value ('ModuleSet')]}.module;[\n);
518 $s .= submodule_declarations ($src, $Info);
519 $s .= qq(]]>\n);
520 } elsif ($src->local_name eq 'ElementSwitch') {
521 $s .= qq(<!ENTITY % @{[name_of ($src, $Info)]}.element "@{[$src->get_attribute_value ('Use')>0?'INCLUDE':'IGNORE']}">\n);
522 } elsif ($src->local_name eq 'AttributeSwitch') {
523 $s .= qq(<!ENTITY % @{[name_of ($src, $Info)]}.attlist "@{[$src->get_attribute_value ('Use')>0?'INCLUDE':'IGNORE']}">\n);
524 } elsif ($src->local_name eq 'ParameterEntity') {
525 $s .= qq(@{[description ($src, $Info)]}<!ENTITY % @{[$src->get_attribute_value ('Name')]} @{[paralit $src->get_attribute_value ('EntityValue')]}>\n);
526 }
527 }
528 $s;
529 }
530
531 sub element_content_def ($$) {
532 my ($src, $Info) = @_;
533 qq(<!ENTITY % @{[name_of ($src, $Info, key => 'ElementType')]}.content @{[paralit convert_content_model ($src, $Info, default => 'EMPTY')]}>\n);
534 }
535
536 sub element_def ($$) {
537 my ($src, $Info) = @_;
538 my $name = get_name ($src, $Info);
539 my $mname = $name =~ /^\Q$Info->{ID}.\E/ ? $name : qq($Info->{ID}.$name);
540 $Info->{QName}->{$1} = 1 if $name =~ /^\Q$Info->{ID}\E\.(.+)/;
541 my $s = <<EOH;
542 @{[get_desc ($src, $Info)]}<!ENTITY % $mname.element "INCLUDE">
543 <![%$mname.element;[
544 <!ENTITY % $name.content @{[paralit convert_content_model ($src, $Info, default => 'EMPTY')]}>
545 <!ELEMENT %$name.qname; %$name.content;>
546 ]]>
547 EOH
548 $s .= attlist_def (scalar $src->get_attribute ('Attribute', make_new_node => 1), $Info, $mname);
549 $s;
550 }
551
552 sub get_model_token ($$) {
553 my ($name, $Info) = @_;
554 my $suffix = '.qname';
555 if ($name =~ s/^\$//) {
556 $suffix = $name =~ /\.(?:mix|class|content|datatype)$/ ? '' : '.class';
557 }
558 if ($name =~ /^:(.+)/) {
559 $name = qq(%$1$suffix;);
560 } elsif ($name =~ /([^:]+):(.+)/) {
561 $name = qq(%$1.$2$suffix;);
562 } elsif ($name =~ /"([^"]+)"/) {
563 $name = qq($1);
564 } else {
565 $name = qq(%$Info->{ID}.$name$suffix;);
566 }
567 $name;
568 }
569
570 sub attlist_def ($$;$) {
571 my ($src, $Info, $name) = @_;
572 $name ||= get_name ($src, $Info, 'ElementType');
573 my $mname = get_name ($src, $Info);
574 $mname = ($name =~ /^\Q$Info->{ID}.\E/ ? $name : qq($Info->{ID}.$name))
575 if $mname eq "$Info->{ID}.";
576 $Info->{QName}->{$1} = 1 if $name =~ /^\Q$Info->{ID}\E\.(.+)/;
577 my $s = qq(@{[description ($src, $Info)]}<!ENTITY % $mname.attlist "INCLUDE">
578 <![%$mname.attlist;[
579 <!ATTLIST %$name.qname;);
580 for my $src (@{$src->child_nodes}) {
581 ## Attribute Definition
582 if ($src->local_name eq 'Attribute') {
583 $s .= "\n\t". attrib_def ($src, $Info);
584 ## Reference to Attribute Definition
585 } elsif ($src->local_name eq 'ref') {
586 $s .= "\n\t". attrib_ref ($src, $Info);
587 } elsif ($src->local_name eq 'REF') {
588 $s .= "\n\t". attrib_REF ($src, $Info);
589 }
590 }
591 if ($_[2]) {
592 $s .= qq(\n\t%$Info->{ID}.common.attrib;);
593 }
594 $s .= qq(>
595 ]]>
596
597 );
598 $s;
599 }
600
601 sub make_module ($$$$) {
602 my ($src, $Info, $id, $s) = @_;
603 my $name = $src->get_attribute_value ('Name')
604 || {attribs => q/Common Attributes/,
605 datatype => q/Datatypes/,
606 model => q/Document Model/,
607 qname => q/QName/,
608 struct => q/Structual/,
609 }->{$id}
610 || $id;
611
612 my $r = <<EOH;
613 <!-- $Info->{Name} : $name Module
614
615 Copyright @{[(gmtime)[5]+1900]} $Info->{Copyright}
616 Revision: @{[sprintf '%04d-%02d-%02dT%02d:%02d:%02d+00:00',
617 (gmtime)[5]+1900, (gmtime)[4]+1, (gmtime)[3,2,1,0]]}
618
619 SYSTEM "$Info->{BaseURI}$Info->{ID}-$id.mod"
620 -->
621
622 EOH
623
624 $r .= $s;
625
626 $r .= qq(\n<!-- end of $Info->{ID}-$id.mod -->\n);
627
628 my $file = qq"$Info->{ID}-$id.mod";
629 open FILE, '>', $file or die "$0: $file: $!";
630 print FILE $r;
631 close FILE;
632 print STDERR "$0: $file created\n";
633 }
634
635 sub make_dtd ($$$$) {
636 my ($src, $Info, $id, $s) = @_;
637 $id = "-$id" if $id;
638
639 my $r = <<EOH;
640 <!-- $Info->{Name} : Document Type Definition
641
642 Copyright @{[(gmtime)[5]+1900]} $Info->{Copyright}
643 Revision: @{[sprintf '%04d-%02d-%02dT%02d:%02d:%02d+00:00',
644 (gmtime)[5]+1900, (gmtime)[4]+1, (gmtime)[3,2,1,0]]}
645
646 SYSTEM "$Info->{BaseURI}$Info->{ID}$id.dtd"
647 -->
648
649 EOH
650
651 $r .= $s;
652
653 $r .= qq(\n<!-- end of $Info->{ID}$id.dtd -->\n);
654
655 my $file = qq"$Info->{ID}$id.dtd";
656 open FILE, '>', $file or die "$0: $file: $!";
657 print FILE $r;
658 close FILE;
659 print STDERR "$0: $file created\n";
660 }
661
662
663 =head1 NAME
664
665 mkdtds.pl --- Moduralized XML Document Type Definition Generator
666
667 =head1 DESCRIPTION
668
669 This script can be used to generate XML DTD modules and driver
670 which is interoperable with XHTML DTD modules.
671
672 =head1 USAGE
673
674 $ perl mkdtds.pl driver.dds
675 mkdtds.pl: driver.dtd created
676 mkdtds.pl: driver-model.mod created
677
678 $ perl mkdtds.pl moduleset.dms
679 mkdtds.pl: moduleset-datatype.mod created
680 mkdtds.pl: moduleset-attrib.mod created
681 mkdtds.pl: moduleset-module1.mod created
682
683 =head1 DTD SOURCE FORMAT
684
685 (((See examples on <http://suika.fam.cx/gate/cvs/markup/>)))
686
687 =head1 REQUIRED MODULE
688
689 This script uses SuikaWiki::Markup::SuikaWikiConfig20 and
690 SuikaWiki::Markup::SuikaWikiConfig20::Parser.
691 Please get it from <http://suika.fam.cx/gate/cvs/suikawiki/script/lib/>
692 and put into your lib directory.
693
694 =head1 AUTHOR
695
696 Wakaba <w@suika.fam.cx>
697
698 =head1 LICENSE
699
700 Copyright 2003 Wakaba <w@suika.fam.cx>
701
702 This program is free software; you can redistribute it and/or
703 modify it under the same terms as Perl itself.
704
705 Note that author claims no right about DTD modules generated by this script.
706 Author(s) of DTD modules should be explicily state their license terms.
707
708 =cut

admin@suikawiki.org
ViewVC Help
Powered by ViewVC 1.1.24