XML-Fast

 view release on metacpan or  search on metacpan

Fast.xs  view on Meta::CPAN

#define MODE_ARRAYS  0x4000

typedef struct {
	// config
	unsigned int flags;
	unsigned int bytes;
	unsigned int utf8;
	SV  * attr;
	SV  * text;
	SV  * join;
	SV  * cdata;
	SV  * comm;
	HV  * array;

	// state
	char *encoding;
	SV   *encode;
	int depth;
	unsigned int chainsize;
	xml_node * chain;
	HV ** hchain;

Fast.xs  view on Meta::CPAN


typedef struct {
	// config
	unsigned int flags;
	unsigned int bytes;
	unsigned int utf8;
	
	char  * attr; STRLEN attl;
	char  * text;
	char  * join;
	char  * cdata;
	char  * comm;
	
	
	HV  * array;

	// state
	char *encoding;
	SV   *encode;
	unsigned int chainsize;
	xml_node * chain;

Fast.xs  view on Meta::CPAN

		ctx->textval = 0;
	}
	else {
		//printf("text close, store %s\n",SvPV_nolen(ctx->textval));
		hv_store_a(ctx->hcurrent, ctx->text, ctx->textval);
	}
	ctx->textval = 0;
}


void on_cdata(void * pctx, char * data,unsigned int length) {
#if XML_DEVEL
	if (!pctx) croak("Context not passed to on_cdata");
#endif
	parsestate *ctx = pctx;
	SV *sv   = newSVpvn(data, length);
	xml_sv_decode(ctx,sv);
	hv_store_a(ctx->hcurrent, ctx->cdata, sv );
}

void on_pi_open(void * pctx, char * data, unsigned int length) {
#if XML_DEVEL
	if (!pctx) croak("Context not passed to on_pi_open");
#endif
	parsestate *ctx = pctx;
	ctx->pi = newSVpvn(data,length);
}

Fast.xs  view on Meta::CPAN

	STRLEN  i, nlen;
	
	AV  *av;
	SV **avv;
	
	debug("key=%s, val=%s",key, SvPV_nolen(val));
	if ( mystrcmp( key, p->text ) == 0 ) {
		h2xpe(p, SvPV_nolen( val ));
	}
	else
	if ( mystrcmp( key, p->cdata ) == 0 ) {
		h2xp(p, "<![CDATA[");
		h2xp(p, SvPV_nolen( val ));
		h2xp(p, "]]>");
	}
	else
	if ( p->comm && mystrcmp( key, p->comm) == 0 ) {
		debug("comm: %s", SvPV_nolen( val ));
		h2xp(p, "<!-- ");
		h2xpe(p, SvPV_nolen( val ));
		h2xp(p, " -->");

Fast.xs  view on Meta::CPAN

			if (SvOK(*key) && SvCUR(*key) > 0 ) { // defined and length
				ctx.attr = *key;
			}
		}
		if ((key = hv_fetch(conf, "text", 4, 0)) && SvOK(*key)) {
			ctx.text = *key;
		}
		if ((key = hv_fetch(conf, "join", 4, 0)) && SvPOK(*key)) {
			ctx.join = *key;
		}
		if ((key = hv_fetch(conf, "cdata", 5, 0)) && SvPOK(*key)) {
			ctx.cdata = *key;
		}
		if ((key = hv_fetch(conf, "comm", 4, 0)) && SvPOK(*key)) {
			ctx.comm = *key;
		}
		if ((key = hv_fetch(conf, "array", 5, 0)) && SvOK(*key)) {
			if (SvROK(*key) && SvTYPE( SvRV(*key) ) == SVt_PVAV) {
				AV *av = (AV *) SvRV( *key );
				ctx.array = newHV();
				I32 len = 0, avlen = av_len(av) + 1;
				SV **val;

Fast.xs  view on Meta::CPAN

				//
			} else {
				state.cb.warn         = on_warn;
				ctx.flags |= EMIT_WARNS;
			}
			state.cb.die         = on_die;
			
			if(ctx.comm)
				state.cb.comment      = on_comment;
			
			if(ctx.cdata)
				state.cb.cdata        = on_cdata;
			else if(ctx.text)
				state.cb.cdata        = on_bytes;
			
			state.cb.bytes        = on_bytes;
			state.cb.bytespart    = on_bytes_part;
			state.cb.uchar        = on_uchar;
			
			if (!(ctx.flags & MODE_TRIM))
				state.save_wsp     = 1;
		}
		parse(xml,&state);
		

