XML-Spice
view release on metacpan or search on metacpan
lib/XML/Spice.pm view on Meta::CPAN
attrs => {},
};
for my $arg (@args) {
if (ref $arg eq "HASH") {
for my $key (keys %$arg) {
if (!defined $arg->{$key}) {
delete $chunk->{attrs}->{$key};
} else {
$chunk->{attrs}->{$key} = "".$arg->{$key};
}
}
}
else {
push @{$chunk->{sub}}, $arg;
}
}
return bless $chunk, "XML::Spice::Chunk";
}
package # hide from PAUSE
XML::Spice::Chunk;
use warnings;
use strict;
use Carp;
use overload
'""' => \&_xml;
my $TIDY_LOADED;
sub _xml {
my ($chunk) = @_;
if ($PRETTY_PRINT && !defined $TIDY_LOADED) {
eval { require XML::Tidy::Tiny };
if ($@) {
carp "Couldn't load XML::Tidy::Tiny: $@";
$TIDY_LOADED = 0;
}
else {
$TIDY_LOADED = 1;
}
}
my $WANT_PRETTY = $PRETTY_PRINT && $TIDY_LOADED;
return $chunk->{cached} if exists $chunk->{cached} && !$WANT_PRETTY;
sub _escape_attr {
my ($val) = @_;
$val =~ s/'/'/g;
return $val;
}
sub _escape_cdata {
my ($val) = @_;
$val =~ s/&/&/g;
$val =~ s/</</g;
$val =~ s/>/>/g;
$val =~ s/"/"/g;
$val =~ s/([^\x20-\x7E])/'&#' . ord($1) . ';'/ge;
return $val;
}
sub _serialise {
my ($chunk, @things) = @_;
my $xml = '';
for my $thing (@things) {
next if ! defined $thing;
if (ref $thing eq "CODE") {
$thing = &{$thing};
if (ref $thing eq "HASH") {
for my $key (keys %$thing) {
if (!defined $thing->{$key}) {
delete $chunk->{attrs}->{$key};
} else {
$chunk->{attrs}->{$key} = "".$thing->{$key};
}
}
undef $thing;
}
redo;
}
if (ref $thing eq "ARRAY") {
$xml .= $chunk->_serialise(@$thing);
}
elsif (ref $thing eq "XML::Spice::Chunk") {
$xml .= $thing->_xml;
}
else {
next if $thing eq "";
$xml .= _escape_cdata($thing);
}
}
return $xml;
}
my $subxml = $chunk->_serialise(@{$chunk->{sub}}) if exists $chunk->{sub};
my $xml = "<" . $chunk->{tag};
for my $attr (keys %{$chunk->{attrs}}) {
$xml .= " $attr='" . _escape_attr($chunk->{attrs}->{$attr}) . "'";
}
if (!defined $subxml) {
$xml .= "/>";
$chunk->{cached} = $xml unless $WANT_PRETTY;
return $WANT_PRETTY ? XML::Tidy::Tiny::xml_tidy($xml) : $xml;
}
$xml .= ">" . $subxml . "</" . $chunk->{tag} . ">";
$chunk->{cached} = $xml unless $WANT_PRETTY;
return $WANT_PRETTY ? XML::Tidy::Tiny::xml_tidy($xml) : $xml;
}
sub forget {
my ($chunk) = @_;
delete $chunk->{cached};
}
1;
__END__
=pod
=encoding UTF-8
=for markdown [](http://travis-ci.org/robn/XML-Spice)
=head1 NAME
XML::Spice - generating XML has never been so Perly!
=head1 SYNOPSIS
use XML::Spice qw(html head title body h1 p a);
print
html(
head(
title("my great page"),
),
body(
h1("my great page"),
p("this is my great page, made with ",
a("spice", { href => "http://en.wikipedia.org/wiki/Spice/" }),
),
( run in 0.551 second using v1.01-cache-2.11-cpan-6aa56a78535 )