HTML-AutoTag
view release on metacpan or search on metacpan
lib/HTML/AutoTag.pm view on Meta::CPAN
} else {
# simple attrs can bypass being tied
$attr_str = '';
my @keys = $SORTED ? sort keys %$attr : keys %$attr;
for my $key (@keys) {
$attr_str .= ' ' . Tie::Hash::Attribute::_key( $key ) . '="' . Tie::Hash::Attribute::_val( $attr->{$key} ) . '"';
}
}
# emtpy tag
unless (defined $args{cdata}) {
return ( $INDENT x $LEVEL )
. "<$args{tag}"
. ( defined( $attr_str ) ? $attr_str : scalar( %$attr ) )
. " />$NEWLINE"
;
}
my $cdata;
my $no_post_indent;
if (ref($args{cdata}) eq 'ARRAY') {
if (ref($args{cdata}[0]) eq 'HASH') {
$LEVEL++;
$cdata = $NEWLINE;
for (0 .. $#{ $args{cdata} }) {
$cdata .= $self->tag( %{ $args{cdata}[$_] } );
}
$LEVEL--;
} else {
my $str = '';
for (@{ $args{cdata} }) {
$str .= $self->tag( tag => $args{tag}, attr => $attr, cdata => $_);
}
return $str;
}
} elsif (ref($args{cdata}) eq 'HASH') {
$LEVEL++;
$cdata = $NEWLINE . $self->tag( %{ $args{cdata} } );
$LEVEL--;
} else {
$cdata = $ENCODE ? HTML::Entities::encode_entities( $args{cdata}, $ENCODES ) : $args{cdata};
$no_post_indent = 1;
}
return ( $INDENT x $LEVEL )
. "<$args{tag}" . ( defined( $attr_str ) ? $attr_str : scalar( %$attr ) )
. ">$cdata"
. ( $no_post_indent ? '' : ( $INDENT x $LEVEL ) )
. "</$args{tag}>$NEWLINE"
;
}
1;
__END__
=head1 NAME
lib/HTML/AutoTag.pm view on Meta::CPAN
use HTML::AutoTag;
my $auto = HTML::AutoTag->new( indent => ' ', encode => 1 );
my %attr = ( style => { color => [qw(red green)] } );
my @data = qw( one two three four five six seven eight );
print $auto->tag(
tag => 'ol',
attr => {qw( reversed reversed )},
cdata => [
map { tag => 'li', attr => \%attr, cdata => $_ }, @data
]
);
=head1 DESCRIPTION
Generate nested HTML (HTML4, XHTML and HTML5) tags with custom indentation,
custom encoding and automatic attribute value rotation.
=head1 METHODS
lib/HTML/AutoTag.pm view on Meta::CPAN
Accepts three arguments:
=over 8
=item * C<tag>
The name of the tag. String.
tag => 'table'
=item * C<cdata>
The value inbetween the tag. Types allowed are:
=over 12
=item * scalar - the string to be wrapped in tags
cdata => 'hello world'
=item * hash ref - another tag with its own cdata and attributes
cdata => { tag => 'td', attr => {}, cdata => 'value' }
=item * AoH - multiple tags as hash references.
cdata => [
{ tag => 'td', attr => {}, cdata => 'value1' }
{ tag => 'td', attr => {}, cdata => 'value2' }
]
=back
=item * C<attr>
The attributes and values to write out for the tag. Hash reference.
attr => { border => 1 }
lib/HTML/AutoTag.pm view on Meta::CPAN
=head1 EXAMPLES
The following will render a table with rotating attributes:
my $auto = HTML::AutoTag->new( indent => " " );
my %tr_attr = ( class => [qw(odd even)] );
print $auto->tag(
tag => 'table',
attr => { class => 'spreadsheet' },
cdata => [
{
tag => 'tr',
attr => \%tr_attr,
cdata => {
tag => 'td',
attr => { style => { color => [qw(red green)] } },
cdata => [qw(one two three four five six)],
},
},
{
tag => 'tr',
attr => \%tr_attr,
cdata => {
tag => 'td',
attr => { style => { color => [qw(green red)] } },
cdata => [qw(seven eight nine ten eleven twelve)],
},
},
{
tag => 'tr',
attr => \%tr_attr,
cdata => {
tag => 'td',
attr => { style => { color => [qw(red green)] } },
cdata => [qw(thirteen fourteen fifteen sixteen seventeen eighteen)],
},
},
]
);
The following will emulate CGI.pm's C<scrolling_list()> output:
my $auto = HTML::AutoTag->new( indent => " " );
print $auto->tag(
tag => 'select',
attr => { name => 'widgets', size => 3, multiple => 'multiple' },
cdata => [
{ tag => 'option', cdata => 'foo', attr => { value => 1, } },
{ tag => 'option', cdata => 'bar', attr => { value => 2, selected => 'selected' } },
{ tag => 'option', cdata => 'baz', attr => { value => 3, selected => 'selected' } },
]
);
Or in a more programatic way:
my $auto = HTML::AutoTag->new( indent => " " );
my @selected = (2, 3);
my @options = (
[ 1, 'foo' ],
lib/HTML/AutoTag.pm view on Meta::CPAN
my $selected = [];
for my $o (@options) {
push @$selected, (grep $_ eq $o->[0], @selected) ? 'selected' : undef;
}
my %attr = ( value => [ map $_->[0], @options ], selected => $selected );
print $auto->tag(
tag => 'select',
attr => { name => 'widgets', size => scalar @options, multiple => 'multiple' },
cdata => [ map { tag => 'option', attr => \%attr, cdata => $_->[1] }, @options ],
);
See tests in C<t/> from the distribution or github for more examples:
L<https://github.com/jeffa/HTML-AutoTag/tree/master/t>
=head1 INSPIRATION
This module was the unintentional result of efforts to refactor
L<DBIx::XHTML_Table> into L<DBIx::HTML> and L<Spreadsheet::HTML>. The need
to reimplement what CGI and HTML::Element (and a slew of others out there
use HTML::AutoTag;
my $auto = HTML::AutoTag->new( indent => ' ', encode => 1 );
my %attr = ( style => { color => [qw(red green)] } );
my @data = qw( one two three four five six seven eight );
print $auto->tag(
tag => 'ol',
attr => {qw( reversed reversed )},
cdata => [
map { tag => 'li', attr => \%attr, cdata => $_ }, @data
]
);
```
Installation
------------
To install this module, you should use CPAN. A good starting
place is [How to install CPAN modules](http://www.cpan.org/modules/INSTALL.html).
If you truly want to install from this github repo, then
t/00-load.t view on Meta::CPAN
use Test::More tests => 9;
use_ok 'HTML::AutoTag';
my $auto = new_ok 'HTML::AutoTag';
is $auto->tag( tag => 'foo' ),
'<foo />',
"tag with no attributes or children";
is $auto->tag( tag => 'foo', cdata => 'bar' ),
'<foo>bar</foo>',
"tag with one child";
is $auto->tag( tag => 'foo', attr => { class => 'baz' } ),
'<foo class="baz" />',
"tag with only attributes";
is $auto->tag( tag => 'foo', attr => { class => 'baz' }, cdata => 'bar' ),
'<foo class="baz">bar</foo>',
"tag with attributes and one child";
is $auto->tag( tag => 'foo', cdata => [qw(bar baz qux)] ),
'<foo>bar</foo><foo>baz</foo><foo>qux</foo>',
"tag with multiple children";
is $auto->tag( tag => 'foo', attr => { col => [1..3] }, cdata => [qw(one two three four)] ),
'<foo col="1">one</foo><foo col="2">two</foo><foo col="3">three</foo><foo col="1">four</foo>',
"tag with multiple children and rotating attributes";
is $auto->tag( tag => 'bar', cdata => { tag => 'foo', attr => { col => [1..3] }, cdata => [qw(one two three four)] } ),
'<bar><foo col="1">one</foo><foo col="2">two</foo><foo col="3">three</foo><foo col="1">four</foo></bar>',
"nested tag with multiple children and rotating attributes";
t/01-indentation.t view on Meta::CPAN
use warnings FATAL => 'all';
use Test::More tests => 7;
use_ok 'HTML::AutoTag';
my $auto = HTML::AutoTag->new( indent => ' ' );
is $auto->tag( tag => 'foo' ),
"<foo />\n",
"correct indentation for closed tag";
is $auto->tag( tag => 'foo', cdata => 'bar' ),
"<foo>bar</foo>\n",
"correct indentation for tag with scalar cdata";
is $auto->tag( tag => 'foo', cdata => [qw(bar baz qux)] ),
"<foo>bar</foo>
<foo>baz</foo>
<foo>qux</foo>
",
"correct indentation for tag with array ref cdata";
is $auto->tag( tag => 'foo', cdata => { tag => 'bar' } ),
"<foo>
<bar />
</foo>
",
"correct indentation for tag with empty tag cdata";
is $auto->tag( tag => 'bar', cdata => { tag => 'foo', attr => { col => [1..3] }, cdata => [qw(one two three four)] } ),
'<bar>
<foo col="1">one</foo>
<foo col="2">two</foo>
<foo col="3">three</foo>
<foo col="1">four</foo>
</bar>
',
"correct indentation for cdata as array ref";
is $auto->tag(
tag => 'bar',
cdata => {
tag => 'foo',
cdata => [ map { tag => 'bar', }, 1.. 4 ]
}
), '<bar>
<foo>
<bar />
<bar />
<bar />
<bar />
</foo>
</bar>
',
"correct indentation for cdata as hash ref";
t/02-list.t view on Meta::CPAN
use warnings FATAL => 'all';
use Test::More tests => 1;
use HTML::AutoTag;
my $auto = HTML::AutoTag->new( indent => ' ' );
my %attr = ( class => [qw(odd even)] );
my @data = qw( one two three four five six seven eight );
is $auto->tag(
tag => 'ol',
cdata => [
map { tag => 'li', attr => \%attr, cdata => $_ }, @data
]
), '<ol>
<li class="odd">one</li>
<li class="even">two</li>
<li class="odd">three</li>
<li class="even">four</li>
<li class="odd">five</li>
<li class="even">six</li>
<li class="odd">seven</li>
<li class="even">eight</li>
t/03-table.t view on Meta::CPAN
use Test::More tests => 1;
use HTML::AutoTag;
my $auto = HTML::AutoTag->new( indent => ' ' );
my %tr_attr = ( class => [qw(odd even)] );
is $auto->tag(
tag => 'table',
attr => { class => 'spreadsheet' },
cdata => [
{
tag => 'tr',
attr => \%tr_attr,
cdata => {
tag => 'td',
attr => { style => { color => [qw(red green)] } },
cdata => [qw(one two three four five six)],
},
},
{
tag => 'tr',
attr => \%tr_attr,
cdata => {
tag => 'td',
attr => { style => { color => [qw(red green)] } },
cdata => [qw(seven eight nine ten eleven twelve)],
},
},
{
tag => 'tr',
attr => \%tr_attr,
cdata => {
tag => 'td',
attr => { style => { color => [qw(red green)] } },
cdata => [qw(thirteen fourteen fifteen sixteen seventeen eighteen)],
},
},
]
), '<table class="spreadsheet">
<tr class="odd">
<td style="color: red">one</td>
<td style="color: green">two</td>
<td style="color: red">three</td>
<td style="color: green">four</td>
<td style="color: red">five</td>
t/04-deep-nest.t view on Meta::CPAN
use strict;
use warnings FATAL => 'all';
use Test::More tests => 1;
use HTML::AutoTag;
my $auto = HTML::AutoTag->new( indent => ' ' );
is $auto->tag(
tag => 'aaa',
cdata => {
tag => 'bbb',
cdata => {
tag => 'ccc',
cdata => {
tag => 'ddd',
cdata => {
tag => 'eee',
cdata => {
tag => 'fff',
cdata => {
tag => 'ggg',
cdata => {
tag => 'hhh',
cdata => ':D',
}
}
}
}
}
}
}
), '<aaa>
<bbb>
<ccc>
t/05-encodes.t view on Meta::CPAN
#!perl -T
use 5.006;
use strict;
use warnings FATAL => 'all';
use Test::More tests => 8;
use HTML::AutoTag;
my $auto = HTML::AutoTag->new();
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
'<foo><bar baz="qux"></foo>',
"encodes turned off by default";
$auto = HTML::AutoTag->new( encode => 1 );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
'<foo><bar baz="qux"></foo>',
"setting encode to true encodes default chars";
$auto = HTML::AutoTag->new( encode => 1, encodes => '' );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
'<foo><bar baz="qux"></foo>',
"setting encodes to '' with encode set to true encodes default";
$auto = HTML::AutoTag->new( encode => 1, encodes => undef );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
'<foo><bar baz="qux"></foo>',
"setting encodes to undef with encode set to true encodes default";
$auto = HTML::AutoTag->new( encodes => 0 );
is $auto->tag( tag => 'foo', cdata => '<bar baz="0">' ),
'<foo><bar baz="0"></foo>',
"encodes turned on for character 0";
$auto = HTML::AutoTag->new( encodes => '<=' );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
'<foo><bar baz="qux"></foo>',
"encodes turned on for specific chars";
$auto = HTML::AutoTag->new( encode => 0, encodes => '<=' );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
'<foo><bar baz="qux"></foo>',
"encodes turned off when encode is 0";
$auto = HTML::AutoTag->new( encode => '', encodes => '<=' );
is $auto->tag( tag => 'foo', cdata => '<bar baz="qux">' ),
'<foo><bar baz="qux"></foo>',
"encodes turned off when encode is ''";
t/10-tagset.t view on Meta::CPAN
( keys %HTML::Tagset::isHeadOrBodyElement ),
( keys %HTML::Tagset::isKnown ),
);
%containers = map { $_ => undef } @containers;
}
my $auto = HTML::AutoTag->new( indent => '', sorted => 1 );
my @given;
push @given, $auto->tag( tag => $_ ) for sort keys %empty;
push @given, $auto->tag( tag => $_, cdata => '' ) for sort keys %containers;
for (sort keys %HTML::Tagset::linkElements) {
my $attr = { map { $_ => 'value' } @{ $HTML::Tagset::linkElements{$_} } };
push @given, $auto->tag( tag => $_, attr => $attr, cdata => '' );
}
for (sort keys %HTML::Tagset::boolean_attr) {
my $thingy = $HTML::Tagset::boolean_attr{$_};
my $attr = ref($thingy) eq 'HASH' ? $thingy : { $thingy => 1 };
push @given, $auto->tag( tag => $_, attr => $attr, cdata => '' );
}
for (sort @given) {
chomp( $_ );
is "$_\n", <DATA>, "correctly formed: $_";
}
__DATA__
<a href="value"></a>
<a></a>
use warnings FATAL => 'all';
use Test::More tests => 1;
use HTML::AutoTag;
my $auto = HTML::AutoTag->new( sorted => 1 );
is $auto->tag(
tag => 'svg',
attr => { width=>"12cm", height=>"4cm", viewBox=>"0 0 1200 400", xmlns=>"http://www.w3.org/2000/svg", version=>"1.1" },
cdata => [
{
tag => 'desc',
cdata => 'Example circle01 - circle filled with red and stroked with blue',
},
{
tag => 'rect',
attr => { x=>"1", y=>"1", width=>"1198", height=>"398", fill=>"none", stroke=>"blue", 'stroke-width'=>"2" },
},
{
tag => 'circle',
attr => { cx=>"600", cy=>"200", r=>"100", fill=>"red", stroke=>"blue", 'stroke-width'=>"10" },
},
]
( run in 1.399 second using v1.01-cache-2.11-cpan-e1769b4cff6 )