/* * scl2html.cc * * Ian Soboroff, NIST * June, 1994 * * scl2html is a program to lay out a given schema in HTML, suitable for * hypertext browsing using Mosaic or any other HTML viewer/WWW surfboard. * While this particular code as designed is linked to the Example schema * (via tests.h), it can be "fed" any exp2cxx-compiled schema and give * appropriate output. * * The Makefile defaults to building the app to use the example schema. To * link to another schema, build the appropriate libraries for it and * 'make SCHEMA_NAME=my-schema'. See the Makefile for more details. * * The executable is named after the schema you use, e.g., scl2html.example. * This can be renamed to whatever you want. * * This program works by using the registry to walk through each entity type. * At each entity, the supertypes, subtypes, and attributes are probed out * and mapped into a relatively nifty-looking HTML format. * * This code was heavily inspired by the original scltest program, * distributed with the DataProbe, v2.0.x. */ /* Since scl2html doesn't use any schema-specific things except the init function, we don't need to include the schema's header file inside tests.h */ #define DONT_NEED_HEADER #include "../tests.h" /* STEPentity* Iterator class definition */ #include "../SEarritr.h" // PrintAttrTypeWithAnchor() // Given an attribute, print out its immediate type (not fundamental). // Ah, but if life were so simple. If this attribute is _not_ of a // fundamental type, put in an anchor to somewhere with info on the type. // This could be either the index page Type list, or an entity's page if // the attribute is an entity. // BUGS: (sort of) IMHO, the handling of aggregates here is a kludge, but // it's a kludge without a solution I can see. While the dictionary has // ways to show you what kinds of things an aggregate holds, it won't tell // you what kind of _aggragation_ (no pun intended) you have, as in giving // you a code or "Bag" or something by itself. It probably doesn't work // aesthetically for compound aggregates (i.e., a list of lists). void PrintAttrTypeWithAnchor( const TypeDescriptor * typeDesc, ofstream & outhtml ) { std::string buf; // The type. See clstepcore/baseType.h for info PrimitiveType base = typeDesc->Type(); // the type descriptor for the "referent type," if any. // This is NULL if the attribute is a fundamental type. // All we use it for now is checking for NULL. const TypeDescriptor * reference = typeDesc->ReferentType(); // Do we need an anchor? int anchor = 0; // First, figure out if we need an anchor... if( reference ) { // if this has a referent type (i.e., is a non-base type) if( base != sdaiAGGR ) { // anchor all non-bases except for aggregates anchor = 1; // which we'll take care of recursively } } else { // entities and enumerations show up as base, but we want to // anchor them anyway if( base == sdaiENUMERATION || base == sdaiINSTANCE ) { anchor = 1; } } // Now, print type, with anchor if necessary if( anchor && base != sdaiINSTANCE ) { // for regular TYPEs, anchor to the index at that definition outhtml << "Name() << "\">"; } else if( anchor && base == sdaiINSTANCE ) { // for entities, anchor to that entity's page outhtml << "Name(); outhtml << ".html\">"; } typeDesc->AttrTypeName( buf ); outhtml << buf; if( base == sdaiAGGR ) { outhtml << " (contains elements of type "; PrintAttrTypeWithAnchor( typeDesc->AggrElemTypeDescriptor(), outhtml ); outhtml << ")" << endl; } if( anchor ) { outhtml << ""; } } // PrintAttrsHTML() // Given an entity, print out to the HTML file an unordered list of // the entity's attributes and their types. It returns the number of // explicit attributes that the entity has. int PrintAttrsHTML( const EntityDescriptor * ent, ofstream & outhtml ) { int attrCount = 0; // To traverse the attributes of the entity, we're going to use // an iterator native to the class library. This could also have // been done using GetHead() and NextNode() of the entity's attribute // list (nearly identical to how the entity lists are traversed), see // PrintParentAttrsHTML() and also main() below. AttrDescItr aditr( ent->ExplicitAttr() ); const AttrDescriptor * attrDesc = aditr.NextAttrDesc(); if( attrDesc != 0 ) { outhtml << "\nName() << " >\n\n"; outhtml << "" << endl; } return attrCount; } // PrintParentAttrsHTML() // This function, given an entity and its parent, recursively travels up // the inheritance tree of the entity, printing to the HTML file a // description-list structure showing all ancestors. For each ancestor, // the attributes are printed using the PrintAttrsHTML() function above. void PrintParentAttrsHTML( const EntityDescriptor * ent, const EntityDescriptor * parent, ofstream & outhtml ) { // Passing this function the pointer to ent is really cosmetic, so // we can easily print out this 'header' information. outhtml << "\nName() << ">\n\n"; outhtml << "
" << endl; outhtml << "
" << ent->Name() << " inherits from "; outhtml << "Name() << ".html\">"; outhtml << parent->Name() << "" << endl; // Here we're going to traverse the list of supertypes of the parent // using the EntityDescriptorList const EntityDescriptorList * grandpaList = &( parent->Supertypes() ); EntityDescLinkNode * grandpaNode = ( EntityDescLinkNode * )grandpaList->GetHead(); while( grandpaNode ) { // for each "grandparent" of ent, inside a descriptor body (
) // recursively call this function... the 'while' takes care of // multiple inheritance: for each grandparent, trace back. outhtml << "
" << endl; const EntityDescriptor * grandpa = grandpaNode->EntityDesc(); PrintParentAttrsHTML( parent, grandpa, outhtml ); grandpaNode = ( EntityDescLinkNode * )grandpaNode->NextNode(); } // Now print the parent's attributes. This calls PrintAttrsHTML() to // actually print any existing attributes, but to see if there are // any, we'll check to see if the head of the attribute descriptor list // exists. Conversely, once grabbing the head we could print out // the attributes by following the list (attrNode->NextNode()). const AttrDescriptorList * attrList = &( parent->ExplicitAttr() ); AttrDescLinkNode * attrNode = ( AttrDescLinkNode * )attrList->GetHead(); if( attrNode ) { outhtml << "
" << parent->Name(); outhtml << " has the following attributes" << endl; outhtml << "
" << endl; if( PrintAttrsHTML( parent, outhtml ) == 0 ) { outhtml << "none" << endl; } } outhtml << "
" << endl; } /******************** main() ****************************/ main() { // This has to be done before anything else. This initializes // all of the registry information for the schema you are using. // The SchemaInit() function is generated by exp2cxx... see // extern statement above. Registry * registry = new Registry( SchemaInit ); // Rather than using the standard Registry class here, as in the treg // example, we are using MyRegistry, which is derived from the original. // Registry doesn`t contain a facility for browsing the types, as it // does schemas and entities... so I added it. See the file // MyRegistry.h for details on how this was done. // "Reset" has tables for browsing registry->ResetEntities(); registry->ResetSchemas(); registry->ResetTypes(); const SchemaDescriptor * schema = registry->NextSchema(); int num_ents = registry->GetEntityCnt(); cout << "Processing schema " << schema->Name(); cout << " with " << num_ents << " entities." << endl; // Set up root-level index of the schema, in a file called // "index.html". In this document are links to all objects in // the schema. cout << "Creating 'index.html'" << endl; ofstream root( "index.html" ); root << "" << schema->Name() << "" << endl; root << "

Schema: " << schema->Name() << "

" << endl; // Do Type-list cout << "Processing types "; root << "
" << endl; root << "

Types

" << endl; root << "" << endl; cout << endl; // Do entity root-section and pages root << "
" << endl; root << "

Entities

" << endl; root << "" << endl; cout << "Done!" << endl; }