Tk-Tree-XML
view release on metacpan or search on metacpan
examples/tkxmlview.pl view on Meta::CPAN
use strict;
use Tk;
use Tk::Table;
use Tk::Tree::XML;
die "Syntax: $0 <file.xml>\n" unless (scalar @ARGV == 1);
my $xml_filename = shift;
my ($FOREGROUND, $BACKGROUND) = ("black", "#FFFFFF");
my ($attrs_table, $pcdata_textarea);
my $top = MainWindow->new;
my $xml_tree = $top->ScrolledXML(
-background => $BACKGROUND, -foreground => $FOREGROUND, -height => 20,
);
$xml_tree->configure(-browsecmd => sub {
if ($xml_tree->is_mixed()) {
# mixed element => update attrs table and clear/disable pcdata text
update_table($attrs_table, $xml_tree->get_attrs);
$pcdata_textarea->delete("1.0", "end");
$pcdata_textarea->configure(-state => "disable");
} else {
# pcdata element => clear attrs table and enable/update pcdata text
update_table($attrs_table, ());
$pcdata_textarea->configure(-state => "normal");
$pcdata_textarea->delete("1.0", "end");
$pcdata_textarea->insert("end", $xml_tree->get_text);
}
});
$xml_tree->load_xml_file($xml_filename);
# XML attributes (name/value) table (for currently selected element in tree)
$attrs_table = $top->Table(
-columns => 2, -rows => 3, -scrollbars => 'ne',
-background => $BACKGROUND, -foreground => $FOREGROUND,
);
$attrs_table->put(0, 0, ' ' x 40 . 'Name' . ' ' x 40);
$attrs_table->put(0, 1, ' ' x 40 . 'Value' . ' ' x 40);
# PCDATA text area (for currently selected element in tree if PCDATA)
$pcdata_textarea = $top->Text(
-height => 10, -background => $BACKGROUND, -foreground => $FOREGROUND,
);
# bottom area containing the exit button
my $bottom_area = $top->Frame;
# exit button
my $exit_button = $top->Button(
-text => 'Exit', #-command => \&exit,
-command => sub {exit;},
-background => $BACKGROUND, -foreground => $FOREGROUND,
);
# pack gui components
$xml_tree->pack(-side => 'top', -fill => 'x', -expand => 1);
$attrs_table->pack(-side => 'top', -fill => 'both', -expand => 0);
$pcdata_textarea->pack(-side => 'top', -fill => 'x', -expand => 0);
$bottom_area->pack(-side => 'top', -fill => 'x', -expand => 0);
$exit_button -> pack(-side => 'right', -in => $bottom_area->parent,
-fill => 'none', -expand => 0
);
MainLoop;
sub update_table { # clear and update table with data
my ($table, %data) = @_;
my $row = 0;
lib/Tk/Tree/XML.pm view on Meta::CPAN
sub Tk::Widget::ScrolledXML { shift->Scrolled('XML' => @_) }
# ConfigSpecs default values
my $PCDATA_MAX_LENGTH = 80;
sub Populate {
my ($myself, $args) = @_;
$myself->SUPER::Populate($args);
$myself->ConfigSpecs(
-pcdatamaxlength => ["METHOD", "pcdataMaxLength",
"PCDATAMaxLength", $PCDATA_MAX_LENGTH],
-pcdatalongsymbol => ["PASSIVE", "pcdataLongSymbol",
"PCDATALongSymbol", '...'],
-pcdatapreservespace => ["PASSIVE", "pcdataPreserveSpace",
"PCDATAPreserveSpace", 0],
-itemtype => ["SELF", "itemType", "ItemType", 'text']
);
}
# ConfigSpecs methods
# get/set maximum number of characters for visualization of pcdata contents
sub pcdatamaxlength {
my ($myself, $args) = @_;
if (@_ > 1) {
$myself->_configure(-pcdatamaxlength => &_pcdata_max_length($args));
}
return $myself->_cget('-pcdatamaxlength');
}
# validate given max number of characters for visualization of pcdata contents
# return given number if it is valid, $PCDATA_MAX_LENGTH otherwise
sub _pcdata_max_length {
$_ = shift;
/^\+?\d+$/ ? $& : &{ sub {
carp "Attempt to assign an invalid value to -pcdatamaxlength: '$_' is" .
" not a positive integer. Default value ($PCDATA_MAX_LENGTH)" .
" will be used instead.\n";
$PCDATA_MAX_LENGTH
}};
}
# application programming interface
sub load_xml_file { # load_xml_file($xml_filename)
my ($myself, $xmlfile) = @_;
lib/Tk/Tree/XML.pm view on Meta::CPAN
my $myself = shift;
my $text = $myself->entrycget($myself->selectionGet(), '-data');
ref($text) ? undef : $text;
}
sub is_mixed { # is_mixed()
my $myself = shift;
'HASH' eq ref($myself->entrycget($myself->selectionGet(), '-data'));
}
sub is_pcdata { # is_pcdata()
my $myself = shift;
!$myself->is_mixed();
}
# helper methods
sub _xml_parser { # _xml_parser(): get an XML::Parser instance.
new XML::Parser(Style => 'Tree', ErrorContext => 2)
}
# _load_xml($parent_path, @children): load XML elems under entry at $parent_path
# @children is a list of tag/content pairs where each pair is such as:
# - ($element_tag, [%element_attrs, @element_children]) <= element is mixed
# - 0, 'pcdata contents' <= element is PCDATA
# for each entry, XML -data and -text are set, respectively, to:
# attributes and element tag <= element is mixed
# pcdata content and formatted pcdata content <= element is PCDATA
sub _load_xml {
my ($myself, $parent_path, @children) = ($_[0], $_[1], @{$_[2]});
my $entry_path;
while (@children) {
my ($elem_tag, $elem_content) = (shift @children, shift @children);
if (!ref $elem_content) { # element is #PCDATA
$elem_content =~ s/[\n\t ]*(.*)[\n\t ]*/$1/ # trim spacing
unless $myself->cget('-pcdatapreservespace') eq 1;
if ('' ne $elem_content) {
$entry_path = $myself->addchild(
$parent_path, -data => $elem_content,
-text => $myself->_format_pcdata($elem_content),
);
}
} else { # element is not pcdata
$entry_path = $myself->addchild($parent_path,
-data => $elem_content->[0], -text => $elem_tag
);
shift(@$elem_content); # shift element attributes off
$myself->_load_xml($entry_path, $elem_content)
unless !scalar @$elem_content; # recursively process children
}
}
}
sub _format_pcdata { # _format_pcdata($pcdata): format/return pcdata accordingly
my ($myself, $pcdata) = @_;
my $pcdata_max_length = $myself->cget('-pcdatamaxlength');
length($pcdata) > $pcdata_max_length
? substr($pcdata, 0, $pcdata_max_length) .
$myself->cget('-pcdatalongsymbol')
: $pcdata;
}
1;
__END__
=head1 NAME
Tk::Tree::XML - XML tree widget
lib/Tk/Tree/XML.pm view on Meta::CPAN
B<XML> is a subclass of L<Tk::Tree> and therefore inherits all of its
standard options.
Details on standard widget options can be found at L<Tk::options>.
=head1 WIDGET-SPECIFIC OPTIONS
=over 4
=item Name: B<pcdataMaxLength>
=item Class: B<PCDATAMaxLength>
=item Switch: B<-pcdatamaxlength>
Set the maximum number of characters to be displayed for PCDATA elements.
Content of such elements is trimmed to a length of B<pcdataMaxLength> characters.
Default value: C<80>.
=item Name: B<pcdataLongSymbol>
=item Class: B<PCDATALongSymbol>
=item Switch: B<-pcdatalongsymbol>
Set the symbol to append to PCDATA content with length greater than
B<pcdataMaxLength> characters.
Default value: C<...>.
=item Name: B<pcdataPreserveSpace>
=item Class: B<PCDATAPreserveSpace>
=item Switch: B<-pcdatapreservespace>
Specify whether space characters surrounding PCDATA elements should be
preserved or not. Such characters are preserved if this option is set to 1 and
not preserved if set to 0.
Default value: 0.
=back
=head1 WIDGET METHODS
lib/Tk/Tree/XML.pm view on Meta::CPAN
Example(s):
# determine if selected element is mixed or not
print "element is " . ($xml_tree->is_mixed() ? 'mixed' : 'PCDATA');
=back
=over 4
=item $xml_tree->B<is_pcdata>()
Indicate whether the currently selected element is PCDATA or not. If the
element is not PCDATA then it is mixed.
Return value: TRUE if the currently selected element is PCDATA, FALSE if it is
mixed.
Example(s):
# determine if selected element is PCDATA or not
print "element is " . ($xml_tree->is_pcdata() ? 'PCDATA' : 'mixed');
=back
=head1 EXAMPLES
An XML viewer using B<Tk::Tree::XML> can be found in the F<examples> directory
included with this module.
=head1 VERSION
t/pod-coverage.t view on Meta::CPAN
plan skip_all => "Test::Pod::Coverage $min_tpc required for testing POD coverage"
if $@;
# Test::Pod::Coverage doesn't require a minimum Pod::Coverage version,
# but older versions don't recognize some common documentation styles
my $min_pc = 0.18;
eval "use Pod::Coverage $min_pc";
plan skip_all => "Pod::Coverage $min_pc required for testing POD coverage"
if $@;
all_pod_coverage_ok({also_private => [qw/Populate pcdatamaxlength/]});
( run in 0.633 second using v1.01-cache-2.11-cpan-454fe037f31 )