File Coverage

web/cgi-bin/yatt.lib/YATT/LRXML/Parser.pm
Criterion Covered Total %
statement 307 317 96.8
branch 137 158 86.7
condition 38 45 84.4
subroutine 57 58 98.2
pod 0 48 0.0
total 539 626 86.1


line stmt bran cond sub pod time code
1             # -*- mode: perl; coding: utf-8 -*-
2             package YATT::LRXML::Parser;
3 7     7   15137 use strict;
  7         10  
  7         282  
4 7     7   24 use warnings FATAL => qw(all);
  7         12  
  7         281  
5 7     7   26 use base qw(YATT::Class::Configurable);
  7         11  
  7         1395  
6             use YATT::Fields
7 7         82 (qw(^tokens
8             cf_tree
9             metainfo
10             nsdict
11             nslist
12             re_splitter
13             re_ns
14             re_attlist
15             re_entity
16              
17             re_arg_decls
18              
19             elem_kids
20              
21             cf_special_entities
22              
23             cf_untaint
24             cf_debug
25             cf_registry
26             )
27             , [cf_html_tags => {input => 1, option => 0
28             , form => 0, textarea => 0, select => 0}]
29             , [cf_tokens => qw(comment declarator pi tag entity)]
30 7     7   769 );
  7         11  
31              
32 7     7   28 use YATT::Util;
  7         9  
  7         871  
33 7     7   31 use YATT::Util::Taint;
  7         8  
  7         535  
34 7     7   27 use YATT::Util::Symbol qw(fields_hash);
  7         8  
  7         230  
35 7     7   388 use YATT::LRXML::Node;
  7         8  
  7         1015  
36              
37 7     7   1187 use YATT::LRXML ();
  7         10  
  7         90  
38 7     7   1114 use YATT::LRXML::MetaInfo ();
  7         10  
  7         25850  
