XML-Hash-XS

 view release on metacpan or  search on metacpan

MANIFEST  view on Meta::CPAN

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

README  view on Meta::CPAN

            # 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

src/xh.c  view on Meta::CPAN

    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;
    }

src/xh.c  view on Meta::CPAN

                    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)) {

src/xh.h  view on Meta::CPAN

    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',
    ;
}
{

t/06-x2h.t  view on Meta::CPAN

        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>



( run in 0.856 second using v1.01-cache-2.11-cpan-454fe037f31 )