XML-Hash-XS-0.66/ 0000755 0001750 0001750 00000000000 15235614141 012042 5 ustar yura yura XML-Hash-XS-0.66/Changes 0000644 0001750 0001750 00000014671 15235610240 013342 0 ustar yura yura Revision history for perl module XML::Hash::XS
0.66 2026-08-08
- Fix build on Solaris and illumos, where iconv() declares the input
buffer as "const char **".
0.65 2026-08-05
- Add incremental XML parsing with Parser->feed/finish.
- Add callback STOP/SKIP controls and event callback mode.
- Add streaming hash2xml output_cb callback.
- Fix option and output filehandle ownership in OOP converters.
- Add boundary, callback, and memory-safety regression tests.
- Fix build with perl older than 5.22, where xsubpp failed to find the typemap.
- Fix memory leak of the sorted hash when a callback dies in canonical mode.
- Add GitHub Actions CI.
0.64 2025-01-01
- Fix for Sparc64.
0.63 2024-12-29
- Fix for OpenBSD.
- Fix for MSVC.
0.62 2024-12-28
- Fix for Win32.
0.61 2024-12-27
- Another fix for big endian.
0.60 2024-12-24
- Another fix for big endian.
0.59 2024-12-21
- Fix typo
0.58 2024-12-20
- Fix for big endian architecture
0.57 2024-09-27
- Use "keep_root" option to generate XML via "hash2xml"
- Change default value of "keep_root" option to "1"
0.56 2021-02-14
- Fix XML parsing with file handle
- Thanks to Rory Zweistra for report
- Fix case of "XML::Simple" in docs
- Thanks to Anirvan Chatterjee for help
0.55 2020-03-03
- Parse "xml-stylesheet" processing instruction
0.54 2019-12-28
- Add "SuppressEmpty" option
0.53 2018-08-31
- Don't trim spaces on text node when "trim" option is off
- Thanks to Tudor Marghidanu for report
0.52 2018-03-25
- Implement searilization of objects with overloaded stringification
- Thanks to Slobodan Mišković for advice
0.51 2017-08-28
- Add partial support for DTD
0.50 2017-03-16
- Fix documentation typo
0.49 2017-03-16
- Fix encoder error handling
- Thanks to Ben Bullock for report
0.48 2017-03-15
- Don't merge text from different nodes
0.47 2017-02-18
- The "trim" option now is used while conversion of xml to hash
- Thanks to Useperl for report
0.46 2017-01-28
- Fix bug occurs while using multiple job compile
- Fix configure error on OpenBSD: No library found for -liconv
0.45 2017-01-19
- Fix incorrect folding of arrays in LX mode
- Thanks to Nigelm for report
0.44 2016-06-09
- Fix bug with null-terminated xml
- Thanks to Zdm for report
0.43 2015-07-15
- Fix memory allocation bug
- Thanks to Jeffrey Ryan Thalhammer for report
0.42 2015-05-08
- Improved fix for OpenBSD/NetBSD
0.41 2015-04-30
- Fix bug in parsing entity references
0.40 2015-04-30
- Fix memory allocation bug
- Thanks to Phillup for report
- Fix compilation on OpenBSD/NetBSD
0.39 2015-04-28
- Improved XML detection
- Thanks to Phillup for report
0.38 2015-04-21
- New options "filter" and "cb"
- Fix some memory leaks bugs
- Fix compilation errors with using -Wextra
0.37 2015-04-14
- Fix broken archive
0.36 2015-04-14
- Fix bug with use force_array option
- Thanks to Dmytro Zagashev for report
- New option "force_content"
- New option "merge_text"
0.35 2015-04-13
- Fix bug with regexp on perl 5.8.X
0.34 2015-04-12
- Fix bug when many contents in one node
0.33 2015-04-12
- Fix bug when many contents in one node
- New option "force_array"
0.32 2015-03-28
- Revamped Makefile.PL
- Add resources to META_MERGE
- Add prereqs to META_ADD
- Replace bugtracker to github
- Added author tests
0.31 2015-03-25
- Fix xml parsing failure when CR symbol found after xml declaration
- https://rt.cpan.org/Ticket/Display.html?id=103002
- Thanks to Dmytro Zagashev for report
0.30 2015-03-23
- Fix params validation failure
- https://rt.cpan.org/Ticket/Display.html?id=102992
- Thanks to Dmytro Zagashev for report
0.29 2015-01-30
- Fix segmentation fault on test for tied handle
0.28 2015-01-14
- Fix test for tied handle
- Fix compilation failure on Haiku OS
0.27 2015-01-14
- Added feature conversion of xml to hash
0.26 2014-03-13
- Fix compilation failure on some OS
- Fix compilation failure when using libiconv with MinGW
- Fix segmentation fault when using XML::LibXML
0.25 2014-03-11
- Added possibility object serialization using methods "toString" and "iternext"
- Fixed docs and other minor fixes
0.24 2014-01-17
- Fix overriding CCFLAGS when passed to WriteMakefile
0.23 2014-01-15
- Mass refactoring, fix many bugs and add some tests
0.22 2013-07-20
- Using XML::LibXML library is optional now
- Fix some tests
0.21 2013-07-16
- Fixed #include error
0.20 2013-07-14
- Fix bug when conv_writer_t has no member named encoder
- Fix 02-conv-lx.t test
0.19 2013-07-08
- Fix segmentation fault when value=undef and use_attr=1
- Set utf8 flag for result string
0.18 2013-04-14
- Fix segmentation fault
- Skip encoding tests if encoding is not supported
0.17 2013-03-22
- Fix bug with invalid stack pointer
0.16 2013-03-19
- New option "doc"
0.15 2013-03-17
- Modify for directly using of Iconv and ICU libs
0.14 2013-03-13
- Fixed bug with memory allocation
0.13 2013-03-09
- Implemented OO interface
0.12_01 2013-03-07
- Added benchmark results
0.12 2013-03-06
- Added experimental support the conversion method
of the XML::Hash::LX library
0.11 2013-03-02
- Fix for compatibility with version 2.9.0 library libxml2
0.10 2012-04-19
- New option "xml_decl".
0.09 2012-04-12
- New option "content"
0.08 2012-04-10
- Fix build error when using perl < 5.10
0.07 2012-04-07
- Fix memory leak
0.06 2012-04-06
- New options "canonical" and "use_attr"
0.05_03 2012-04-02
- Fix bug with ppport.h
0.05_02 2012-04-02
- Added ppport.h
- No more using Scalar::Util
0.05_01 2012-03-26
- Fix conv.t test
0.05 2012-03-25
- Fix build error on FreeBSD
0.04 2012-03-24
- Updated Makefile.PL
0.03_01 2012-02-28
- Added META.json
0.03 2012-02-25
- Changed output to a file handle
- Thanks to Cono
0.02 2012-02-15
- Increased performance by 2.5 times via direct conversion to a string without creating a DOM
0.01 2012-02-12
- First version
XML-Hash-XS-0.66/LICENSE 0000644 0001750 0001750 00000002062 14732550202 013045 0 ustar yura yura MIT License
Copyright (c) 2024 Yurii Ustiushenko
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
XML-Hash-XS-0.66/benchmark/ 0000755 0001750 0001750 00000000000 15235614140 013773 5 ustar yura yura XML-Hash-XS-0.66/benchmark/benchmark.pl 0000755 0001750 0001750 00000003166 13177671425 016307 0 ustar yura yura #!/usr/bin/env perl
use FindBin;
use lib ("$FindBin::Bin/../blib/lib", "$FindBin::Bin/../blib/arch");
use LWP::Simple 'get';
use XML::Hash::LX;
use XML::Hash;
use XML::Simple;
use XML::LibXML;
use XML::Hash::XS qw();
use Benchmark qw(:all);
use XML::Bare;
my $xml_converter = XML::Hash->new();
my $xml = getXml();
my $xh_hash = $xml_converter->fromXMLStringtoHash($xml);
my $lx_hash = xml2hash($xml);
my $xs_hash = XMLin($xml);
my $xs_conv = XML::Hash::XS->new();
print "\nHash to XML:\n";
cmpthese -3, {
'XML::Hash' => sub {
my $oxml = $xml_converter->fromHashtoXMLString($xh_hash);
},
'XML::Simple' => sub {
my $oxml = XMLout($xs_hash);
},
'XML::Hash::LX' => sub {
my $oxml = hash2xml($lx_hash);
},
'XML::Hash::XS' => sub {
my $oxml = XML::Hash::XS::hash2xml($xs_hash);
},
};
print "\nXML to Hash:\n";
cmpthese -3, {
# 'XML::Hash' => sub {
# my $oxml = $xml_converter->fromXMLStringtoHash($xh_hash);
# },
'XML::Simple' => sub {
my $oxml = XMLin($xml);
},
'XML::Hash::LX' => sub {
my $oxml = hash2xml($lx_hash);
},
'XML::Hash::XS' => sub {
my $oxml = XML::Hash::XS::xml2hash($xml);
},
'XML::Bare' => sub {
my $oxml = XML::Bare->new(text => $xml)->parse();
},
};
sub getXml {
my $fn = "$FindBin::Bin/uploads.rdf";
open my $f, '<',$fn or return do {
warn "Fetching file\n";
my $data = get 'http://search.cpan.org/uploads.rdf';
open my $fo, '>', $fn;
print $fo $data;
close $fo;
$data;
};
warn "Have preloaded file\n";
local $/;
<$f>
}
XML-Hash-XS-0.66/t/ 0000755 0001750 0001750 00000000000 15235614140 012304 5 ustar yura yura XML-Hash-XS-0.66/t/22-h2x-output-cb.t 0000644 0001750 0001750 00000011754 15234655553 015357 0 ustar yura yura package main;
use strict;
use warnings;
use Test::More 0.98;
use Scalar::Util qw(weaken);
use XML::Hash::XS qw(hash2xml);
my %data = (
alpha => 'one',
beta => [ map { "value-$_" } 1 .. 20 ],
);
my $expected = hash2xml(\%data, canonical => 1, buf_size => 32);
{
my @chunks;
my @argc;
my $result = hash2xml(
\%data,
canonical => 1,
buf_size => 32,
output_cb => sub {
push @argc, scalar @_;
push @chunks, $_[0];
},
);
is($result, undef, 'callback output returns undef');
cmp_ok(scalar @chunks, '>', 1, 'small buffer produces multiple chunks');
is(join('', @chunks), $expected, 'chunks contain the complete XML document');
is_deeply(\@argc, [ (1) x @argc ], 'callback receives exactly one argument');
}
{
my @weak_chunks;
hash2xml(
\%data,
canonical => 1,
buf_size => 8,
output_cb => sub {
push @weak_chunks, \$_[0];
weaken($weak_chunks[-1]);
},
);
ok(!grep(defined, @weak_chunks), 'unretained callback chunks are released immediately');
}
{
my @chunks;
hash2xml(
{ value => 'abcdef' },
xml_decl => 0,
buf_size => 4,
output_cb => sub {
push @chunks, $_[0];
$_[0] = 'changed';
},
);
isnt(join('', @chunks), 'changed', 'callback receives stable independent chunks');
is(join('', @chunks), 'abcdef', 'mutating callback argument does not alter output');
}
{
my @chunks;
my $converter;
my $weak;
{
my $callback = sub { push @chunks, $_[0] };
$weak = $callback;
weaken($weak);
$converter = XML::Hash::XS->new(
xml_decl => 0,
output_cb => $callback,
);
}
ok(defined $weak, 'object retains output callback');
is($converter->hash2xml({ item => 'value' }), undef, 'OOP callback output returns undef');
is(join('', @chunks), '- value
', 'OOP callback receives XML');
undef $converter;
ok(!defined $weak, 'object releases output callback');
}
{
my $calls = 0;
my $error;
eval {
hash2xml(
\%data,
canonical => 1,
buf_size => 8,
output_cb => sub {
++$calls;
die "output callback failed\n";
},
);
};
$error = $@;
like($error, qr/^output callback failed/, 'callback exception is propagated');
is($calls, 1, 'failing callback is not called again during cleanup');
}
{
my $error;
eval { hash2xml({}, output_cb => 'not a callback') };
$error = $@;
like($error, qr/Parameter 'output_cb' is not CODE reference/, 'output_cb must be a code reference');
}
{
open(my $fh, '>', \my $output) or die "Can't open scalar filehandle: $!";
my $error;
eval { hash2xml({}, output => $fh, output_cb => sub {}) };
$error = $@;
like($error, qr/mutually exclusive/, 'output and output_cb cannot be combined');
}
{
my @utf8_chunks;
hash2xml(
{ text => "\x{410}\x{411}" },
xml_decl => 0,
utf8 => 1,
buf_size => 4,
output_cb => sub { push @utf8_chunks, $_[0] },
);
ok(!grep(!utf8::is_utf8($_), @utf8_chunks), 'callback chunks carry the UTF-8 flag');
my @byte_chunks;
hash2xml(
{ text => "\x{410}\x{411}" },
xml_decl => 0,
utf8 => 0,
buf_size => 4,
output_cb => sub { push @byte_chunks, $_[0] },
);
ok(!grep(utf8::is_utf8($_), @byte_chunks), 'utf8 => 0 returns byte chunks');
}
SKIP: {
my $encoded = eval {
hash2xml(
{ text => "\x{410}\x{411}" },
canonical => 1,
encoding => 'cp1251',
utf8 => 0,
buf_size => 4096,
);
};
skip 'external encoding support is not available', 3 if $@;
my @chunks;
hash2xml(
{ text => "\x{410}\x{411}" },
canonical => 1,
encoding => 'cp1251',
utf8 => 0,
buf_size => 4,
output_cb => sub { push @chunks, $_[0] },
);
is(join('', @chunks), $encoded, 'callback receives externally encoded chunks');
my $calls = 0;
my $error;
eval {
hash2xml(
\%data,
canonical => 1,
encoding => 'cp1251',
utf8 => 0,
buf_size => 4,
output_cb => sub {
++$calls;
die "encoded callback failed\n";
},
);
};
$error = $@;
like($error, qr/^encoded callback failed/, 'encoded callback exception is propagated');
is($calls, 1, 'failing encoded callback is not retried during cleanup');
}
{
my @chunks;
local $XML::Hash::XS::output_cb = sub { push @chunks, $_[0] };
my $result = hash2xml({ item => 'global' }, xml_decl => 0);
is($result, undef, 'global output_cb returns undef');
is(join('', @chunks), '- global
', 'global output_cb receives XML');
}
done_testing;
XML-Hash-XS-0.66/t/09-x2h_cdata.t 0000644 0001750 0001750 00000001434 14675463631 014574 0 ustar yura yura package main;
use strict;
use warnings;
use Test::More tests => 4;
use Data::Dumper;
$Data::Dumper::Indent = 0;
$Data::Dumper::Sortkeys = 1;
use XML::Hash::XS 'xml2hash';
$XML::Hash::XS::keep_root = 0;
our $xml_decl_utf8 = qq{};
{
is
xml2hash("\n\t ]]>"),
"\n\t abcde!\@#\$%^&*<>\n\t ",
'use special symbols',
;
}
{
is
xml2hash(" ]]]]]]>"),
' [ abc ] ]> ]]]]',
'terminate section',
;
}
{
is
xml2hash(""),
' ]',
'terminate section2',
;
}
{
is
xml2hash(""),
'',
'empty section',
;
}
XML-Hash-XS-0.66/t/04-h2x-lx.t 0000644 0001750 0001750 00000005466 13037760327 014056 0 ustar yura yura
use strict;
use warnings;
use Test::More tests => 15;
use XML::Hash::XS 'hash2xml';
$XML::Hash::XS::method = 'LX';
$XML::Hash::XS::trim = 1;
our $xml_decl = qq{\n};
{
is
hash2xml( { root => { '#text' => ' zzzz ' } } ),
qq{$xml_declzzzz},
'text',
;
}
{
is
hash2xml( { root => { sub => 'test' } } ),
qq{$xml_decltest},
'node',
;
}
{
is
hash2xml( { root => { -attr => "test < > & \" \t \n \r end" } } ),
qq{$xml_decl},
'attr',
;
}
{
is
hash2xml( { root => { _attr => "test" } }, attr => '_' ),
qq{$xml_decl},
'attr _',
;
}
{
is
hash2xml( { root => { '~' => "zzzz < > & \r end" } }, text => '~' ),
qq{$xml_declzzzz < > &
end},
'text ~',
;
}
{
is
hash2xml( { root => " \t\ntest" }, trim => 1 ),
qq{$xml_decltest},
'trim 1',
;
is
hash2xml( { root => " \t\ntest" }, trim => 0 ),
qq{$xml_decl \t\ntest},
'trim 0',
;
}
{
is
hash2xml( { root => { sub => { '@' => "cdata < > & \" \t \n \r end" } } }, cdata => '@' ),
qq{$xml_decl & \" \t \n \r end]]>},
'cdata @',
;
}
{
is
hash2xml( { root => { sub => { '/' => "comment < > & \" \t \n \r end" } } },comm => '/' ),
qq{$xml_decl},
'comm /',
;
}
{
is
hash2xml( { root => { -attr => undef } } ),
qq{$xml_decl},
'empty attr',
;
}
{
is
hash2xml( { root => { '#cdata' => undef } }, cdata => '#cdata' ),
qq{$xml_decl},
'empty cdata',
;
}
{
is
hash2xml( { root => { '/' => undef } }, comm => '/' ),
qq{$xml_decl},
'empty comment',
;
}
{
is
hash2xml( { root => { x=>undef } } ),
qq{$xml_decl},
'empty tag',
;
}
{
is
hash2xml( { root => { item => [1, 2, 3, { -attr => 4, node => 5 }, [6, 7] ] } } ),
qq{$xml_decl- 1
- 2
- 3
- 5
- 6
- 7
},
'array',
;
}
SKIP: {
my $data;
eval { $data = hash2xml( { root => { test => "Тест" } }, encoding => 'cp1251' ) };
my $err = $@;
chomp $err;
skip $err, 1 if $err;
is
$data,
qq{\n\322\345\361\362},
'encoding support',
;
}
XML-Hash-XS-0.66/t/03-h2x-oop.t 0000644 0001750 0001750 00000000771 12307437245 014220 0 ustar yura yura
use strict;
use warnings;
use Test::More tests => 2;
use XML::Hash::XS qw();
our $conv = XML::Hash::XS->new();
our $xml_decl = qq{};
{
is
$conv->hash2xml( { node1 => sub { 'value1' } } ),
qq{$xml_decl\nvalue1},
'code reference',
;
}
{
is
XML::Hash::XS::hash2xml( { node1 => sub { 'value1' } } ),
qq{$xml_decl\nvalue1},
'code reference',
;
}
XML-Hash-XS-0.66/t/17-x2h_stylesheet.t 0000644 0001750 0001750 00000000753 14675463560 015714 0 ustar yura yura package main;
use strict;
use warnings;
use Test::More tests => 1;
use XML::Hash::XS 'xml2hash';
$XML::Hash::XS::keep_root = 0;
{
is
xml2hash('' .
'' .
'' .
'OK'),
"OK",
'simple',
;
}
XML-Hash-XS-0.66/t/test_null_terminated.xml 0000644 0001750 0001750 00000000204 12726250242 017250 0 ustar yura yura