SGML-SPGroveBuilder

 view release on metacpan or  search on metacpan

SPGroveNew.cc  view on Meta::CPAN

//
void
SPGrove::startElement(const StartElementEvent &event)
{
  flushData();
  SV *element[3];

  // Create empty array for contents
  AV *contents = newAV();
  element[0] = newRV_noinc((SV*)contents);

  // Name
  element[1] = newSVpv(as_string(event.gi), event.gi.len);

  // Attributes
  HV *attributes = (HV*)&sv_undef;
  size_t nAttributes = event.nAttributes;

  if (nAttributes > 0) {
    // XXX we can optimize by using a C array and av_make instead of push
    const Attribute *att_ptr = event.attributes;

    while (nAttributes-- > 0) {
      switch (att_ptr->type) {
      case Attribute::implied:
	break;			// ignored
      case Attribute::tokenized:
	{
	  if (attributes == (HV*)&sv_undef) {
	    attributes = newHV();
	  }

	  if (att_ptr->nEntities != 0) {
	    AV *att_data = newAV();
	    size_t nEntities = att_ptr->nEntities;
	    const SGMLApplication::Entity *entities = att_ptr->entities;

	    while (nEntities-- > 0) {
	      SV *entity_ref = entity (entities);
	      SvREFCNT_inc (entity_ref);
	      av_push (att_data, entity_ref);
	      entities ++;
	    }
	    hv_store (attributes,
		      as_string(att_ptr->name), att_ptr->name.len,
		      newRV_noinc((SV*)att_data), 0);
	  } else if (att_ptr->notation.name.len > 0) {
	    SV *notation_ref = notation(&att_ptr->notation);
	    SvREFCNT_inc (notation_ref);
	    hv_store (attributes,
		      as_string(att_ptr->name), att_ptr->name.len,
		      notation_ref, 0);
	  } else {
	    SV *token = newSVpv(as_string(att_ptr->tokens), att_ptr->tokens.len);
	    hv_store (attributes,
		      as_string(att_ptr->name), att_ptr->name.len,
		      token, 0);
	  }
	}
        break;
      case Attribute::cdata:
	{
	  AV *att_data = newAV();
	  size_t nCdataChunks = att_ptr->nCdataChunks;
	  const SGMLApplication::Attribute::CdataChunk *cdataChunk
	    = att_ptr->cdataChunks;

	  if (attributes == (HV*)&sv_undef) {
	    attributes = newHV();
	  }

	  // XXX we can optimize by using a C array and av_make instead of push
	  while (nCdataChunks-- > 0) {
	    SV *data = NULL;

	    if (cdataChunk->isSdata) {
	      SV *sdata_a[2];
	      sdata_a[0] = newSVpv(as_string(cdataChunk->data),
				   cdataChunk->data.len);
	      sdata_a[1] = newSVpv(as_string(cdataChunk->entityName),
				   cdataChunk->entityName.len);
	      AV *sdata = av_make(2, &sdata_a[0]);
	      SvREFCNT_dec (sdata_a[0]);
	      SvREFCNT_dec (sdata_a[1]);
	      data = newRV_noinc((SV*)sdata);
	      sv_bless (data, sdata_stash_);
	    } else if (!cdataChunk->isNonSgml) {
	      data = newSVpv(as_string(cdataChunk->data), cdataChunk->data.len);
	    } else {
	      // XXX we need to do better than this
	      fprintf (stderr, "SPGroveNew: isNonSGML in cdata attribute\n");
	    }
	    if (data != NULL) {
	      av_push (att_data, data);
	    }
	    cdataChunk ++;
	  }

	  hv_store (attributes,
		    as_string(att_ptr->name), att_ptr->name.len,
		    newRV_noinc((SV*)att_data), 0);
	}
	break;
      default: {
	  // XXX this is a CANT_HAPPEN
	  av_push(errors_, newSVpv("SPGroveNew: invalid attribute type", 0));
	  break;
	}
      }
      att_ptr ++;
    }
  }

  // finish off adding the attributes to the element
  if (attributes == (HV*)&sv_undef) {
    element[2] = &sv_undef;
  } else {
    element[2] = newRV_noinc((SV*)attributes);
  }

  // create a reference so we can bless it and pass it around
  SV *element_ref = newRV_noinc((SV*)av_make(3, &element[0]));
  SvREFCNT_dec (element[0]);
  SvREFCNT_dec (element[1]);
  if (element[2] != &sv_undef) {
    SvREFCNT_dec (element[2]);
  }
  sv_bless (element_ref, element_stash_);

  av_push (contents_, element_ref);
  av_push (stack_, (SV*)contents_);

  // cache the contents array
  contents_ = contents;
}