39              
40             sub MetaInfo () { 'YATT::LRXML::MetaInfo' }
41             sub Scanner () { 'YATT::LRXML::Scanner' }
42             sub Builder () { 'YATT::LRXML::Builder' }
43             sub Cursor () { 'YATT::LRXML::NodeCursor' }
44              
45             sub after_configure {
46 489     489 0 583 my MY $self = shift;
47 489         1270 $self->SUPER::after_configure;
48 489         1455 $$self{re_ns} = $self->re_ns(0);
49 489         1069 $$self{re_splitter} = $self->re_splitter(1, $$self{re_ns});
50 489         2239 $$self{re_attlist} = $self->re_attlist(2);
51 489         1272 $$self{re_arg_decls} = $self->re_arg_decls(1);
52             {
53 489         616 my %re_cached = map {$_ => 1} grep {/^re_/} keys %{fields_hash($self)};
  489         485  
  2445         3061  
  8313         9207  
  489         1414  
54 489         1335 my @token_pat = $self->re_tokens(2);
55 489         1172 while (@token_pat) {
56 2445         3079 my ($name, $pattern) = splice @token_pat, 0, 2;
57 2445         1936 push @{$self->{elem_kids}}, [$name, qr{^$pattern}];
  2445         79061  
58 2445 100       8564 next unless $re_cached{"re_$name"};
59 489         2780 $self->{"re_$name"} = $pattern;
60             }
61             }
62             }
63              
64             sub configure_namespace {
65 4     4 0 13 shift->metainfo->configure(namespace => shift);
66             }
67              
68             sub configure_metainfo {
69 489     489 0 562 (my MY $self) = shift;
70 489 50       1409 if (@_ == 1) {
    100          
71 0         0 $self->{metainfo} = shift;
72             } elsif (not $self->{metainfo}) {
73             # @_ == 0 || > 1
74 165         763 $self->{metainfo} = MetaInfo->new(@_);
75             } else {
76 324         825 $self->{metainfo}->configure(@_);
77             }
78 489         1317 $self->{metainfo}
79             }
80              
81             sub metainfo {
82 739     739 0 809 (my MY $self) = shift;
83 739   66     1947 $self->{metainfo} ||= $self->configure_metainfo;
84             }
85              
86             sub parse_handle {
87 156     156 0 378 (my MY $self, my ($fh)) = splice @_, 0, 2;
88 156         330 $self->configure_metainfo(@_);
89 156         305 $self->after_configure;
90 156 50       628 if (my $layer = $self->{metainfo}->cget('iolayer')) {
91 0         0 binmode $fh, $layer;
92             }
93 156         202 my $scan = $self->tokenize(do {
94 156         645 local $/;
95 156         3308 my $data = <$fh>;
96 156 50       872 $self->{cf_untaint} ? untaint_any($data) : $data;
97             });
98 156         513 $self->organize($scan);
99             }
100              
101             sub parse_string {
102 12     12 0 82 my MY $self = shift;
103 12         32 $self->configure_metainfo(splice @_, 1);
104 12         43 $self->after_configure;
105 12         35 my $scan = $self->tokenize($_[0]);
106 12         31 $self->organize($scan);
107             # $self->{cf_document}->set_tokens($self->{tokens});
108             # $self->{cf_document}->set_tree($tree);
109             }
110              
111             #========================================
112              
113             sub scanner {
114 170     170 0 297 (my MY $self) = @_;
115 170         1496 $self->Scanner->new(array => $self->{tokens}, index => 0
116             , linenum => 1
117             , metainfo => $self->{metainfo});
118             }
119              
120             sub tree {
121 166     166 0 226 my MY $self = shift;
122 166         662 my $cursor = $self->call_type(Cursor => new => $self->{cf_tree}
123             , metainfo => $self->{metainfo});
124             #$cursor->configure(path => $self->Cursor->Path->new($self->{cf_tree}));
125 166         798 $cursor;
126             }
127              
128             sub new_root_builder {
129 168     168 0 262 (my MY $self, my Scanner $scan) = @_;
130 168 100       476 if (my $reg = $self->{cf_registry}) {
131 156         606 $reg->new_root_builder($self, $scan);
132             } else {
133 12         58 require_and($self->Builder
134             , new => $self->{cf_tree} = $self->create_node('root')
135             , undef
136             , startpos => 0
137             , startline => $scan->{cf_linenum}
138             , linenum => $scan->{cf_linenum});
139             }
140             }
141              
142             sub organize {
143 168     168 0 249 (my MY $self, my Scanner $scan) = @_;
144 168         399 my $builder = $self->new_root_builder($scan);
145 168         643 while ($scan->readable) {
146 789         1561 my $text = $scan->read;
147 789 100       2177 $builder->add($scan, $text) if $text ne '';
148 789 100       1506 last unless $scan->readable;
149 635         1736 my ($toktype, @match) = $scan->expect($self->{elem_kids});
150 635 50       1286 unless (defined $toktype) {
151 0         0 $self->build_scanned($builder, $scan
152             , unknown => undef, $scan->read);
153 0         0 next;
154             }
155              
156 635 100       2231 if (my $sub = $self->can("build_$toktype")) {
157             # declarator も complex 扱いにした方が良いね。
158 633         1480 $builder = $sub->($self, $scan, $builder, \@match);
159             } else {
160             # easy case.
161 2         3 my ($ns, $body) = @match;
162 2         4 $self->build_scanned($builder, $scan
163             , $toktype => $ns, $body);
164             }
165             }
166 163 100 66     514 if ($builder->{cf_endtag} and $builder->{parent}) {
167 2         17 die "Missing close tag '$builder->{cf_endtag}'"
168             ." at line $builder->{cf_startline}"
169             .$scan->{cf_metainfo}->in_file." \n";
170             }
171            
172 161 50       269 if (wantarray) {
173 0         0 ($self->tree, $self->{metainfo});
174             } else {
175 161         440 $self->tree;
176             }
177             }
178              
179             sub build_scanned {
180 193     193 0 371 (my MY $self, my Builder $builder, my Scanner $scan) = splice @_, 0, 3;
181 193         566 my $node = $self->create_node(@_);
182 193         549 node_set_nlines($node, $scan->{cf_last_nol});
183 193         407 $builder->add($scan, $node);
184             }
185              
186             sub build_pi {
187 19     19 0 36 (my MY $self, my Scanner $scan, my Builder $builder, my ($match)) = @_;
188 19         72 $self->build_scanned($builder, $scan
189             , pi => $match->[0]
190             , $self->parse_entities($match->[1]));
191 19         70 $builder;
192             }
193              
194             sub build_entity {
195 172     172 0 328 (my MY $self, my Scanner $scan, my Builder $builder, my ($match)) = @_;
196 172         563 $self->build_scanned($builder, $scan
197             , entity => $self->parse_entpath($match->[0]));
198 172         540 $builder;
199             }
200              
201             sub build_tag {
202 255     255 0 458 (my MY $self, my Scanner $scan, my Builder $builder, my ($match)) = @_;
203 255         701 my ($close, $html, $ns, $tagname, $attlist, $is_ee) = @$match;
204 255   66     570 $tagname ||= $html;
205              
206 255 100       489 if ($close) {
207 64         216 $builder->verify_close($tagname, $scan);
208             # そうか、ここで attribute element からの脱出もせにゃならん。
209             # switched product 方式なら、parent は共通、かな?
210 63         215 return $builder->parent;
211             }
212              
213 191         202 my ($is_att, $nodetype, $qflag) = do {
214 191 100 100     873 if (defined $ns and $ns =~ s/^:(?=\w)//) {
215 21         108 (1, attribute => YATT::LRXML::Node->quoted_by_element($is_ee));
216             } else {
217 170         146 my $type = do {
218 170 100       299 if (defined $html) {
219 18         46 $is_ee = $self->{cf_html_tags}{lc($html)};
220 18         23 'html';
221             } else {
222 152         266 'element'
223             }
224             };
225 170 100       677 (0, $type => $is_ee ? EMPTY_ELEMENT : 0);
226             }
227             };
228              
229 191 100       1106 my $element = $self->create_node([$nodetype, $qflag]
230             , $html
231             ? $html
232             : [$ns, split /[:\.]/, $tagname]);
233 191         537 $self->parse_attlist($attlist, $element);
234              
235 191 100       420 unless ($is_ee) {
    100          
236             # ..., <:yatt:attr>...
237 67         215 $builder->add($scan, $element)->open($element, endtag => $tagname);
238             } elsif ($is_att) {
239             # <:yatt:attr />...
240 16         60 $builder->switch($element);
241             } else {
242             #
243 108         321 node_set_nlines($element, $scan->{cf_last_nol});
244 108         320 $builder->add($scan, $element);
245             }
246             }
247              
248             #========================================
249              
250             sub build_declarator {
251 187     187 0 341 (my MY $self, my Scanner $scan, my Builder $builder, my ($match)) = @_;
252 187         445 my ($ns, $tagname, $attlist) = @$match;
253              
254 187         687 my $element = $self->create_node(declarator =>
255             [$ns, $tagname]);
256 187         597 push @$element, $self->parse_arg_decls(\$attlist);
257 187         633 node_set_nlines($element, $scan->{cf_last_nol});
258 187 100       531 if (my $reg = $self->{cf_registry}) {
259 183         611 $reg->new_decl_builder($builder, $scan, $element, $self);
260             } else {
261 4         11 $builder->add($scan, $element);
262             }
263             }
264              
265             sub re_arg_decls {
266 491     491 0 1282 (my MY $self, my ($capture)) = @_;
267 491 50       920 die "re_arg_decls(capture=0) is not yet implemented!" unless $capture;
268 491         654 my ($SQ, $DQ) = ($self->re_sqv(2), $self->re_dqv(2));
269 491         1028 my $BARE = qr{([^=\-\'\"\s<>/\[\]%]+ | /(?!>))}x;
270 491         798 my $ENT = qr{%([\w\:\.]+(?:[\w:\.\-=\[\]\{\}\(,\)]+)?);}x;
271 491         3541 qr{^ \s* -- (.*?) -- # 1
272             |^ \s* $ENT # 2
273             |^ \s* (\]) # 3
274             |^ \s+
275             (?: (\w+)\s*=\s*)? # 4
276             (?: $SQ # 5
277             | $DQ # 6
278             | $BARE # 7
279             | (\[)(?:\s* (\w+(?:\:\w+)*)) # 8, 9
280             )
281             }xs;
282             # '[ word' を一括で取り出すのは、次に ^\s+ を残しておくため.
283             }
284              
285             sub re_decl_entity {
286 3     3 0 10 (my MY $self, my ($capture)) = @_;
287 3         6 qr{%([\w\:\.]+(?:[\w:\.\-=\[\]\{\}\(,\)]+)?);}x;
288             }
289              
290             sub parse_arg_decls {
291 207     207 0 291 (my MY $self, my ($strref)) = @_;
292 207         196 my @args;
293 207         1834 while ($$strref =~ s{$$self{re_arg_decls}}{}x) {
294 0 0       0 print STDERR "parse_arg_decls: ", join("|", map {
295 429 50       947 defined $_ ? $_ : "(null)"
296             } $&
297             , $1 # comment
298             , $2 # ENT
299             , $3 # ]
300             , $4 # name
301             , $5 # '..'
302             , $6 # ".."
303             , $7 # bare
304             , $8 # [
305             , $9 # leader
306             ), "\n" if $self->{cf_debug};
307 429 100       1509 if (defined $1) { # comment
    100          
    100          
308 3         9 push @args, $self->create_node(decl_comment => undef, $1);
309             } elsif (defined $2) { # ENT
310 52         192 push @args
311             , $self->create_node([entity => 1] => $self->parse_entpath($2));
312             } elsif (defined $3) { # ]
313 20         30 last;
314             } else {
315             # $4 # name
316             # $5 # '..'
317             # $6 # ".."
318             # $7 # bare
319             # $8 # ]
320 354 100       604 if (defined $8) { # [
321             # XXX: hard coded.
322 20         81 push @args, my $nest = $self->create_node([attribute => 3], $4, $9);
323 20         66 push @$nest, $self->parse_arg_decls($strref);
324             } else {
325             # XXX: dummy.
326 334         960 push @args, $self->create_attlist('', $4, '=', $5, $6, $7);
327             }
328             }
329             }
330 207 50       508 print STDERR "REST<$$strref>\n" if $self->{cf_debug};
331 207         449 @args;
332             }
333              
334             #========================================
335              
336             sub parse_attlist {
337 191     191 0 251 my MY $self = shift;
338 191         208 my $result = $_[1]; # Yes. this *is* intentional.
339             # XXX: タグ内改行がここでカウントされなくなる。
340 191 100 66     2018 if (defined $_[0] and my @match = $_[0] =~ m{$$self{re_attlist}}g) {
341 112         425 push @$result, $self->create_attlist(@match);
342             }
343 191         315 $result;
344             }
345              
346             sub parse_entities {
347 264     264 0 414 my MY $self = shift;
348             # XXX: 行番号情報を受け取れた方が、嬉しいのだが…
349 264 50       478 return undef unless defined $_[0]; # make sure single scalar is returned.
350 264 50       519 return '' if $_[0] eq '';
351 264 50       571 return $_[0] unless defined $$self{re_entity};
352 264         1586 my @tokens = split $$self{re_entity}, $_[0];
353 264 100       1004 return $tokens[0] if @tokens == 1;
354 58         81 my @result;
355 58         185 for (my $i = 0; $i < @tokens; $i += 2) {
356 91 100       196 push @result, $tokens[$i] if $tokens[$i] ne "";
357 91 100       298 push @result
358             , $self->create_node(entity => $self->parse_entpath($tokens[$i+1]))
359             if $i+1 < @tokens;
360             }
361 58 100       111 if (wantarray) {
    100          
362 52         187 @result;
363             } elsif (@result > 1) {
364 5         24 [TEXT_TYPE, undef, @result];
365             } else {
366 1         4 $result[0];
367             }
368             }
369              
370             sub parse_entpath {
371 291     291 0 451 (my MY $self, my ($entpath)) = @_;
372 291         282 my @name;
373 291         2590 push @name, $1 while $entpath =~ s{^[\.\:]?(\w+)(?=[\.\:]|$)}{};
374             # :func(), array[], hash{} is stored in node_body.
375             # In &SA(); case, node_name is undef.
376 291 100       1392 (@name ? \@name : undef
    100          
377             , $entpath eq "" ? () : $entpath);
378             }
379              
380             #========================================
381              
382             sub tokenize {
383 168     168 0 227 my MY $self = shift;
384 168         5142 $self->{tokens} = [split $$self{re_splitter}, $_[0]];
385 168 50       673 if (my MetaInfo $meta = $self->{metainfo}) {
386             # $meta->{tokens} = $self->{tokens};
387             }
388 168         549 $self->scanner;
389             }
390              
391             sub token_patterns {
392 1981     1981 0 1900 my ($self, $token_types, $capture, $ns) = @_;
393 1981         1753 my $wantarray = wantarray;
394 1981         1528 my @result;
395 1981         2188 foreach my $type (@$token_types) {
396 6920         7227 my $meth = "re_$type";
397 6920 100       13951 push @result
398             , $wantarray ? $type : ()
399             , $self->$meth($capture, $ns);
400             }
401 1981 100       4394 return @result if $wantarray;
402 1492         2648 my $pattern = join "\n | ", @result;
403 1492         120488 qr{$pattern}x;
404             }
405              
406             #----------------------------------------
407              
408             sub re_splitter {
409 494     494 0 1156 (my MY $self, my ($capture, $ns)) = @_;
410 494         834 my $body = $self->re_tokens(0, $ns);
411 494 100       46826 $capture ? qr{($body)} : $body;
412             }
413              
414             sub re_tokens {
415 986     986 0 1229 (my MY $self, my ($capture, $ns)) = @_;
416 986         1979 $self->token_patterns($self->{cf_tokens}, $capture, $ns);
417             }
418              
419             #
420             # re_tag(2) returns [ /, specialtag, ns, tag, attlist, / ]
421             #
422             sub re_tag {
423 995     995 0 1272 (my MY $self, my ($capture, $ns)) = @_;
424 995         2266 my $namepat = $self->token_patterns([qw(tagname_html tagname_qualified)]
425             , $capture, $ns);
426 995         2509 my $attlist = $self->re_attlist;
427 995 100 100     3181 if (defined $capture and $capture > 1) {
428 493         26588 qr{<(/)? (?: $namepat) ($attlist*) \s*(/)?>}xs;
429             } else {
430 502         26852 my $re = qr{}xs;
431 502 100       2110 $capture ? qr{($re)} : $re;
432             }
433             }
434              
435             #----------------------------------------
436              
437             sub re_name {
438 3     3 0 10 my ($self, $capture) = @_;
439 3         3 my $body = q{[\w\-\.]+};
440 3 100       31 $capture ? qr{($body)} : qr{$body};
441             }
442              
443             sub re_ns {
444 579     579 0 682 my ($self, $capture, $nslist, $additional) = @_;
445 579 50       861 die "re_ns capture is not yet implemented" if $capture;
446 579   33     1100 $nslist ||= $self->{nslist} = do {
447 579         1079 my $meta = $self->metainfo;
448 579         1312 $self->{nsdict} = $meta->nsdict;
449 579         1247 $meta->cget('namespace');
450             };
451 579 50       1102 unless (@$nslist) {
452 0         0 '';
453             } else {
454 579 50       1424 my $pattern = join "|", map {ref $_ ? @$_ : $_} @$nslist
  1053 50       1949  
    100          
455             , !$additional ? () : ref $additional ? @$additional : $additional;
456 579         1477 qq{(?:$pattern)};
457             }
458             }
459              
460             sub re_nsname {
461 3505     3505 0 2870 my ($self, $capture) = @_;
462 3505         2593 my $body = q{[\w\-\.:]+};
463 3505 100       9528 $capture ? qr{($body)} : qr{$body};
464             }
465              
466             sub re_tagname_qualified {
467 1989     1989 0 1858 my ($self, $capture, $ns) = @_;
468 1989 100       3358 $ns = $$self{re_ns} unless defined $ns;
469 1989         2519 my $name = $self->re_nsname;
470 1989 100 100     5932 if (defined $capture and $capture > 1) {
471 985         12367 qr{ ( :?$ns) : ($name) }xs;
472             } else {
473 1004         1731 my $re = qq{ :?$ns : $name };
474 1004 100       13927 $capture ? qr{($re)}xs : qr{$re}xs;
475             }
476             }
477              
478             sub re_tagname_html {
479 998     998 0 1179 (my MY $self, my ($capture, $ns)) = @_;
480 998         937 my $body = join "|", keys %{$self->{cf_html_tags}};
  998         2902  
481 998 100       4274 $capture ? qr{($body)}i : qr{$body}i;
482             }
483              
484             #----------------------------------------
485              
486             sub re_attlist {
487 1491     1491 0 2426 my ($self, $capture) = @_;
488 1491         1957 my $name = $self->re_nsname;
489 1491         2446 my $value = $self->re_attvalue($capture);
490 1491         3344 my $sp = q{\s+};
491 1491         1163 my $eq = q{\s* = \s*};
492 1491 100 100     4411 if (defined $capture and $capture > 1) {
493 494         3729 qr{($sp|\b) (?:($name) ($eq))? $value}xs;
494             } else {
495 997         4858 my $re = qr{(?:$sp|\b) (?:$name $eq)? $value}xs;
496 997 100       2926 $capture ? qr{($re)} : $re;
497             }
498             }
499              
500             sub re_attvalue {
501 1494     1494 0 1441 my ($self, $capture) = @_;
502 1494         2018 my ($SQ, $DQ, $NQ) =
503             ($self->re_sqv($capture),
504             $self->re_dqv($capture),
505             $self->re_bare($capture));
506 1494         37933 qr{$SQ | $DQ | $NQ}xs;
507             }
508              
509             sub re_sqv {
510 1988     1988 0 1524 my ($self, $capture) = @_;
511 1988         3125 my $body = qr{(?: [^\'\\]+ | \\.)*}x;
512 1988 100       4767 $body = qr{($body)} if $capture;
513 1988         19523 qr{\'$body\'}s;
514             }
515              
516             sub re_dqv {
517 1988     1988 0 1847 my ($self, $capture) = @_;
518 1988         2762 my $body = qr{(?: [^\"\\]+ | \\.)*}x;
519 1988 100       4609 $body = qr{($body)} if $capture;
520 1988         15399 qr{\"$body\"}s;
521             }
522              
523             sub re_bare;
524             *re_bare = \&re_bare_torelant;
525              
526             sub re_bare_strict {
527 3     3 0 11 shift->re_nsname(@_);
528             }
529              
530             sub re_bare_torelant {
531 1500     1500 0 1451 my ($self, $capture) = @_;
532 1500         2143 my $body = qr{[^\'\"\s<>/]+ | /(?!>)}x;
533 1500 100       5506 $capture ? qr{($body+)} : qr{$body+};
534             }
535              
536             sub strip_bs {
537 0     0 0 0 shift;
538 0         0 $_[0] =~ s/\\(\.)/$1/g;
539 0         0 $_[0];
540             }
541              
542             #----------------------------------------
543              
544             sub re_declarator {
545 991     991 0 986 my ($self, $capture, $ns) = @_;
546 991         1603 my $namepat = $self->re_tagname_qualified($capture, $ns);
547 991         1393 my $arg_decls = q{[^>]};
548             # $self->re_arg_decls(0);
549             # print "<<$arg_decls>>\n";
550 991 100 100     3024 if (defined $capture and $capture > 1) {
551 491         10343 qr{}xs;
552             } else {
553 500         10318 my $re = qr{}xs;
554 500 100       1706 $capture ? qr{($re)} : $re;
555             }
556             }
557              
558             sub re_comment {
559 991     991 0 935 my ($self, $capture, $ns) = @_;
560 991         1405 $ns = $self->re_prefix($capture, $ns, '#');
561 991 100       14863 $capture ? qr{}s : qr{}s;
562             }
563              
564             sub re_pi {
565 991     991 0 1168 my ($self, $capture, $ns) = @_;
566 991         1307 $ns = $self->re_prefix($capture, $ns);
567 991 100       2206 my $body = $capture ? qr{(.*?)}s : qr{.*?}s;
568 991         16321 qr{<\?\b$ns\b$body\?>}s;
569             }
570              
571             sub re_entity {
572 991     991 0 2180 shift->re_entity_pathexpr(@_);
573             }
574              
575             # normal entity
576             sub re_entity_strict {
577 3     3 0 8 my ($self, $capture, $ns) = @_;
578 3 50       8 $ns = defined $ns ? qq{$ns\:} : qr{\w+:};
579 3         5 my $body = $self->re_nsname;
580 3 100 100     11 if (defined $capture and $capture > 1) {
581 1         23 qr{&$ns($body);}xs;
582             } else {
583 2         22 my $re = qr{&$ns$body;}xs;
584 2 100       24 $capture ? qr{($re)} : $re;
585             }
586             }
587              
588             # extended (subscripted) entity.
589             sub re_entity_subscripted {
590 6     6 0 13 my ($self, $capture, $ns) = @_;
591 6 50       15 $ns = defined $ns ? qq{$ns\:} : qr{\w+:};
592 6         7 my $name = $self->re_nsname;
593 6         8 my $sub = $self->re_subscript;
594 6         12 my $body = qq{$name$sub*};
595 6 100 100     19 if (defined $capture and $capture > 1) {
596 1         50 qr{&($ns)($body);}xs;
597             } else {
598 5         67 my $re = qr{&$ns$body;}xs;
599 5 100       77 $capture ? qr{($re)} : $re;
600             }
601             }
602              
603             # This cannot handle matching paren, of course;-).
604             sub re_subscript {
605 10     10 0 22 my $name = shift->re_nsname;
606 10         78 qr{[\[\(\{]
607             [\w\.\-\+\$\[\]\{\}]*?
608             [\}\)\]]
609             |\. $name
610             |\: [/\$\.\-\w]+
611             }xs;
612             }
613              
614             # more extended
615             sub re_entity_pathexpr {
616 994     994 0 1255 my ($self, $capture, $ns) = @_;
617 994         1480 $ns = $self->re_prefix(0, $self->entity_ns($ns), '');
618 994         1885 my $body = qr{[\w\$\-\+\*/%<>\.=\@\|!:\[\]\{\}\(,\)]*};
619 994 100 100     2663 if (defined $capture and $capture > 1) {
620 492         11713 qr{&($ns\b$body);}xs;
621             } else {
622 502         12432 my $re = qr{&$ns\b$body;}xs;
623 502 100       1875 $capture ? qr{($re)} : $re;
624             }
625             }
626              
627             sub entity_ns {
628 994     994 0 848 my ($self, $ns) = @_;
629 994 100       3023 my $special = $self->{cf_special_entities}
630             or return $ns;
631             # XXX: die "entity_ns \$ns ($ns) is not yet implemented" if defined $ns;
632 90         149 $self->re_ns(0, undef, $special);
633             }
634              
635             #
636             sub re_prefix {
637 2976     2976 0 4222 (my MY $self, my ($capture, $ns, $pre, $suf)) = @_;
638 2976 100       5629 $ns = $$self{re_ns} unless defined $ns;
639 2976 100       3647 $pre = '' unless defined $pre;
640 2976 50       4117 $suf = '' unless defined $suf;
641 2976 100 66     8025 if (defined $ns and $ns ne '') {
642 2974 100 100     6310 $ns = "($ns)" if $capture && $capture > 1;
643 2974         4968 qq{$pre$ns$suf};
644             } else {
645 2         4 ''
646             }
647             }
648              
649             1;