view release on metacpan or search on metacpan
src/XS.xs
t/00-load.t
t/01-h2x.t
t/02-h2d.t
t/03-h2x-oop.t
t/04-h2x-lx.t
t/05-h2d-lx.t
t/06-x2h.t
t/07-x2h_filter.t
t/08-x2h_trim.t
t/09-x2h_cdata.t
t/10-x2h_encode.t
t/11-x2h_read.t
t/12-x2h_ref.t
t/13-x2h_force_array.t
t/14-x2h_merge_text.t
t/15-x2h_doctype.t
t/16-x2h_suppress_empty.t
t/17-x2h_stylesheet.t
t/test.xml
t/test_cp1251.xml
# 222
# 333
method [ = 'NATIVE' ] *# hash2xml*
experimental support the conversion methods other libraries
if method is 'LX' then conversion result is the same as using
XML::Hash::LX library
Note: for 'LX' method following additional options are available:
attr cdata text comm
OBJECT SERIALISATION(hash2xml)
1. When object has a "toString" method
In this case, the <toString> method of object is invoked in scalar
context. It must return a single scalar that can be directly encoded
into XML.
Example:
use XML::LibXML;
lib/XML/Hash/XS.pm view on Meta::CPAN
use vars qw($VERSION @EXPORT @EXPORT_OK);
use base 'Exporter';
@EXPORT_OK = @EXPORT = qw( hash2xml xml2hash );
$VERSION = '0.64';
require XSLoader;
XSLoader::load('XML::Hash::XS', $VERSION);
use vars qw($method $output $root $version $encoding $utf8 $indent $canonical
$use_attr $content $xml_decl $doc $max_depth $attr $text $trim $cdata
$comm $buf_size $keep_root $force_array $force_content $merge_text
$suppress_empty
);
# 'NATIVE' or 'LX'
$method = 'NATIVE';
# native options
$output = undef;
$root = 'root';
lib/XML/Hash/XS.pm view on Meta::CPAN
$buf_size = 4096;
$trim = 0;
$force_array = undef;
$force_content = 0;
$merge_text = 0;
$suppress_empty = 0;
# XML::Hash::LX options
$attr = '-';
$text = '#text';
$cdata = undef;
$comm = undef;
1;
__END__
=head1 NAME
XML::Hash::XS - Simple and fast hash to XML and XML to hash conversion written in C
=begin HTML
lib/XML/Hash/XS.pm view on Meta::CPAN
# 333
=item method [ = 'NATIVE' ] I<# hash2xml>
experimental support the conversion methods other libraries
if method is 'LX' then conversion result is the same as using L<XML::Hash::LX> library
Note: for 'LX' method following additional options are available:
attr
cdata
text
comm
=back
=head1 OBJECT SERIALISATION(hash2xml)
=over 2
=item 1. When object has a "toString" method
XH_PARAM_READ_INT (opts->buf_size, "XML::Hash::XS::buf_size", XH_DEF_BUF_SIZE);
XH_PARAM_READ_PATTERN(opts->force_array, "XML::Hash::XS::force_array", XH_DEF_FORCE_ARRAY);
XH_PARAM_READ_BOOL (opts->force_content, "XML::Hash::XS::force_content", XH_DEF_FORCE_CONTENT);
XH_PARAM_READ_BOOL (opts->merge_text, "XML::Hash::XS::merge_text", XH_DEF_MERGE_TEXT);
/* XML::Hash::LX options */
XH_PARAM_READ_STRING (opts->attr, "XML::Hash::XS::attr", XH_DEF_ATTR);
opts->attr_len = xh_strlen(opts->attr);
XH_PARAM_READ_STRING (opts->text, "XML::Hash::XS::text", XH_DEF_TEXT);
XH_PARAM_READ_BOOL (opts->trim, "XML::Hash::XS::trim", XH_DEF_TRIM);
XH_PARAM_READ_STRING (opts->cdata, "XML::Hash::XS::cdata", XH_DEF_CDATA);
XH_PARAM_READ_STRING (opts->comm, "XML::Hash::XS::comm", XH_DEF_COMM);
/* method */
XH_PARAM_READ_STRING (method, "XML::Hash::XS::method", XH_DEF_METHOD);
if (xh_strcmp(method, XH_CHAR_CAST "LX") == 0) {
opts->method = XH_METHOD_LX;
}
else if (use_attr) {
opts->method = XH_METHOD_NATIVE_ATTR_MODE;
}
xh_param_assign_string(opts->text, v);
break;
}
if (xh_str_equal4(p, 'u', 't', 'f', '8')) {
opts->utf8 = xh_param_assign_bool(v);
break;
}
goto error;
case 5:
if (xh_str_equal5(p, 'c', 'd', 'a', 't', 'a')) {
xh_param_assign_string(opts->cdata, v);
break;
}
goto error;
case 6:
if (xh_str_equal6(p, 'i', 'n', 'd', 'e', 'n', 't')) {
xh_param_assign_int(p, &opts->indent, v);
break;
}
if (xh_str_equal6(p, 'm', 'e', 't', 'h', 'o', 'd')) {
if (!SvOK(v)) {
xh_bool_t merge_text;
xh_int_t suppress_empty;
xh_pattern_t filter;
SV *cb;
/* LX options */
xh_char_t attr[XH_PARAM_LEN];
size_t attr_len;
xh_char_t text[XH_PARAM_LEN];
xh_bool_t trim;
xh_char_t cdata[XH_PARAM_LEN];
xh_char_t comm[XH_PARAM_LEN];
} xh_opts_t;
xh_opts_t *xh_create_opts(void);
void xh_destroy_opts(xh_opts_t *opts);
xh_bool_t xh_init_opts(xh_opts_t *opts);
void xh_parse_param(xh_opts_t *opts, xh_int_t first, I32 ax, I32 items);
void xh_copy_opts(xh_opts_t *dst, xh_opts_t *src);
void *xh_get_obj_param(xh_int_t *nparam, I32 ax, I32 items, char *class);
SV *xh_get_hash_param(xh_int_t *nparam, I32 ax, I32 items);
src/xh_dom.h view on Meta::CPAN
(void) xmlAddChild(rootNode, xmlNewDocComment(rootNode->doc, BAD_CAST content));
content[content_len] = ch;
}
else {
(void) xmlAddChild(rootNode, xmlNewDocComment(rootNode->doc, BAD_CAST content));
}
}
XH_INLINE void
xh_dom_new_cdata(xh_h2x_ctx_t *ctx, xmlNodePtr rootNode, SV *value)
{
xh_char_t *content;
size_t content_len;
STRLEN str_len;
if (value == NULL) {
content = XH_EMPTY_STRING;
content_len = 0;
}
else {
src/xh_h2x_lx.c view on Meta::CPAN
xh_xml_write_end_node(&ctx->writer, key, key_len);
}
XH_INLINE void
_xh_h2x_lx(xh_h2x_ctx_t *ctx, xh_char_t *key, I32 key_len, SV *value, xh_int_t flag)
{
xh_uint_t type;
value = xh_h2x_resolve_value(ctx, value, &type);
if (ctx->opts.cdata[0] != '\0' && xh_strcmp(key, ctx->opts.cdata) == 0) {
if (flag & XH_H2X_F_ATTR_ONLY || !(type & XH_H2X_T_SCALAR)) return;
xh_xml_write_cdata(&ctx->writer, value);
}
else if (ctx->opts.text[0] != '\0' && xh_strcmp(key, ctx->opts.text) == 0) {
if (flag & XH_H2X_F_ATTR_ONLY || !(type & XH_H2X_T_SCALAR)) return;
xh_xml_write_content(&ctx->writer, value);
}
else if (ctx->opts.comm[0] != '\0' && xh_strcmp(key, ctx->opts.comm) == 0) {
if (flag & XH_H2X_F_ATTR_ONLY) return;
if (type & XH_H2X_T_SCALAR) {
xh_xml_write_comment(&ctx->writer, value);
src/xh_h2x_lx.c view on Meta::CPAN
xh_h2d_lx(ctx, rootNode, value, key, key_len, XH_H2X_F_NONE);
}
XH_INLINE void
_xh_h2d_lx(xh_h2x_ctx_t *ctx, xmlNodePtr rootNode, xh_char_t *key, I32 key_len, SV *value, xh_int_t flag)
{
xh_uint_t type;
value = xh_h2x_resolve_value(ctx, value, &type);
if (ctx->opts.cdata[0] != '\0' && xh_strcmp(key, ctx->opts.cdata) == 0) {
if (flag & XH_H2X_F_ATTR_ONLY || !(type & XH_H2X_T_SCALAR)) return;
xh_dom_new_cdata(ctx, rootNode, value);
}
else if (ctx->opts.text[0] != '\0' && xh_strcmp(key, ctx->opts.text) == 0) {
if (flag & XH_H2X_F_ATTR_ONLY || !(type & XH_H2X_T_SCALAR)) return;
xh_dom_new_content(ctx, rootNode, value);
}
else if (ctx->opts.comm[0] != '\0' && xh_strcmp(key, ctx->opts.comm) == 0) {
if (flag & XH_H2X_F_ATTR_ONLY) return;
if (!type) {
xh_dom_new_comment(ctx, rootNode, NULL);
src/xh_x2h.c view on Meta::CPAN
END(STYLESHEET_PI_ATTR)
goto INVALID_XML;
END10(STYLESHEET_PI, INVALID_XML)
goto INVALID_XML;
EXPECT_ANY("wrong character")
goto INVALID_XML;
END(XML_DECL_ATTR)
goto INVALID_XML;
END3(XML_DECL, INVALID_XML)
goto INVALID_XML;
EXPECT_CHAR("comment or cdata or doctype", '!')
flags &= ~XH_X2H_TEXT_NODE;
END_OF_TEXT(TEXT_BEFORE_COMMENT, content, end - content)
DO(XML_COMMENT_NODE_OR_CDATA)
EXPECT_CHAR("comment", '-')
PARSE_COMMENT
EXPECT_CHAR("cdata", '[')
if (ctx->opts.trim) {
PARSE_CDATA_WITH_TRIM
;
}
else {
PARSE_CDATA
;
}
EXPECT_CHAR("doctype", 'D')
PARSE_DOCTYPE
src/xh_xml.h view on Meta::CPAN
XH_BUFFER_WRITE_CHAR4(buf, "<!--")
XH_BUFFER_WRITE_LONG_STRING(buf, content, content_len);
XH_BUFFER_WRITE_CHAR3(buf, "-->")
if (writer->indent) {
XH_BUFFER_WRITE_CHAR(buf, '\n')
}
}
XH_INLINE void
xh_xml_write_cdata(xh_writer_t *writer, SV *value)
{
size_t indent_len;
xh_perl_buffer_t *buf;
xh_char_t *content;
size_t content_len;
STRLEN str_len;
buf = &writer->main_buf;
if (value == NULL) {
t/04-h2x-lx.t view on Meta::CPAN
'trim 1',
;
is
hash2xml( { root => " \t\ntest" }, trim => 0 ),
qq{$xml_decl<root> \t\ntest</root>},
'trim 0',
;
}
{
is
hash2xml( { root => { sub => { '@' => "cdata < > & \" \t \n \r end" } } }, cdata => '@' ),
qq{$xml_decl<root><sub><![CDATA[cdata < > & \" \t \n \r end]]></sub></root>},
'cdata @',
;
}
{
is
hash2xml( { root => { sub => { '/' => "comment < > & \" \t \n \r end" } } },comm => '/' ),
qq{$xml_decl<root><sub><!--comment < > & \" \t \n \r end--></sub></root>},
'comm /',
;
}
{
is
hash2xml( { root => { -attr => undef } } ),
qq{$xml_decl<root attr=""></root>},
'empty attr',
;
}
{
is
hash2xml( { root => { '#cdata' => undef } }, cdata => '#cdata' ),
qq{$xml_decl<root></root>},
'empty cdata',
;
}
{
is
hash2xml( { root => { '/' => undef } }, comm => '/' ),
qq{$xml_decl<root><!----></root>},
'empty comment',
;
}
{
t/05-h2d-lx.t view on Meta::CPAN
'trim 1',
;
is
fix_xml $c->hash2xml( { root => " \t\ntest" }, trim => 0 )->toString(),
qq{$xml_decl<root> \t\ntest</root>},
'trim 0',
;
}
{
is
fix_xml $c->hash2xml( { root => { sub => { '@' => "cdata < > & \" \t \n \r end" } } }, cdata => '@' )->toString(),
qq{$xml_decl<root><sub><![CDATA[cdata < > & \" \t \n \r end]]></sub></root>},
'cdata @',
;
}
{
is
fix_xml $c->hash2xml( { root => { sub => { '/' => "comment < > & \" \t \n \r end" } } },comm => '/' )->toString(),
qq{$xml_decl<root><sub><!--comment < > & \" \t \n \r end--></sub></root>},
'comm /',
;
}
{
is
fix_xml $c->hash2xml( { root => { -attr => undef, '#text' => 'text' } } )->toString(),
qq{$xml_decl<root attr="">text</root>},
'empty attr',
;
}
{
is
fix_xml $c->hash2xml( { root => { '#cdata' => undef, '#text' => 'text' } }, cdata => '#cdata' )->toString(),
qq{$xml_decl<root>text</root>},
'empty cdata',
;
}
{
is
fix_xml $c->hash2xml( { root => { '/' => undef } }, comm => '/' )->toString(),
qq{$xml_decl<root><!----></root>},
'empty comment',
;
}
{
content2
</node3>
<node4>
content1
<empty_node4/>
content2
</node4>
<item>1</item>
<item>2</item>
<item>3</item>
<cdata><![CDATA[
abcde!@#$%^&*<>
]]></cdata>
<cdata2><![CDATA[ abc ]]]></cdata2>
<cdata3><![CDATA[ [ abc ] ]> ]]]]]]></cdata3>
</root>
XML
Dumper({
root => {
attr1 => '1',
attr2 => '2',
cdata => 'abcde!@#0^&*<>',
cdata2 => 'abc ]',
cdata3 => '[ abc ] ]> ]]]]',
item => ['1', '2', '3'],
node1 => 'value1',
node2 => {
attr1 => '1',
text => 'value2',
},
node3 => ['content1', 'content2'],
node4 => {
text => ['content1', 'content2'],
empty_node4 => '',
t/08-x2h_trim.t view on Meta::CPAN
'boom',
'ignore leading white spaces',
;
}
{
is
Dumper(xml2hash(<<"XML", keep_root => 1)),
$xml_decl_utf8
<root>
<cdata1> <![CDATA[\n\t cdata1\n\t ]]> </cdata1>
<cdata2> <![CDATA[ ]]> </cdata2>
<text> text\n \n</text>
</root>
XML
Dumper({
root => {
cdata1 => "\n\t cdata1\n\t ",
cdata2 => " ",
text => " text\n \n",
},
}),
'if the trim is off',
;
}
{
is
Dumper(xml2hash(<<"XML", keep_root => 1, trim => 1)),
$xml_decl_utf8
<root>
<cdata1> <![CDATA[\n\t cdata1\n\t ]]> </cdata1>
<cdata2> <![CDATA[ ]]> </cdata2>
<text> text\n \n</text>
</root>\r\n
XML
Dumper({
root => {
cdata1 => 'cdata1',
cdata2 => '',
text => 'text',
},
}),
'if the trim is on',
;
}
{
is
Dumper(xml2hash(<<"XML", trim => 1)),
t/09-x2h_cdata.t view on Meta::CPAN
$Data::Dumper::Indent = 0;
$Data::Dumper::Sortkeys = 1;
use XML::Hash::XS 'xml2hash';
$XML::Hash::XS::keep_root = 0;
our $xml_decl_utf8 = qq{<?xml version="1.0" encoding="utf-8"?>};
{
is
xml2hash("<cdata><![CDATA[\n\t abcde!@#\$%^&*<>\n\t ]]></cdata>"),
"\n\t abcde!\@#\$%^&*<>\n\t ",
'use special symbols',
;
}
{
is
xml2hash("<cdata><![CDATA[ [ abc ] ]> ]]]]]]></cdata>"),
' [ abc ] ]> ]]]]',
'terminate section',
;
}
{
is
xml2hash("<cdata><![CDATA[ ]]]></cdata>"),
' ]',
'terminate section2',
;
}
{
is
xml2hash("<cdata><![CDATA[]]></cdata>"),
'',
'empty section',
;
}
t/14-x2h_merge_text.t view on Meta::CPAN
is
Dumper(xml2hash(<<"XML", merge_text => 1, keep_root => 1)),
<?xml version="1.0" encoding="utf-8"?>
<root>
<![CDATA[Hello,]]><![CDATA[ world!\n]]>
</root>
XML
Dumper({
'root' => "Hello, world!\n"
}),
'merge cdata',
;
}
{
is
Dumper(xml2hash(<<"XML", merge_text => 1, keep_root => 1)),
<?xml version="1.0" encoding="utf-8"?>
<root>
<value><![CDATA[Hello,]]></value>
<value><![CDATA[ world!\n]]></value>