//
// `endElement' is called at the closing of each element in the
// instance.  `endElement' pulls the parent element off the stack and
// copies it's contents to the `contents_' cache
//
void
SPGrove::endElement(const EndElementEvent &)
{
  flushData();

  contents_ = (AV*)av_pop(stack_);
}

//
// `data' is called when ordinary instance data comes across
//
// XXX we could provide an option for concatenation
void
SPGrove::data(const DataEvent &event)
{

SPGroveNew.cc  view on Meta::CPAN

  av_push(contents_, pi_ref);
}

//
// `externalDataEntity'
//
void
SPGrove::externalDataEntityRef(const ExternalDataEntityRefEvent &event)
{
  flushData();

  SV *entity_ref = entity(&event.entity);
  SvREFCNT_inc (entity_ref);
  av_push(contents_, entity_ref);
}

//
// `subdocEntityRef'
//
void SPGrove::subdocEntityRef(const SubdocEntityRefEvent &event)
{
  flushData();

  SV *entity_ref = entity(&event.entity);
  SvREFCNT_inc (entity_ref);
  av_push(contents_, entity_ref);
}

//
// `nonSgmlChar'
//
void SPGrove::nonSgmlChar(const NonSgmlCharEvent &event)
{
  flushData();

  fprintf (stderr, "SPGroveNew: nonSgmlChar not handled\n");
}

//
// `error' is called when an error is encountered during the parse.
//
void SPGrove::error(const ErrorEvent &event) {
  av_push(errors_, newSVpv(as_string(event.message), event.message.len));
}

//
// `entity' returns an entity definition, creating it if necessary
//
SV *
SPGrove::entity (const SGMLApplication::Entity *entity)
{
  char *name = as_string(entity->name);
  SV **entity_def = hv_fetch(entities_, name, entity->name.len, 0);
  if (!entity_def) {
    HV *new_entity = newHV();
    hv_store(new_entity, "name", 4, newSVpv(name, entity->name.len), 0);

    char *type = 0;
    HV *stash;
    switch (entity->dataType) {
    case Entity::cdata:  type = "CDATA"; stash = extentity_stash_; break;
    case Entity::sdata:  type = "SDATA"; stash = extentity_stash_; break;
    case Entity::ndata:  type = "NDATA"; stash = extentity_stash_; break;
    case Entity::subdoc: stash = subdocentity_stash_; break;
    default: {
        av_push(errors_, newSVpv("SPGroveNew: data type not handled", 0));
      }
    }
    if (type) {
      hv_store(new_entity, "type", 4, newSVpv(type, 5), 0);
    }
    if (entity->isInternal) {
      hv_store(new_entity, "data", 4,
	       newSVpv(as_string(entity->text), entity->text.len), 0);
      stash = entity_stash_;
    } else {
      store_external_id (new_entity, &entity->externalId);
      // XXX attributes

      if (entity->notation.name.len > 0) {
	SV *notation_ref = notation(&entity->notation);
	SvREFCNT_inc (notation_ref);
	hv_store(new_entity, "notation", 8,
		 notation_ref, 0);
      }
    }

    SV *entity_ref = newRV_noinc((SV*)new_entity);
    sv_bless (entity_ref, stash);
    name = as_string(entity->name); // again since it was overwritten
    entity_def = hv_store (entities_, name, entity->name.len, entity_ref, 0);
  }

  return (*entity_def);
}

//
// `notation' returns a notation definition, creating it if necessary
//
SV *
SPGrove::notation (const SGMLApplication::Notation *notation)
{
  char *name = as_string(notation->name);
  SV **notation_def = hv_fetch(notations_, name, notation->name.len, 0);
  if (!notation_def) {
    HV *new_notation = newHV();
    hv_store(new_notation, "name", 4, newSVpv(name, notation->name.len), 0);

    store_external_id (new_notation, &notation->externalId);

    SV *notation_ref = newRV_noinc((SV*)new_notation);
    sv_bless (notation_ref, notation_stash_);
    name = as_string(notation->name); // again since it was overwritten
    notation_def = hv_store (notations_, name, notation->name.len, notation_ref, 0);
  }

  return (*notation_def);
}

//
// `store_external_id' stores external ID values in `hash'



( run in 2.323 seconds using v1.01-cache-2.11-cpan-995e09ba956 )