File Coverage

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


line stmt bran cond sub pod time code
1             # -*- mode: perl; coding: utf-8 -*-
2             package YATT::LRXML::Parser;
3 7     7   13715 use strict;
  7         13  
  7         250  
4 7     7   36 use warnings qw(FATAL all NONFATAL misc);
  7         10  
  7         395  
5 7     7   37 use base qw(YATT::Class::Configurable);
  7         13  
  7         2016  
6             use YATT::Fields
7 7         91 (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   1215 );
  7         14  
31              
32 7     7   41 use YATT::Util;
  7         11  
  7         1178  
33 7     7   35 use YATT::Util::Taint;
  7         12  
  7         690  
34 7     7   37 use YATT::Util::Symbol qw(fields_hash);
  7         16  
  7         324  
35 7     7   726 use YATT::LRXML::Node;
  7         12  
  7         1709  
36              
37 7     7   1950 use YATT::LRXML ();
  7         13  
  7         122  
38 7     7   1969 use YATT::LRXML::MetaInfo ();
  7         20  
  7         41905  
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 778 my MY $self = shift;
47 489         1568 $self->SUPER::after_configure;
48 489         2133 $$self{re_ns} = $self->re_ns(0);
49 489         1535 $$self{re_splitter} = $self->re_splitter(1, $$self{re_ns});
50 489         3043 $$self{re_attlist} = $self->re_attlist(2);
51 489         1785 $$self{re_arg_decls} = $self->re_arg_decls(1);
52             {
53 489         934 my %re_cached = map {$_ => 1} grep {/^re_/} keys %{fields_hash($self)};
  489         753  
  2445         5153  
  8313         18337  
  489         1950  
54 489         2488 my @token_pat = $self->re_tokens(2);
55 489         1678 while (@token_pat) {
56 2445         5161 my ($name, $pattern) = splice @token_pat, 0, 2;
57 2445         3680 push @{$self->{elem_kids}}, [$name, qr{^$pattern}];
  2445         128723  
58 2445 100       13444 next unless $re_cached{"re_$name"};
59 489         3904 $self->{"re_$name"} = $pattern;
60             }
61             }
62             }
63              
64             sub configure_namespace {
65 4     4 0 16 shift->metainfo->configure(namespace => shift);
66             }
67              
68             sub configure_metainfo {
69 489     489 0 845 (my MY $self) = shift;
70 489 50       1913 if (@_ == 1) {
    100          
71 0         0 $self->{metainfo} = shift;
72             } elsif (not $self->{metainfo}) {
73             # @_ == 0 || > 1
74 165         1102 $self->{metainfo} = MetaInfo->new(@_);
75             } else {
76 324         1328 $self->{metainfo}->configure(@_);
77             }
78             $self->{metainfo}
79 489         1802 }
80              
81             sub metainfo {
82 739     739 0 1218 (my MY $self) = shift;
83 739   66     2989 $self->{metainfo} ||= $self->configure_metainfo;
84             }
85              
86             sub parse_handle {
87 156     156 0 450 (my MY $self, my ($fh)) = splice @_, 0, 2;
88 156         439 $self->configure_metainfo(@_);
89 156         450 $self->after_configure;
90 156 50       944 if (my $layer = $self->{metainfo}->cget('iolayer')) {
91 0         0 binmode $fh, $layer;
92             }
93 156         316 my $scan = $self->tokenize(do {
94 156         758 local $/;
95 156         4096 my $data = <$fh>;
96 156 50       1028 $self->{cf_untaint} ? untaint_any($data) : $data;
97             });
98 156         624 $self->organize($scan);
99             }
100              
101             sub parse_string {
102 12     12 0 103 my MY $self = shift;
103 12         42 $self->configure_metainfo(splice @_, 1);
104 12         27 $self->after_configure;
105 12         41 my $scan = $self->tokenize($_[0]);
106 12         55 $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 337 (my MY $self) = @_;
115             $self->Scanner->new(array => $self->{tokens}, index => 0
116             , linenum => 1
117 170         1817 , metainfo => $self->{metainfo});
118             }
119              
120             sub tree {
121 166     166 0 249 my MY $self = shift;
122             my $cursor = $self->call_type(Cursor => new => $self->{cf_tree}
123 166         908 , metainfo => $self->{metainfo});
124             #$cursor->configure(path => $self->Cursor->Path->new($self->{cf_tree}));
125 166         1043 $cursor;
126             }
127              
128             sub new_root_builder {
129 168     168 0 330 (my MY $self, my Scanner $scan) = @_;
130 168 100       521 if (my $reg = $self->{cf_registry}) {
131 156         836 $reg->new_root_builder($self, $scan);
132             } else {
133             require_and($self->Builder
134             , new => $self->{cf_tree} = $self->create_node('root')
135             , undef
136             , startpos => 0
137             , startline => $scan->{cf_linenum}
138 12         57 , linenum => $scan->{cf_linenum});
139             }
140             }
141              
142             sub organize {
143 168     168 0 335 (my MY $self, my Scanner $scan) = @_;
144 168         523 my $builder = $self->new_root_builder($scan);
145 168         950 while ($scan->readable) {
146 789         2656 my $text = $scan->read;
147 789 100       3235 $builder->add($scan, $text) if $text ne '';
148 789 100       2269 last unless $scan->readable;
149 635         2404 my ($toktype, @match) = $scan->expect($self->{elem_kids});
150 635 50       1737 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       3264 if (my $sub = $self->can("build_$toktype")) {
157             # declarator も complex 扱いにした方が良いね。
158 633         1618 $builder = $sub->($self, $scan, $builder, \@match);
159             } else {
160             # easy case.
161 2         6 my ($ns, $body) = @match;
162 2         6 $self->build_scanned($builder, $scan
163             , $toktype => $ns, $body);
164             }
165             }
166 163 50 66     630 if ($builder->{cf_endtag} and $builder->{parent}) {
167             die "Missing close tag '$builder->{cf_endtag}'"
168             ." at line $builder->{cf_startline}"
169 2         20 .$scan->{cf_metainfo}->in_file." \n";
170             }
171            
172 161 50       433 if (wantarray) {
173 0         0 ($self->tree, $self->{metainfo});
174             } else {
175 161         518 $self->tree;
176             }
177             }
178              
179             sub build_scanned {
180 193     193 0 479 (my MY $self, my Builder $builder, my Scanner $scan) = splice @_, 0, 3;
181 193         672 my $node = $self->create_node(@_);
182 193         742 node_set_nlines($node, $scan->{cf_last_nol});
183 193         625 $builder->add($scan, $node);
184             }
185              
186             sub build_pi {
187 19     19 0 38 (my MY $self, my Scanner $scan, my Builder $builder, my ($match)) = @_;
188 19         80 $self->build_scanned($builder, $scan
189             , pi => $match->[0]
190             , $self->parse_entities($match->[1]));
191 19         97 $builder;
192             }
193              
194             sub build_entity {
195 172     172 0 449 (my MY $self, my Scanner $scan, my Builder $builder, my ($match)) = @_;
196 172         660 $self->build_scanned($builder, $scan
197             , entity => $self->parse_entpath($match->[0]));
198 172         820 $builder;
199             }
200              
201             sub build_tag {
202 255     255 0 915 (my MY $self, my Scanner $scan, my Builder $builder, my ($match)) = @_;
203 255         752 my ($close, $html, $ns, $tagname, $attlist, $is_ee) = @$match;
204 255   66     681 $tagname ||= $html;
205              
206 255 100       625 if ($close) {
207 64         280 $builder->verify_close($tagname, $scan);
208             # そうか、ここで attribute element からの脱出もせにゃならん。
209             # switched product 方式なら、parent は共通、かな?
210 63         233 return $builder->parent;
211             }
212              
213 191         319 my ($is_att, $nodetype, $qflag) = do {
214 191 100 100     1077 if (defined $ns and $ns =~ s/^:(?=\w)//) {
215 21         115 (1, attribute => YATT::LRXML::Node->quoted_by_element($is_ee));
216             } else {
217 170         235 my $type = do {
218 170 100       385 if (defined $html) {
219 18         60 $is_ee = $self->{cf_html_tags}{lc($html)};
220 18         37 'html';
221             } else {
222 152         285 'element'
223             }
224             };
225 170 100       771 (0, $type => $is_ee ? EMPTY_ELEMENT : 0);
226             }
227             };
228              
229 191 100       1680 my $element = $self->create_node([$nodetype, $qflag]
230             , $html
231             ? $html
232             : [$ns, split /[:\.]/, $tagname]);
233 191         794 $self->parse_attlist($attlist, $element);
234              
235 191 100       603 unless ($is_ee) {
    100          
236             # ..., <:yatt:attr>...
237 67         299 $builder->add($scan, $element)->open($element, endtag => $tagname);
238             } elsif ($is_att) {
239             # <:yatt:attr />...
240 16         78 $builder->switch($element);
241             } else {
242             #
243 108         436 node_set_nlines($element, $scan->{cf_last_nol});
244 108         390 $builder->add($scan, $element);
245             }
246             }
247              
248             #========================================
249              
250             sub build_declarator {
251 187     187 0 394 (my MY $self, my Scanner $scan, my Builder $builder, my ($match)) = @_;
252 187         516 my ($ns, $tagname, $attlist) = @$match;
253              
254 187         926 my $element = $self->create_node(declarator =>
255             [$ns, $tagname]);
256 187         807 push @$element, $self->parse_arg_decls(\$attlist);
257 187         869 node_set_nlines($element, $scan->{cf_last_nol});
258 187 100       568 if (my $reg = $self->{cf_registry}) {
259 183         851 $reg->new_decl_builder($builder, $scan, $element, $self);
260             } else {
261 4         15 $builder->add($scan, $element);
262             }
263             }
264              
265             sub re_arg_decls {
266 491     491 0 2011 (my MY $self, my ($capture)) = @_;
267 491 50       1334 die "re_arg_decls(capture=0) is not yet implemented!" unless $capture;
268 491         1195 my ($SQ, $DQ) = ($self->re_sqv(2), $self->re_dqv(2));
269 491         1368 my $BARE = qr{([^=\-\'\"\s<>/\[\]%]+ | /(?!>))}x;
270 491         1257 my $ENT = qr{%([\w\:\.]+(?:[\w:\.\-=\[\]\{\}\(,\)]+)?);}x;
271 491         5271 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 18 (my MY $self, my ($capture)) = @_;
287 3         13 qr{%([\w\:\.]+(?:[\w:\.\-=\[\]\{\}\(,\)]+)?);}x;
288             }
289              
290             sub parse_arg_decls {
291 207     207 0 382 (my MY $self, my ($strref)) = @_;
292 207         276 my @args;
293 207         2122 while ($$strref =~ s{$$self{re_arg_decls}}{}x) {
294             print STDERR "parse_arg_decls: ", join("|", map {
295 0 0       0 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 429 50       1280 ), "\n" if $self->{cf_debug};
307 429 100       2120 if (defined $1) { # comment
    100          
    100          
308 3         10 push @args, $self->create_node(decl_comment => undef, $1);
309             } elsif (defined $2) { # ENT
310 52         210 push @args
311             , $self->create_node([entity => 1] => $self->parse_entpath($2));
312             } elsif (defined $3) { # ]
313 20         42 last;
314             } else {
315             # $4 # name
316             # $5 # '..'
317             # $6 # ".."
318             # $7 # bare
319             # $8 # ]
320 354 100       877 if (defined $8) { # [
321             # XXX: hard coded.
322 20         104 push @args, my $nest = $self->create_node([attribute => 3], $4, $9);
323 20         85 push @$nest, $self->parse_arg_decls($strref);
324             } else {
325             # XXX: dummy.
326 334         1429 push @args, $self->create_attlist('', $4, '=', $5, $6, $7);
327             }
328             }
329             }
330 207 50       595 print STDERR "REST<$$strref>\n" if $self->{cf_debug};
331 207         707 @args;
332             }
333              
334             #========================================
335              
336             sub parse_attlist {
337 191     191 0 292 my MY $self = shift;
338 191         306 my $result = $_[1]; # Yes. this *is* intentional.
339             # XXX: タグ内改行がここでカウントされなくなる。
340 191 100 66     2493 if (defined $_[0] and my @match = $_[0] =~ m{$$self{re_attlist}}g) {
341 112         506 push @$result, $self->create_attlist(@match);
342             }
343 191         518 $result;
344             }
345              
346             sub parse_entities {
347 264     264 0 502 my MY $self = shift;
348             # XXX: 行番号情報を受け取れた方が、嬉しいのだが…
349 264 50       657 return undef unless defined $_[0]; # make sure single scalar is returned.
350 264 50       626 return '' if $_[0] eq '';
351 264 50       672 return $_[0] unless defined $$self{re_entity};
352 264         1771 my @tokens = split $$self{re_entity}, $_[0];
353 264 100       1410 return $tokens[0] if @tokens == 1;
354 58         103 my @result;
355 58         228 for (my $i = 0; $i < @tokens; $i += 2) {
356 91 100       299 push @result, $tokens[$i] if $tokens[$i] ne "";
357 91 100       410 push @result
358             , $self->create_node(entity => $self->parse_entpath($tokens[$i+1]))
359             if $i+1 < @tokens;
360             }
361 58 100       148 if (wantarray) {
    100          
362 52         293 @result;
363             } elsif (@result > 1) {
364 5         37 [TEXT_TYPE, undef, @result];
365             } else {
366 1         7 $result[0];
367             }
368             }
369              
370             sub parse_entpath {
371 291     291 0 600 (my MY $self, my ($entpath)) = @_;
372 291         384 my @name;
373 291         3680 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       1744 (@name ? \@name : undef
    100          
377             , $entpath eq "" ? () : $entpath);
378             }
379              
380             #========================================
381              
382             sub tokenize {
383 168     168 0 328 my MY $self = shift;
384 168         6639 $self->{tokens} = [split $$self{re_splitter}, $_[0]];
385 168 50       848 if (my MetaInfo $meta = $self->{metainfo}) {
386             # $meta->{tokens} = $self->{tokens};
387             }
388 168         736 $self->scanner;
389             }
390              
391             sub token_patterns {
392 1981     1981 0 3427 my ($self, $token_types, $capture, $ns) = @_;
393 1981         2763 my $wantarray = wantarray;
394 1981         2196 my @result;
395 1981         3550 foreach my $type (@$token_types) {
396 6920         12065 my $meth = "re_$type";
397 6920 100       22010 push @result
398             , $wantarray ? $type : ()
399             , $self->$meth($capture, $ns);
400             }
401 1981 100       6358 return @result if $wantarray;
402 1492         3983 my $pattern = join "\n | ", @result;
403 1492         197252 qr{$pattern}x;
404             }
405              
406             #----------------------------------------
407              
408             sub re_splitter {
409 494     494 0 1621 (my MY $self, my ($capture, $ns)) = @_;
410 494         1430 my $body = $self->re_tokens(0, $ns);
411 494 100       79505 $capture ? qr{($body)} : $body;
412             }
413              
414             sub re_tokens {
415 986     986 0 2029 (my MY $self, my ($capture, $ns)) = @_;
416 986         2884 $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 2021 (my MY $self, my ($capture, $ns)) = @_;
424 995         3529 my $namepat = $self->token_patterns([qw(tagname_html tagname_qualified)]
425             , $capture, $ns);
426 995         3210 my $attlist = $self->re_attlist;
427 995 100 100     5342 if (defined $capture and $capture > 1) {
428 493         44365 qr{<(/)? (?: $namepat) ($attlist*) \s*(/)?>}xs;
429             } else {
430 502         43275 my $re = qr{}xs;
431 502 100       2894 $capture ? qr{($re)} : $re;
432             }
433             }
434              
435             #----------------------------------------
436              
437             sub re_name {
438 3     3 0 16 my ($self, $capture) = @_;
439 3         5 my $body = q{[\w\-\.]+};
440 3 100       52 $capture ? qr{($body)} : qr{$body};
441             }
442              
443             sub re_ns {
444 579     579 0 1245 my ($self, $capture, $nslist, $additional) = @_;
445 579 50       1496 die "re_ns capture is not yet implemented" if $capture;
446 579   33     1819 $nslist ||= $self->{nslist} = do {
447 579         1469 my $meta = $self->metainfo;
448 579         2015 $self->{nsdict} = $meta->nsdict;
449 579         2061 $meta->cget('namespace');
450             };
451 579 50       1661 unless (@$nslist) {
452 0         0 '';
453             } else {
454 579 50       1735 my $pattern = join "|", map {ref $_ ? @$_ : $_} @$nslist
  1053 50       3298  
    100          
455             , !$additional ? () : ref $additional ? @$additional : $additional;
456 579         2229 qq{(?:$pattern)};
457             }
458             }
459              
460             sub re_nsname {
461 3505     3505 0 5194 my ($self, $capture) = @_;
462 3505         4545 my $body = q{[\w\-\.:]+};
463 3505 100       15328 $capture ? qr{($body)} : qr{$body};
464             }
465              
466             sub re_tagname_qualified {
467 1989     1989 0 3040 my ($self, $capture, $ns) = @_;
468 1989 100       4713 $ns = $$self{re_ns} unless defined $ns;
469 1989         3842 my $name = $self->re_nsname;
470 1989 100 100     8586 if (defined $capture and $capture > 1) {
471 985         19809 qr{ ( :?$ns) : ($name) }xs;
472             } else {
473 1004         2370 my $re = qq{ :?$ns : $name };
474 1004 100       20845 $capture ? qr{($re)}xs : qr{$re}xs;
475             }
476             }
477              
478             sub re_tagname_html {
479 998     998 0 2064 (my MY $self, my ($capture, $ns)) = @_;
480 998         1789 my $body = join "|", keys %{$self->{cf_html_tags}};
  998         3918  
481 998 100       6749 $capture ? qr{($body)}i : qr{$body}i;
482             }
483              
484             #----------------------------------------
485              
486             sub re_attlist {
487 1491     1491 0 3813 my ($self, $capture) = @_;
488 1491         3123 my $name = $self->re_nsname;
489 1491         3624 my $value = $self->re_attvalue($capture);
490 1491         5521 my $sp = q{\s+};
491 1491         2103 my $eq = q{\s* = \s*};
492 1491 100 100     5938 if (defined $capture and $capture > 1) {
493 494         5847 qr{($sp|\b) (?:($name) ($eq))? $value}xs;
494             } else {
495 997         8294 my $re = qr{(?:$sp|\b) (?:$name $eq)? $value}xs;
496 997 100       5315 $capture ? qr{($re)} : $re;
497             }
498             }
499              
500             sub re_attvalue {
501 1494     1494 0 2484 my ($self, $capture) = @_;
502 1494         3206 my ($SQ, $DQ, $NQ) =
503             ($self->re_sqv($capture),
504             $self->re_dqv($capture),
505             $self->re_bare($capture));
506 1494         64083 qr{$SQ | $DQ | $NQ}xs;
507             }
508              
509             sub re_sqv {
510 1988     1988 0 2704 my ($self, $capture) = @_;
511 1988         5176 my $body = qr{(?: [^\'\\]+ | \\.)*}x;
512 1988 100       7471 $body = qr{($body)} if $capture;
513 1988         29424 qr{\'$body\'}s;
514             }
515              
516             sub re_dqv {
517 1988     1988 0 3042 my ($self, $capture) = @_;
518 1988         4794 my $body = qr{(?: [^\"\\]+ | \\.)*}x;
519 1988 100       6998 $body = qr{($body)} if $capture;
520 1988         26388 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 18 shift->re_nsname(@_);
528             }
529              
530             sub re_bare_torelant {
531 1500     1500 0 2387 my ($self, $capture) = @_;
532 1500         3641 my $body = qr{[^\'\"\s<>/]+ | /(?!>)}x;
533 1500 100       8958 $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 1719 my ($self, $capture, $ns) = @_;
546 991         2270 my $namepat = $self->re_tagname_qualified($capture, $ns);
547 991         2201 my $arg_decls = q{[^>]};
548             # $self->re_arg_decls(0);
549             # print "<<$arg_decls>>\n";
550 991 100 100     4657 if (defined $capture and $capture > 1) {
551 491         16974 qr{}xs;
552             } else {
553 500         16426 my $re = qr{}xs;
554 500 100       2540 $capture ? qr{($re)} : $re;
555             }
556             }
557              
558             sub re_comment {
559 991     991 0 1589 my ($self, $capture, $ns) = @_;
560 991         2410 $ns = $self->re_prefix($capture, $ns, '#');
561 991 100       19938 $capture ? qr{}s : qr{}s;
562             }
563              
564             sub re_pi {
565 991     991 0 1790 my ($self, $capture, $ns) = @_;
566 991         2277 $ns = $self->re_prefix($capture, $ns);
567 991 100       3801 my $body = $capture ? qr{(.*?)}s : qr{.*?}s;
568 991         23350 qr{<\?\b$ns\b$body\?>}s;
569             }
570              
571             sub re_entity {
572 991     991 0 2795 shift->re_entity_pathexpr(@_);
573             }
574              
575             # normal entity
576             sub re_entity_strict {
577 3     3 0 16 my ($self, $capture, $ns) = @_;
578 3 50       13 $ns = defined $ns ? qq{$ns\:} : qr{\w+:};
579 3         9 my $body = $self->re_nsname;
580 3 100 100     18 if (defined $capture and $capture > 1) {
581 1         34 qr{&$ns($body);}xs;
582             } else {
583 2         33 my $re = qr{&$ns$body;}xs;
584 2 100       39 $capture ? qr{($re)} : $re;
585             }
586             }
587              
588             # extended (subscripted) entity.
589             sub re_entity_subscripted {
590 6     6 0 22 my ($self, $capture, $ns) = @_;
591 6 50       23 $ns = defined $ns ? qq{$ns\:} : qr{\w+:};
592 6         14 my $name = $self->re_nsname;
593 6         15 my $sub = $self->re_subscript;
594 6         18 my $body = qq{$name$sub*};
595 6 100 100     28 if (defined $capture and $capture > 1) {
596 1         96 qr{&($ns)($body);}xs;
597             } else {
598 5         116 my $re = qr{&$ns$body;}xs;
599 5 100       171 $capture ? qr{($re)} : $re;
600             }
601             }
602              
603             # This cannot handle matching paren, of course;-).
604             sub re_subscript {
605 10     10 0 28 my $name = shift->re_nsname;
606 10         130 qr{[\[\(\{]
607             [\w\.\-\+\$\[\]\{\}]*?
608             [\}\)\]]
609             |\. $name
610             |\: [/\$\.\-\w]+
611             }xs;
612             }
613              
614             # more extended
615             sub re_entity_pathexpr {
616 994     994 0 1748 my ($self, $capture, $ns) = @_;
617 994         2276 $ns = $self->re_prefix(0, $self->entity_ns($ns), '');
618 994         3160 my $body = qr{[\w\$\-\+\*/%<>\.=\@\|!:\[\]\{\}\(,\)]*};
619 994 100 100     4332 if (defined $capture and $capture > 1) {
620 492         17653 qr{&($ns\b$body);}xs;
621             } else {
622 502         19291 my $re = qr{&$ns\b$body;}xs;
623 502 100       2705 $capture ? qr{($re)} : $re;
624             }
625             }
626              
627             sub entity_ns {
628 994     994 0 1599 my ($self, $ns) = @_;
629             my $special = $self->{cf_special_entities}
630 994 100       4504 or return $ns;
631             # XXX: die "entity_ns \$ns ($ns) is not yet implemented" if defined $ns;
632 90         227 $self->re_ns(0, undef, $special);
633             }
634              
635             #
636             sub re_prefix {
637 2976     2976 0 6444 (my MY $self, my ($capture, $ns, $pre, $suf)) = @_;
638 2976 100       9043 $ns = $$self{re_ns} unless defined $ns;
639 2976 100       5914 $pre = '' unless defined $pre;
640 2976 50       6443 $suf = '' unless defined $suf;
641 2976 100 66     11889 if (defined $ns and $ns ne '') {
642 2974 100 100     9633 $ns = "($ns)" if $capture && $capture > 1;
643 2974         8189 qq{$pre$ns$suf};
644             } else {
645 2         6 ''
646             }
647             }
648              
649             1;