# Copyright (c) 1999-2004 by Steven McDougall. This module is free # software; you can redistribute it and/or modify it under the same # terms as Perl itself. package Pod::Tree::Node; use strict; use Pod::Escapes (); $Pod::Tree::Node::VERSION = '1.10'; sub root # ctor { my($class, $children) = @_; my $node = { type => 'root', children => $children }; bless $node, $class } sub code #ctor { my($class, $paragraph) = @_; my $node = { type => 'code', text => $paragraph }; bless $node, $class } sub verbatim # ctor { my($class, $paragraph) = @_; my $node = { type => 'verbatim', raw => $paragraph, text => $paragraph }; bless $node, $class } my %Argumentative = map { $_ => 1 } qw(=over =for =begin =end); sub command # ctor { my($class, $paragraph) = @_; my($command, $arg, $text); ($command) = split(/\s/, $paragraph); if ($Argumentative{$command}) { ($command, $arg, $text) = split(/\s+/, $paragraph, 3); } else { ($command, $text) = split(/\s+/, $paragraph, 2); $arg = ''; } $command =~ s/^=//; my $node = { type => 'command', raw => $paragraph, command => $command, arg => $arg, text => $text }; bless $node, $class } sub ordinary # ctor { my($class, $paragraph) = @_; my $node = { type => 'ordinary', raw => $paragraph, text => $paragraph }; bless $node, $class } sub letter # ctor { my($class, $token) = @_; my $node = { type => 'letter', letter => substr($token, 0, 1), width => $token =~ tr/ 'sequence', 'letter' => $letter->{'letter'}, children => $children }; bless $node, $class } sub text # ctor { my($class, $text) = @_; my $node = { type => 'text', text => $text }; bless $node, $class } sub target # ctor { my($class, $children) = @_; my $node = bless { type => 'target', children => $children }, $class; $node->unescape; my $text = $node->get_deep_text; if ($text =~ m(^[A-Za-z]+:(?!:))) # a URL { $node->{page } = $text; $node->{section} = ''; $node->{domain } = 'HTTP'; } else # a POD link { my($page, $section) = SplitTarget($text); $node->{page } = $page; $node->{section} = $section; $node->{domain } = 'POD'; } $node } sub SplitTarget { my $text = shift; my($page, $section); if ($text =~ /^"(.*)"$/s) # L<"sec">; { $page = ''; $section = $1; } else # all other cases { ($page, $section) = (split(m(/), $text, 2), '', ''); $page =~ s/\s*\(\d\)$//; # ls (1) -> ls $section =~ s( ^" | "$ )()xg; # lose the quotes # L
(without quotes) if ($page !~ /^[\w.-]+(::[\w.-]+)*$/ and $section eq '') { $section = $page; $page = ''; } } $section =~ s( \s*\n\s* )( )xg; # close line breaks $section =~ s( ^\s+ | \s+$ )()xg; # clip leading and trailing WS ($page, $section) } sub link # ctor { my($class, $node, $page, $section) = @_; my $target = bless { type => 'target', domain => 'POD', children => [ $node ], page => $page, section => $section }, $class; my $link = bless { type => 'sequence', letter => 'L', children => [ $node ], target => $target }, $class; $link } sub is_code { shift->{type} eq 'code' } sub is_command { shift->{type} eq 'command' } sub is_for { shift->{type} eq 'for' } sub is_item { shift->{type} eq 'item' } sub is_letter { shift->{type} eq 'letter' } sub is_list { shift->{type} eq 'list' } sub is_ordinary { shift->{type} eq 'ordinary' } sub is_root { shift->{type} eq 'root' } sub is_sequence { shift->{type} eq 'sequence' } sub is_text { shift->{type} eq 'text' } sub is_verbatim { shift->{type} eq 'verbatim' } sub is_link { my $node = shift; is_sequence $node and $node->{'letter'} eq 'L' } sub is_pod { my $node = shift; not is_code $node and not is_c_cut $node and not is_c_pod $node } sub is_c_head1 { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'head1' } sub is_c_head2 { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'head2' } sub is_c_head3 { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'head3' } sub is_c_head4 { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'head4' } sub is_c_cut { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'cut' } sub is_c_pod { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'pod' } sub is_c_over { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'over' } sub is_c_back { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'back' } sub is_c_item { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'item' } sub is_c_for { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'for' } sub is_c_begin { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'begin' } sub is_c_end { my $node = shift; $node->{type} eq 'command' and $node->{'command'} eq 'end' } sub get_arg { shift->{ arg } } sub get_back { shift->{ back } } sub get_children { shift->{ children } } sub get_command { shift->{'command' } } sub get_domain { shift->{ domain } } sub get_item_type { shift->{ item_type } } sub get_letter { shift->{'letter' } } sub get_list_type { shift->{ list_type } } sub get_page { shift->{ page } } sub get_raw { shift->{ raw } } sub get_raw_kids { shift->{ raw_kids } } sub get_section { shift->{ section } } sub get_siblings { shift->{ siblings } } sub get_target { shift->{'target' } } sub get_text { shift->{'text' } } sub get_type { shift->{'type' } } sub get_url { shift->{'url' } } sub get_brackets { my $node = shift; my $brackets = $node->{brackets}; $brackets } sub get_deep_text { my $node = shift; for ($node->get_type) { /text/ and return $node->{'text'}; /verbatim/ and return $node->{'text'}; } join '', map { $_->get_deep_text } @{$node->{children}} } sub force_text { my($node, $text) = @_; $node->{ type } = 'text'; $node->{'text'} = $text; undef $node->{children}; } sub force_for { my $node = shift; $node->{type } = 'for'; my($bracket) = $node->{raw} =~ /^(=\w+\s+\w+\s+)/; $node->{brackets} = [ $bracket ]; } sub parse_begin { my($node, $nodes) = @_; my $foreign; my @raw; while (@$nodes) { $foreign = shift @$nodes; is_c_end $foreign and last; push @raw, $foreign->{'raw'}; } $node->{'text'} = join '', @raw; my $interpreter = $foreign->{arg}; $interpreter and $interpreter ne $node->{arg} and $node->_warn("Mismatched =begin/=end tags around\n$node->{'text'}"); $node->{type } = 'for'; $node->{brackets} = [ $node->{raw}, $foreign->{raw} ]; } sub set_children { my($node, $children) = @_; $node->{children} = $children; } sub make_sequences { my $node = shift; my $text = $node->{'text'}; my @tokens = split /( [A-Z]<<+\s+ | [A-Z]< | \s+>>+ | > )/x, $text; my $sequences = _parse_text(\@tokens); $node->{children} = $sequences; } sub _parse_text { my $tokens = shift; my(@stack, @width); while (@$tokens) { my $token = shift @$tokens; length $token or next; $token =~ /^[A-Z]{$width[-1],}$/ and do { my $width = pop @width; my($letter, $interior) = _pop_sequence(\@stack, $width); my $node = sequence Pod::Tree::Node $letter, $interior; push @stack, $node; $token =~ s/^\s*>{$width}//; my @tokens = split //, $token; unshift @$tokens, @tokens; next; }; my $node = text Pod::Tree::Node $token; push @stack, $node; } if (@width) { my @text = map { $_->get_deep_text } @stack; Pod::Tree::Node->_warn("Missing '>' delimiter in\n@text"); } \@stack } sub _pop_sequence { my($stack, $width) = @_; my($node, @interior); while (@$stack) { $node = pop @$stack; is_letter $node and $node->{width} == $width and return ($node, \@interior); unshift @interior, $node; } my @text = map { $_->get_deep_text } @interior; $node->_warn("Mismatched sequence delimiters around\n@text"); $node = letter Pod::Tree::Node ' '; $node, \@interior; } sub parse_links { my $node = shift; is_link $node and $node->_parse_link; my $children = $node->{children}; for my $child (@$children) { $child->parse_links; } } sub _parse_link { my $node = shift; $node->{raw_kids} = $node->clone->{children}; my $children = $node->{children}; my($text_kids, $target_kids) = SplitBar($children); $node->{ children } = $text_kids; $node->{'target' } = target Pod::Tree::Node $target_kids; } sub SplitBar { my $children = shift; my(@text, @link); while (@$children) { my $child = shift @$children; is_text $child or do { push @text, $child; next; }; my($text, $link) = split m(\|), $child->{'text'}, 2; $link and do { push @text, text Pod::Tree::Node $text if $text; push @link, (text Pod::Tree::Node $link), @$children; return (\@text, \@link) }; push @text, $child; } (\@text, \@text) } sub unescape { my $node = shift; my $children = $node->{children}; for my $child (@$children) { $child->unescape; } is_sequence $node and $node->_unescape_sequence; } sub _unescape_sequence { my $node = shift; for ($node->{'letter'}) { /Z/ and $node->force_text(''), last; /E/ and do { my $child = $node->{children}[0]; $child or last; my $text = $child->_unescape_text; $text and $node->force_text($text); last; }; } } sub _unescape_text { my $node = shift; my $text = $node->{'text'}; defined $text ? Pod::Escapes::e2char($text) : "E"; } sub consolidate { my $node = shift; my $old = $node->{children}; $old and @$old or return; my $new = []; push @$new, shift @$old; while (@$old) { if (is_text $new->[-1] and is_text $old->[ 0] or is_verbatim $new->[-1] and is_verbatim $old->[ 0] or is_code $new->[-1] and is_code $old->[ 0] ) { $new->[-1]{'text'} .= $old->[0]{'text'}; shift @$old; } else { push @$new, shift @$old; } } $node->{children} = $new; for my $child (@$new) { $child->consolidate; } } sub make_lists { my $root = shift; my $nodes = $root->{children}; $root->_make_lists($nodes); } sub _make_lists { my($node, $old) = @_; my $new = []; my $back; while (@$old) { my $child = shift @$old; is_c_over $child and $child->_make_lists($old); is_c_item $child and $child->_make_item ($old); is_c_back $child and $back = $child, last; push @$new, $child; } $node->{children} = $new; is_root $node and return; $node->{type} = 'list'; $node->{back} = $back; $node->_set_list_type; } sub _set_list_type { my $list = shift; my $children = $list->{children}; $list->{list_type} = ''; # -w for my $child (@$children) { $child->{type} eq 'item' or next; $list->{list_type} = $child->{item_type}; last; } } sub _make_item { my($item, $old) = @_; my $siblings = []; while (@$old) { my $sibling = $old->[0]; is_c_item $sibling and last; is_c_back $sibling and last; shift @$old; is_c_over $sibling and do { $sibling->_make_lists($old); }; push @$siblings, $sibling; } $item->{type } = 'item'; $item->{siblings} = $siblings; $item->_set_item_type; } sub _set_item_type { my $item = shift; my $text = $item->{'text'}; $text =~ m(^\s* \* \s*$ )x and $item->{item_type} = 'bullet'; $text =~ m(^\s* \d+ \s*$ )x and $item->{item_type} = 'number'; $item->{item_type} or $item->{item_type} = 'text'; } sub clone { my $node = shift; my $clone = { %$node }; my $children = $node->{children}; $clone->{children} = [ map { $_->clone } @$children ]; bless $clone, ref $node } my $Indent; my $String; sub dump { my $node = shift; $Indent = 0; $String = ''; $node->_dump; $String } sub _dump { my $node = shift; my $type = $node->get_type; $String .= ' ' x $Indent . uc $type . " "; for ($type) { /command/ and $String .= $node->_dump_command; /code/ and $String .= $node->_dump_code; /for/ and $String .= $node->_dump_for; /item/ and $String .= $node->_dump_item; /list/ and $String .= $node->_dump_list; /ordinary/ and $String .= "\n"; /root/ and $String .= "\n"; /sequence/ and $String .= $node->_dump_sequence; /text/ and $String .= $node->_dump_text; /verbatim/ and $String .= $node->_dump_verbatim; } $node->_dump_children; $node->_dump_siblings; } sub _dump_command { my $node = shift; my $command = $node->get_command; my $arg = $node->get_arg; "$command $arg\n" } sub _dump_code { my $node = shift; my $text = _indent($node->get_text, 3); my $block = "\n{\n$text}\n"; _indent($block, $Indent) } sub _dump_for { my $node = shift; my $arg = $node->get_arg; my $text = _indent($node->get_text, $Indent+3); "$arg\n$text\n" } sub _dump_item { my $node = shift; uc $node->get_item_type . "\n" } sub _dump_list { my $node = shift; uc $node->get_list_type . "\n" } sub _dump_sequence { my $node = shift; my $letter = $node->get_letter; my $link = $node->is_link ? $node->_dump_target : ''; "$letter$link\n"; } sub _dump_text { my $node = shift; my $text = $node->get_text; $text =~ s/([\x80-\xff])/sprintf("\\x%02x", ord($1))/eg; my $indent = ' ' x ($Indent+5); $text =~ s( (?<=\n) (?=.) )($indent)xg; "$text\n" } sub _dump_verbatim { my $node = shift; "\n" . $node->get_text . "\n" } sub _dump_target { my $node = shift; my $target = $node->get_target; my $page = $target->{page}; my $section = $target->{section}; " $page / $section" } sub _dump_children { my $node = shift; my $children = $node->get_children; $children and DumpList($children, '{', '}'); } sub _dump_siblings { my $node = shift; my $siblings = $node->get_siblings; $siblings and DumpList($siblings, '[', ']'); } sub DumpList { my($nodes, $open, $close) = @_; $String .= ' ' x $Indent . "$open\n"; $Indent += 3; for my $node (@$nodes) { $node->_dump; } $Indent -= 3; $String .= ' ' x $Indent . "$close\n"; } sub _indent { my($text, $spaces) = @_; my $indent = ' ' x $spaces; $text =~ s( (?<=\n) (?=.) )($indent)xg; $indent . $text } sub _warn { my($node, $message) = @_; my $filename = $node->get_filename; my $tag = $filename ? "in $filename" : $filename; warn "$message $tag\n"; } sub set_filename { my($package, $filename) = @_; $Pod::Tree::Node::filename = $filename; } sub get_filename { $Pod::Tree::Node::filename } 1 __END__ =head1 NAME Pod::Tree::Node - nodes in a Pod::Tree =head1 SYNOPSIS $node = root Pod::Tree::Node \@paragraphs; $node = code Pod::Tree::Node $paragraph; $node = verbatim Pod::Tree::Node $paragraph; $node = command Pod::Tree::Node $paragraph; $node = ordinary Pod::Tree::Node $paragraph; $node = letter Pod::Tree::Node $token; $node = sequence Pod::Tree::Node $letter, \@children; $node = text Pod::Tree::Node $text; $node = target Pod::Tree::Node $target; $node = link Pod::Tree::Node $node, $page, $section; is_code $node and ... is_command $node and ... is_for $node and ... is_item $node and ... is_letter $node and ... is_list $node and ... is_ordinary $node and ... is_pod $node and ... is_root $node and ... is_sequence $node and ... is_text $node and ... is_verbatim $node and ... is_link $node and ... is_c_head1 $node and ... is_c_head2 $node and ... is_c_head3 $node and ... is_c_head4 $node and ... is_c_cut $node and ... is_c_pod $node and ... is_c_over $node and ... is_c_back $node and ... is_c_item $node and ... is_c_for $node and ... is_c_begin $node and ... is_c_end $node and ... $arg = get_arg $node; $brackets = get_brackets $node; $children = get_children $node; $command = get_command $node; $domain = get_domain $node; $item_type = get_item_type $node; $letter = get_letter $node; $list_type = get_list_type $node; $page = get_page $node; $raw = get_raw $node; $raw_kids = get_raw_kids $node; $section = get_section $node; $siblings = get_siblings $node; $target = get_target $node; $text = get_text $node; $type = get_type $node; $deep_text = get_deep_text $node; $node->force_text($text); $node->force_for; $node->parse_begin (\@nodes); $node->set_children(\@children); $node->make_sequences; $node->parse_links; $node->unescape; $node->consolidate; $node->make_lists; $node->clone; $node->dump; Pod::Tree::Node->set_filename($filename); $filename = $node->get_filename; =head1 REQUIRES Pod::Escapes =head1 DESCRIPTION C objects are nodes in a tree that represents a POD. Applications walk the tree to recover the structure and content of the POD. Methods are provided for =over 4 =item * creating nodes in the tree =item * parsing the POD into nodes =item * returning information about nodes =item * walking the tree =back =head1 TREE STRUCTURE =head2 Root node The tree descends from a single root node; C returns true on this node and no other. $children = $root->get_children returns a reference to an array of nodes. These nodes represent the POD. =head2 Node types For each node, call C to discover the type of the node for $child (@$children) { $type = $child->get_type; } I<$type> will be one of these strings: =over 4 =item 'root' The node is the root of the tree. =item 'code' The node represents a paragraph that is not part of the POD. =item 'verbatim' The node represents a verbatim paragraph. =item 'ordinary' The node represents an ordinary paragraph. =item 'command' The node represents an =command paragraph (but not an =over paragraph). =item 'sequence' The node represents an interior sequence. =item 'target' The node represents the target of a link (An LEE markup). =item 'text' The node represents text that contains no interior sequences. =item 'list' The node represents an =over list. =item 'item' The node represents an item in an =over list. =item 'for' The node represents a =for paragraph, or it represents the paragraphs between =begin/=end commands. =back Here are instructions for walking these node types. =head2 root node Call $children = $node->get_children to get a list of nodes representing the POD. =head2 code nodes A code node contains the text of a paragraph that is not part of the POD, for example, a paragraph that follows an C<=cut> command. Call $text = $node->get_text to recover the text of the paragraph. =head2 verbatim nodes A verbatim node contains the text of a verbatim paragraph. Call $text = $node->get_text to recover the text of the paragraph. =head2 ordinary nodes An ordinary node represents the text of an ordinary paragraph. The text is parsed into a list of text and sequence nodes; these nodes are the children of the ordinary node. Call $children = $node->get_children to get a list of the children. Iterate over this list to recover the text of the paragraph. =head2 command nodes A command node represents an =command paragraph. Call $command = $node->get_command; to recover the name of the command. The name is returned I the equals sign. Z<>=over paragraphs are represented by list nodes, not command nodes; see L, below. The text of a command paragraph is parsed into a list of text and sequence nodes; these nodes are the children of the command node. Call $children = $node->get_children; to get a list of the children. Iterate over this list to recover the text of the paragraph. =head2 sequence nodes A sequence node represents a single interior sequence (a <> markup). Call $node->get_letter to recover the original markup letter. The contents of the markup are parsed into a list of text and sequence nodes; these nodes are the children of the sequence node. Call $node->get_children to recover them. ZEE and EEE markups do not generate sequence nodes; these markups are expanded by C when the tree is built. =head2 target nodes If a sequence node represents a link (an C<< LZ<><> >> markup), then is_link $node returns true and $target = $node->get_target returns a node representing the target of the link. C can represent targets in two I: C and C. The C domain represents the L markups that are described in L. The C domain represents C<< LZ<><> >> markups that contain a URL, e.g. L Call $domain = $target->get_domain to discover the domain of the target. For targets in the POD domain, call $page = $target->get_page; $section = $target->get_section; to recover the man page and section that the link refers to. For targets in the HTTP domain, call $url = $target->get_page; to recover the URL for the link. I<$target> is used only for constructing hyper-links; the text to be displayed for the link is recovered by walking the children of I<$node>, as for any other interior sequence. =head2 text nodes A text node represents text that contains no interior sequences. Call $text = $node->get_text to recover the text. =head2 list nodes A list node represents an =over list. Call $list_type = $node->get_list_type; to discover the type of the list. This will be one of the strings =over 4 =item 'bullet' =item 'number' =item 'text' =back The type of a list is the type of the first item in the list. The children of a list node are item nodes; each item node represents one item in the list. You can call $node->get_arg; to recover the indent value following the =over. =head2 item nodes An item node represents one item in an =over list. Call $item_type = $node->get_item_type; to discover the type of the item. This will be one of the strings shown above for L. Typically, all the items in a list have the same type, but C doesn't assume this. The children of an item node represent the text of the =item paragraph; this is usually of interest only for 'text' items. Call $children = $node->get_children to get a list of the children; these will be sequence and text nodes, as for any other =command paragraph. Each item node also has a list of nodes representing all the paragraphs following it, up to the next =item command, or the end of the list. These nodes are called I of the item node. Call $siblings = $node->get_siblings to get a list of sibling nodes. =head2 for nodes for nodes represent text that is to be passed to an external formatter. Call $formatter = $node->get_arg; to discover the name of the formatter. Call $text = $node->get_text; to obtain the text to be passed to the formatter. This will either be the text of an =for command, or all of the text between =begin and =end commands. =head2 Walking the tree PODs have a recursive structure; therefore, any application that walks a Pod::Tree must also be recursive. See F for an example of the necessary code. =head1 METHODS =head2 Constructors These methods construct C objects. They are used to build trees. They aren't necessary to walk trees. $node = root Pod::Tree::Node \@paragraphs; $node = code Pod::Tree::Node $paragraph; $node = verbatim Pod::Tree::Node $paragraph; $node = command Pod::Tree::Node $paragraph; $node = ordinary Pod::Tree::Node $paragraph; $node = letter Pod::Tree::Node $token; $node = sequence Pod::Tree::Node $letter, \@children; $node = text Pod::Tree::Node $text; $node = target Pod::Tree::Node $target; $node = link Pod::Tree::Node $node, $page, $section; =over 4 =item I<$link> = C->C(I<$node>, I<$page>, I<$section>) Creates a new sequence node representing an C<< LZ<><> >> markup. I<$node> becomes the sole child of the new node. The target of the node is constructed from I<$page> and I<$section>. This method isn't used to parse PODs. It is provided for applications that want to create new links in an existing C structure. =back =head2 Tests These methods return true iff I<$node> has the type indicated by the method name. is_code $node and ... is_command $node and ... is_for $node and ... is_item $node and ... is_letter $node and ... is_link $node and ... is_list $node and ... is_ordinary $node and ... is_pod $node and ... is_root $node and ... is_sequence $node and ... is_text $node and ... is_verbatim $node and ... C returns true for all nodes except code, C<=pod>, and C<=cut> nodes. These methods return true iff I<$node> is a command node, and the command is the one indicated by the method name. is_c_head1 $node and ... is_c_head2 $node and ... is_c_head3 $node and ... is_c_head4 $node and ... is_c_cut $node and ... is_c_pod $node and ... is_c_over $node and ... is_c_back $node and ... is_c_item $node and ... is_c_for $node and ... is_c_begin $node and ... is_c_end $node and ... =head2 Accessors These methods return information about nodes. Most accessors are only relevant for certain types of nodes. =over 4 =item I<$arg> = C I<$node> Returns the argument of I<$node>. This is the number following an =over command, or the name of an external translator for =for, =begin, and =end commands. Only relevant for these four command nodes. =item I<$brackets> = C I<$node> Only relevant for for nodes. If the node represents an =for command, I<@$brackets> is a single-element list. The list element is the text of the =for command and its argument, i.e. the name of the external formatter. If the node represents a =begin/=end construct, I<@$brackets> is a two-element list containing the text of the =begin and =end paragraphs. =item I<$children> = C I<$node> Returns a reference to the list of nodes that are children of I<$node>. May be called on any node. The list may be empty. =item I<$command> = C I<$node> Returns the name of a command, without the equals sign. Only relevant for command nodes. =item I<$domain> = C I<$node> Only relevant for target nodes. Returns the domain of the target. This will be one of the strings =over 4 =item 'HTTP' =item 'POD' =back =item I<$item_type> = C I<$node> Returns the type of an item node. The type will be one of =over 4 =item 'bullet' =item 'number' =item 'text' =back =item I<$letter> = C I<$node> Returns the letter that introduces an interior sequence. Only relevant for sequence nodes. =item I<$list_type> = C I<$node> Returns the type of a list node. The type of a list node is the type of the first item node in the list. =item I<$page> = C I<$node> Only relevant for target nodes. For targets in the C domain, returns the man page that is the target of the link. For targets in the C domain, returns the URL that is the target of the link. =item I<$raw> = C I<$node> Returns the original text of a paragraph. Currently provided for command, verbatim, and ordinary paragraphs. =item I<$raw_kids> = C I<$node> Only provided for LZ<><> sequence nodes. Returns a reference to a list of nodes representing the entire text of the LZ<><> sequence, including any part following a vertical bar (|). The original text of the LZ<><> markup can be reconstructed from this list. =item I<$section> = C I<$node> Only relevant for target nodes in the C domain. Returns the section that is the target of a link. =item I<$siblings> = C I<$node> Returns the siblings of a node. May be called on any node. Only item nodes have siblings. =item I<$target> = C I<$node> Returns the target of a node. Only relevant for sequence nodes that represent links (CE> markups). C returns true on these nodes. =item I<$text> = C I<$node> Returns the text of a node. I<$text> will not contain any interior sequences. Only relevant for text nodes. =item I<$type> = C I<$node> Returns the type of I<$node>. May be called on any node. See L for descriptions of the node types. =item I<$deep_text> = C I<$node> Recursively walks the children of a node, catenates together the text from each node, and returns all that text as a single string. All interior sequence markups are discarded. C is provided as a convenience for applications that want to ignore markups in a POD paragraph. =back =head2 Parsing These methods manipulate the tree while it is being built. They aren't necessary to walk the tree. $node->force_text($text) $node->force_for; $node->parse_begin (\@nodes); $node->set_children(\@children); $node->make_sequences; $node->parse_links; $node->unescape; $node->consolidate; $node->make_lists; =head2 Utility =over 4 =item I<$node>->C Returns a deep copy of a node. Only implemented for C and C nodes. =item I<$node>->C Returns a string containing a pretty-printed representation of the node. Calling C on the root node of a tree will show the entire POD. =item C->C(I<$filename>) Sets the file name to be reported in error messages. =item I<$filename> = $I->C Returns the file name set by C. =back =head1 EXAMPLES The F directory in the C distribution contains examples of PODs, together with dumps of the trees that C constructs for them. The tree for CFC<.pod> is in CFC<.p_exp>. C is a simple example of code that walks a POD tree. F is a skeleton application that walks a POD tree. =head1 NOTES =over 4 =item * There is no provision in L for C<< LZ<><> >> markups to contain URLs, but due to popular demand, this is now supported in C. =back =head1 SEE ALSO perl(1), L> =head1 AUTHOR Steven McDougall, swmcd@world.std.com =head1 COPYRIGHT Copyright (c) 1999-2004 by Steven McDougall. This module is free software; you can redistribute it and/or modify it under the same terms as Perl itself.