Fast.xs  view on Meta::CPAN

			ctx.attr = SvPV_nolen(*key);
			// warn ("Set attr to '%s'", ctx.attr);
		} else {
			ctx.attr = "-";
		}
		if ((key = hv_fetch(conf, "text", 4, 0)) && SvPOK(*key)) {
			ctx.text = SvPV_nolen(*key);
		} else {
			ctx.text = "#text";
		}
		if ((key = hv_fetch(conf, "cdata", 5, 0)) && SvPOK(*key)) {
			ctx.cdata = SvPV_nolen(*key);
		} else {
			ctx.cdata = 0;
		}
		if ((key = hv_fetch(conf, "comm", 4, 0)) && SvPOK(*key)) {
			ctx.comm = SvPV_nolen(*key);
		} else {
			ctx.comm = 0;
		}
		/*
		if ((key = hv_fetch(conf, "array", 5, 0)) && SvOK(*key)) {
			if (SvROK(*key) && SvTYPE( SvRV(*key) ) == SVt_PVAV) {
				AV *av = (AV *) SvRV( *key );

README  view on Meta::CPAN

            # default:
            xml2hash( '<item>Test1<sub />Test2</item>' )
            : { item => { sub => '', '~' => 'Test1Test2' } };
    
            xml2hash( '<item>Test1<sub />Test2</item>', join => '+' )
            : { item => { sub => '', '~' => 'Test1+Test2' } };

    trim [ = 1 ]
        Trim leading and trailing whitespace from text nodes

    cdata [ = undef ]
        When defined, CDATA sections will be stored under this key

            # cdata = undef
            <node><![CDATA[ test ]]></node>  =>  { node => 'test' }

            # cdata = '#'
            <node><![CDATA[ test ]]></node>  =>  { node => { '#' => 'test' } }

    comm [ = undef ]
        When defined, comments sections will be stored under this key

        When undef, comments will be ignored

            # comm = undef
            <node><!-- comm --><sub/></node>  =>  { node => { sub => '' } }

lib/XML/Fast.pm  view on Meta::CPAN

XSLoader::load('XML::Fast', $VERSION);

sub xml2hash($;%) {
	my $xml = shift;
	my %args = (
		order  => 0,        # not impl
		attr   => '-',      # ok
		text   => '#text',  # ok
		join   => '',       # ok
		trim   => 1,        # ok
		cdata  => undef,    # ok + fallback -> text
		comm   => undef,    # ok
		@_
	);
	_xml2hash($xml,\%args);
}

sub hash2xml($;%) {
	my $xml = shift;
	my %args = (
		order  => 0,        # not impl
		attr   => '-',      # ok
		text   => '#text',  # ok
		join   => '',       # ok
		trim   => 1,        # ok
		cdata  => undef,    # ok + fallback -> text
		comm   => undef,    # ok
		@_
	);
	_hash2xml($xml,\%args);
}

1;
__END__
=head1 NAME

lib/XML/Fast.pm  view on Meta::CPAN

    xml2hash( '<item>Test1<sub />Test2</item>' )
    : { item => { sub => '', '~' => 'Test1Test2' } };
    
    xml2hash( '<item>Test1<sub />Test2</item>', join => '+' )
    : { item => { sub => '', '~' => 'Test1+Test2' } };

=item trim [ = 1 ]

Trim leading and trailing whitespace from text nodes

=item cdata [ = undef ]

When defined, CDATA sections will be stored under this key

    # cdata = undef
    <node><![CDATA[ test ]]></node>  =>  { node => 'test' }

    # cdata = '#'
    <node><![CDATA[ test ]]></node>  =>  { node => { '#' => 'test' } }

=item comm [ = undef ]

When defined, comments sections will be stored under this key

When undef, comments will be ignored

    # comm = undef
    <node><!-- comm --><sub/></node>  =>  { node => { sub => '' } }

t/01-conv.t  view on Meta::CPAN

our $data;
{
	is_deeply
		$data = xml2hash($xml1),
		{root => {'-at' => 'key',nest => {'#text' => 'firstmidlast',vv => '',v => ['a',{'-at' => 'a','#text' => 'b'}]}}},
		'default (1)'
	or diag dd($data),"\n";
}
{
	is_deeply
		$data = xml2hash($xml1, cdata => '#cdata'),
		{root => {'-at' => 'key',nest => {'#cdata' => 'first','#text' => 'midlast',vv => '',v => ['a',{'-at' => 'a','#text' => 'b'}]}}},
		'default (1)'
	or diag dd($data),"\n";
}
{
	is_deeply
		$data = xml2hash($xml2),
		{root => {'-at' => 'key',nest => 'first & mid & last'}},
		'default (2)'
	or diag dd($data),"\n";
}

t/01-conv.t  view on Meta::CPAN

}
{
	is_deeply
		$data = xml2hash(q{<root x="1">test</root>}, text => '#textnode'),
		{root => { -x => 1, '#textnode' => 'test' }},
		'text node'
	or diag dd($data),"\n";
}
{
	is_deeply
		$data = xml2hash(q{<root x="1"><![CDATA[test]]></root>}, cdata => '#cdata'),
		{root => { -x => 1, '#cdata' => 'test' }},
		'cdata node'
	or diag dd($data),"\n";
}


# Composing
# Due to unpredictable order of hash keys
#   { node => { a => 1, b => 2 } }
# could be one of:
#   <node><a>1</a><b>2</b></node>
#   <node><b>2</b><a>1</a></node>

t/01-conv.t  view on Meta::CPAN

		'trim 0',
	;
	is
		$data = hash2xml( { node => { sub => [ " \t\n", 'test' ] } }, trim => 0 ),
		qq{$xml<node><sub> \t\ntest</sub></node>\n},
		'trim 1',
	;
}
{
	is
		$data = hash2xml( { node => { sub => { '@' => 'test' } } }, cdata => '@' ),
		qq{$xml<node><sub><![CDATA[test]]></sub></node>\n},
		'cdata @',
	;
}
{
	is
		$data = hash2xml( { node => { sub => { '/' => 'test' } } },comm => '/' ),
		qq{$xml<node><sub><!--test--></sub></node>\n},
		'comm /',
	;
}

t/05-wrongs.t  view on Meta::CPAN

		} else {
			diag "died with $@";
		}
		pass $name;
	}
}

dies_ok { xml2hash('<') } qr/Bad document end/, 'open tag';
dies_ok { xml2hash('<!') } qr/Bad document end/, 'open !';
dies_ok { xml2hash('<!--') } qr/Comment node not terminated/, 'unbalanced comment';
dies_ok { xml2hash('<![CDATA[') } qr/Cdata node not terminated/, 'unbalanced cdata';
dies_ok { xml2hash('<!DOCTYPE') } qr/Doctype not properly terminated/, 'unbalanced doctype';
dies_ok { xml2hash('<!DOCTYPE ') } qr/Doctype not properly terminated/, 'unbalanced doctype';
dies_ok { xml2hash('<!DOCTYPE[') } qr/Doctype intSubset not terminated/, 'unbalanced doctype';
dies_ok { xml2hash('<!BULLSHIT') } qr/Malformed document after/, 'bad <!';
dies_ok { xml2hash('<!BULLSHIT ') } qr/Malformed document after/, 'bad <!+';
dies_ok { xml2hash('<?') } qr/Processing instruction not terminated/, 'open PI';
dies_ok { xml2hash('<? ') } qr/Bad processing instruction/, 'open PI_';
dies_ok { xml2hash('<?x?') } qr/Processing instruction not terminated/, 'open PI';
dies_ok { xml2hash('<?x a="1" ?') } qr/Processing instruction not terminated/, 'open PI';
dies_ok { xml2hash('<?x a=b=c ?>') } qr/Error parsing PI attributes/, 'PI bad attrs';

xmlfast.c  view on Meta::CPAN

								p = search + 3;
							} else xml_error("Comment node not terminated");
							context->state = CONTENT_WAIT;
							goto next;
						} else
						if ( strncmp( p, "[CDATA[", 7 ) == 0) {
							context->state = CDATA_OPEN;
							p+=7;
							search = strstr(p,"]]>");
							if (search) {
								if (cb->cdata) {
									cb->cdata( ctx, p, search - p);
								}
								p = search + 3;
							} else xml_error("Cdata node not terminated");
							context->state = CONTENT_WAIT;
							goto next;
						} else
						if ( strncmp(p, "DOCTYPE", 7 ) == 0 ) {
							p += 7;
							//p = eat_wsp(p);
							state = 0;

xmlfast.h  view on Meta::CPAN

	char *name;
	char *value;
} xml_attr;

typedef void (*xml_callback)(void *,char *, unsigned int, unsigned int);

typedef struct {
	void (*piopen)(void *,char *, unsigned int);
	void (*piclose)(void *,char *, unsigned int);
	void (*comment)(void *,char *, unsigned int);
	void (*cdata)(void *,char *, unsigned int);
	void (*tagopen)(void *,char *, unsigned int);
	void (*attrname)(void *,char *, unsigned int);
	void (*tagclose)(void *,char *, unsigned int);
	void (*bytespart)(void *, char *, unsigned int);
	void (*bytes)(void *, char *, unsigned int);
	void (*uchar)(void *, wchar_t);

	void (*warn)(void *, char *, ...);
	void (*die)(void *, char *, ...);
} xml_callbacks;



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