XML-Bare
view release on metacpan or search on metacpan
// JEdit mode Line -> :folding=indent:mode=c++:indentSize=2:noTabs=true:tabSize=2:
#include "EXTERN.h"
#define PERL_IN_HV_C
#define PERL_HASH_INTERNAL_ACCESS
#include "perl.h"
#include "XSUB.h"
#include "parser.h"
U32 vhash;
U32 chash;
U32 phash;
U32 ihash;
U32 cdhash;
U32 zhash;
U32 ahash;
U32 content_hash;
char *rootpos;
//#define DEBUG
SV *cxml2obj( struct parserc *parser, struct nodec *curnode ) {
HV *output = newHV(); // the root
SV *outputref = newRV_noinc( (SV *) output ); // return a reference to the root
int i; // loop index; defined at the top because this is C
struct attc *curatt; // current attribute being worked with
int numatts = curnode->numatt; // total number of attributes on the current node
SV *attval;
SV *attatt;
int cur_type;
int length = curnode->numchildren;
SV *svi = newSViv( curnode->pos );
hv_store( output, "_pos", 4, svi, phash );
hv_store( output, "_i", 2, newSViv( curnode->name - rootpos ), ihash );
hv_store( output, "_z", 2, newSViv( curnode->z ), zhash );
#ifdef DEBUG
printf("Node: %.*s\n", curnode->namelen, curnode->name );
#endif
// node without children
if( !length ) {
if( curnode->vallen ) {
SV * sv = newSVpvn( curnode->value, curnode->vallen );
SvUTF8_on(sv);
hv_store( output, "value", 5, sv, vhash );
if( curnode->type ) {
SV *svi = newSViv( 1 );
hv_store( output, "_cdata", 6, svi, cdhash );
}
}
if( curnode->comlen ) {
SV * sv = newSVpvn( curnode->comment, curnode->comlen );
SvUTF8_on(sv);
hv_store( output, "comment", 7, sv, chash );
}
}
// node with children
else {
if( curnode->vallen ) {
SV *sv = newSVpvn( curnode->value, curnode->vallen );
SvUTF8_on(sv);
hv_store( output, "value", 5, sv, vhash );
if( curnode->type ) {
SV *svi = newSViv( 1 );
hv_store( output, "_cdata", 6, svi, cdhash );
}
}
if( curnode->comlen ) {
SV *sv = newSVpvn( curnode->comment, curnode->comlen );
SvUTF8_on(sv);
hv_store( output, "comment", 7, sv, chash );
}
// loop through child nodes
curnode = curnode->firstchild;
for( i = 0; i < length; i++ ) {
SV **cur = hv_fetch( output, curnode->name, curnode->namelen, 0 );
// check for multi_[name] nodes
if( curnode->namelen > 6 ) {
if( !strncmp( curnode->name, "multi_", 6 ) ) {
char *subname = &curnode->name[6];
int subnamelen = curnode->namelen-6;
SV **old = hv_fetch( output, subname, subnamelen, 0 );
AV *newarray = newAV();
SV *newarrayref = newRV_noinc( (SV *) newarray );
if( !old ) {
hv_store( output, subname, subnamelen, newarrayref, 0 );
}
else {
if( SvTYPE( SvRV(*old) ) == SVt_PVHV ) { // check for hash ref
SV *newref = newRV( (SV *) SvRV(*old) );
hv_delete( output, subname, subnamelen, 0 );
hv_store( output, subname, subnamelen, newarrayref, 0 );
av_push( newarray, newref );
}
}
}
}
if( !cur ) {
SV *ob = cxml2obj( parser, curnode );
hv_store( output, curnode->name, curnode->namelen, ob, 0 );
}
else { // there is already a node stored with this name
cur_type = SvTYPE( SvRV( *cur ) );
if( cur_type == SVt_PVHV ) { // sub value is a hash; must be anode
AV *newarray = newAV();
SV *newarrayref = newRV_noinc( (SV *) newarray );
SV *newref = newRV( (SV *) SvRV( *cur ) );
SV *ob;
hv_delete( output, curnode->name, curnode->namelen, 0 );
hv_store( output, curnode->name, curnode->namelen, newarrayref, 0 );
av_push( newarray, newref );
ob = cxml2obj( parser, curnode );
av_push( newarray, ob );
}
else if( cur_type == SVt_PVAV ) {
AV *av = (AV *) SvRV( *cur );
SV *ob = cxml2obj( parser, curnode );
av_push( av, ob );
}
else {
// something else; probably an existing value node; just wipe it out
SV *ob = cxml2obj( parser, curnode );
if( !strncmp( curnode->name, "multi_", 6 ) ) {
char *subname = &curnode->name[6];
int subnamelen = curnode->namelen-6;
SV **old = hv_fetch( output, subname, subnamelen, 0 );
AV *newarray = newAV();
SV *newarrayref = newRV_noinc( (SV *) newarray );
if( !old ) {
hv_store( output, subname, subnamelen, newarrayref, 0 );
}
else {
if( SvTYPE( SvRV(*old) ) == SVt_PVHV ) { // check for hash ref
SV *newref = newRV_noinc( (SV *) SvRV(*old) );
hv_delete( output, subname, subnamelen, 0 );
hv_store( output, subname, subnamelen, newarrayref, 0 );
av_push( newarray, newref );
}
}
}
}
if( !cur ) {
SV *ob = cxml2obj_simple( parser, curnode );
hv_store( output, curnode->name, curnode->namelen, ob, 0 );
}
else {
if( SvROK( *cur ) ) {
if( SvTYPE( SvRV(*cur) ) == SVt_PVHV ) {
AV *newarray = newAV();
SV *newarrayref = newRV_noinc( (SV *) newarray );
SV *newref = newRV( (SV *) SvRV( *cur ) );
hv_delete( output, curnode->name, curnode->namelen, 0 );
hv_store( output, curnode->name, curnode->namelen, newarrayref, 0 );
av_push( newarray, newref );
av_push( newarray, cxml2obj_simple( parser, curnode ) );
}
else {
AV *av = (AV *) SvRV( *cur );
av_push( av, cxml2obj_simple( parser, curnode ) );
}
}
else {
AV *newarray = newAV();
SV *newarrayref = newRV( (SV *) newarray );
STRLEN len;
char *ptr = SvPV(*cur, len);
SV *newsv = newSVpvn( ptr, len );
SvUTF8_on(newsv);
av_push( newarray, newsv );
hv_delete( output, curnode->name, curnode->namelen, 0 );
hv_store( output, curnode->name, curnode->namelen, newarrayref, 0 );
av_push( newarray, cxml2obj_simple( parser, curnode ) );
}
}
if( i != ( length - 1 ) ) curnode = curnode->next;
}
curnode = curnode->parent;
}
else {
if( curnode->type ) { // store cdata value under content, even if empty or spaces
SV * sv = newSVpvn( curnode->value, curnode->vallen );
SvUTF8_on(sv);
hv_store( output, "content", 7, sv, content_hash );
}
else {
int hasval = 0;
for( i=0;i<curnode->vallen;i++ ) {
char let = curnode->value[ i ];
if( let != ' ' && let != 0x0d && let != 0x0a ) {
hasval = 1;
break;
}
}
if( hasval ) {
SV * sv = newSVpvn( curnode->value, curnode->vallen );
SvUTF8_on(sv);
hv_store( output, "content", 7, sv, content_hash );
}
}
}
if( numatts ) {
curatt = curnode->firstatt;
for( i = 0; i < numatts; i++ ) {
if( curatt->value == -1 ) attval = newSVpvn( "1", 1 );
else attval = newSVpvn( curatt->value, curatt->vallen );
SvUTF8_on(attval);
hv_store( output, curatt->name, curatt->namelen, attval, 0 );
if( i != ( numatts - 1 ) ) curatt = curatt->next;
}
}
return outputref;
}
void init_hashes() {
PERL_HASH(vhash, "value", 5);
PERL_HASH(ahash, "_att", 4);
PERL_HASH(chash, "comment", 7);
PERL_HASH(phash, "_pos", 4);
PERL_HASH(ihash, "_i", 2 );
PERL_HASH(zhash, "_z", 2 );
PERL_HASH(cdhash, "_cdata", 6 );
}
MODULE = XML::Bare PACKAGE = XML::Bare
SV *
xml2obj( parsersv )
SV *parsersv
CODE:
struct parserc *parser;
parser = INT2PTR( struct parserc *, SvUV( parsersv ) );
if( parser->err ) RETVAL = newSViv( parser->err );
else {
RETVAL = cxml2obj( parser, parser->rootnode );
//printf("refcnt: %i\n", SvREFCNT( RETVAL ) );
}
OUTPUT:
RETVAL
SV *
xml2obj_simple( parsersv )
SV *parsersv
CODE:
PERL_HASH( content_hash, "content", 7 );
struct parserc *parser;
parser = INT2PTR( struct parserc *, SvUV( parsersv ) );
if( parser->err ) RETVAL = newSViv( parser->err );
else {
RETVAL = cxml2obj_simple( parser, parser->rootnode );
//printf("refcnt: %i\n", SvREFCNT( RETVAL ) );
}
OUTPUT:
RETVAL
SV *
c_parse_more( text, parsersv )
char * text
SV *parsersv
CODE:
struct parserc *parser = INT2PTR( struct parserc *, SvUV( parsersv ) );
int err = parserc_parse( parser, text );
RETVAL = newSVuv( PTR2UV( parser ) );
OUTPUT:
RETVAL
SV *
c_parse(text)
char * text
CODE:
init_hashes();
struct parserc *parser = (struct parserc *) malloc( sizeof( struct parserc ) );
parser->last_state = 0;
int err = parserc_parse( parser, text );
RETVAL = newSVuv( PTR2UV( parser ) );
OUTPUT:
RETVAL
SV *
c_parse_unsafely(text)
char * text
( run in 3.450 seconds using v1.01-cache-2.11-cpan-39bf76dae61 )