//-----------------------------------------------------------------------------
// File: sample.cpp
// Title: Simple application template
//-----------------------------------------------------------------------------
#define PCOM_INIT_GUID
#include <psareg.h>
#include <psacom.h>
#include <stdio.h>
#include "xflaim.h"
#ifdef UNIX
#include
<sys/utsname.h>
#endif
FLMBOOL gv_bShutdown = FALSE;
#if defined(NLM)
#define DB_NAME_STR ((FLMBYTE *)"SYS:\\TST.DB")
#define BACKUP_NAME_STR ((FLMBYTE
*)"SYS:\\TST.BAK")
#define NEW_NAME_STR ((FLMBYTE
*)"SYS:\\NEW.DB")
FLMBOOL
gv_bRunning = FALSE;
extern "C"
{
int
nlm_main( int
iArgC,
char ** ppucArgV);
void
ConsolePrintf( const char *format, ...);
void
SynchronizeStart( void);
void
sampleCleanup( void);
}
void sampleCleanup(
void)
{
while( gv_bRunning)
{
f_yieldCPU();
}
}
#else
#define DB_NAME_STR
"tst.db"
#define BACKUP_NAME_STR
"tst.bak"
#define NEW_NAME_STR
"new.db"
#endif
#define MAX_KEY_SIZ 1024
// Update this code to point to where the .dll files are
located.
#ifdef UNIX
const char
* pszComServerPaths[] = { ".",
"./tests", "../lib",
0};
#else
const char * pszComServerPaths[]
= { ".", 0 };
#endif
#define PCOM_INIT_GUID
// {B68FE080-AB53-400d-89AF-DAB2FF592F77}
PCOM_DEFINE_GUID(CLSID_XFlaim_Sample_Prog,
0xb68fe080, 0xab53,
0x400d, 0x89,
0xaf, 0xda,
0xb2, 0xff,
0x59, 0x2f,
0x77);
void printMessage(
char *
pszMessage,
FLMUINT uiLevel = 0);
RCODE printDocument(
IF_Db *
pDb,
IF_DOMNode * pRootNode);
RCODE processAttributes(
IF_Db *
pDb,
IF_DOMNode * pNode,
FLMBYTE ** ppszLine);
/***************************************************************************
Desc: Program entry point (main)
****************************************************************************/
#if defined( UNIX)
int main(
int,
// iArgC,
char **
// ppucArgV
)
#elif defined( NLM)
int nlm_main(
int,
// iArgC,
char **
// ppucArgV
)
#else
int __cdecl main(
int,
// iArgC,
char **
// ppucArgV
)
#endif
{
RCODE
rc = NE_XFLM_OK;
FLMBYTE
ucMsgBuf[ 200];
XFLM_CREATE_OPTS createOpts;
IF_Db *
pDb = NULL;
IF_Backup *
pBackup = NULL;
IF_DOMNode *
pTmpNode = NULL;
bool
bPsaInitialized = false;
IF_DbSystem *
pDbSystem = NULL;
int
iErr = 0;
FLMUINT
uiMusicElementDef=0;
FLMUINT
uiCdElementDef=0;
FLMUINT
uiTitleElementDef=0;
FLMUINT
uiArtistElementDef=0;
FLMUINT
uiTracksElementDef=0;
FLMUINT
uiNoAttrDef=0;
FLMUINT
uiTitleAttrDef=0;
FLMUINT
uiCollectionDef=0;
FLMBOOL
bTranStarted = FALSE;
IF_DOMNode *
pCdChild = NULL;
IF_DOMNode *
pCdElement = NULL;
IF_DOMNode *
pMusicElement = NULL;
IF_DOMNode *
pCdAttr = NULL;
IF_DOMNode *
pTrackNode = NULL;
IF_Query *
pQuery = NULL;
IF_PosIStream *
pPosIStream = NULL;
IF_PosIStream *
pIStream = NULL;
FLMUINT
uiIndex = 1;
FLMBYTE
ucUntilKeyBuf[ MAX_KEY_SIZ];
FLMUINT
uiUntilKeyLen;
FLMBYTE
ucCurrentKeyBuf[ MAX_KEY_SIZ];
FLMUINT
uiCurrentKeyLen;
FLMUINT64
ui64DocId;
char
ucTitle[ 200];
FLMUINT
uiTitleLen;
char * ppszPath[] =
{
".\\xmlfiles\\7001e10c",
".\\xmlfiles\\70028663",
".\\xmlfiles\\70037c08",
".\\xmlfiles\\70040b08",
".\\xmlfiles\\70044808",
".\\xmlfiles\\70045109",
".\\xmlfiles\\70045e09",
".\\xmlfiles\\70046709",
".\\xmlfiles\\7004920a",
""
};
FLMUINT
uiLoop;
IF_DataVector *
pFromKeyV = NULL;
IF_DataVector *
pUntilKeyV = NULL;
char
szQueryString[] = "/music/cd/tracks[@title~=\"we our in
luv\"]";
char *
pszIndex =
"<xflaim:Index "
"xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" "
"xmlns:xflaim=\"http://www.novell.com/XMLDatabase/Schema\" "
"xs:name=\"title_IX\">"
"<xflaim:ElementComponent "
"xs:name=\"title\" "
"xflaim:DictNum=\"1\" "
"xflaim:IndexOn=\"value\" "
"xflaim:KeyComponent=\"1\"/>"
"</xflaim:Index>";
#ifdef NLM
gv_bRunning = TRUE;
// Setup the routines to be called when
the NLM exits
atexit( sampleCleanup);
SynchronizeStart();
#endif
// Initialize the PSA subsystem
iErr = PsaComInitialize( CLSID_XFlaim_Sample_Prog,
pszComServerPaths);
if (iErr)
{
printf( "\nERROR:
Unable to initialize PSA");
goto
Exit;
}
else
{
bPsaInitialized =
true;
}
// Create the database system object
that we will use to access the XFlaim
// database API and initialize it for use.
if (RC_BAD( rc =
PsaComCreateInstance( CLSID_F_DbSystemFactory,
NULL,
IID_IF_DbSystem,
(void **)&pDbSystem)))
{
goto
Exit;
}
if ( RC_BAD( rc = pDbSystem->init()))
{
goto
Exit;
}
// Create the database. This code will
remove the database first if it
// exists. Once removed, it will try to create it. If that
fails for
// any reason other than the database already exists, it will
exit.
RetryCreate:
memset( &createOpts, 0, sizeof(
XFLM_CREATE_OPTS));
if ( RC_BAD( rc = pDbSystem->dbCreate(
DB_NAME_STR,
NULL,
NULL,
NULL,
NULL,
&createOpts,
&pDb)))
{
if (
RC_BAD( rc == NE_XFLM_FILE_EXISTS))
{
if ( RC_BAD( rc = pDbSystem->dbRemove( DB_NAME_STR,
NULL,
NULL,
TRUE)))
{
goto Exit;
}
goto RetryCreate;
}
else
{
goto Exit;
}
}
// Start an update transaction. All
access to the database should
// be done within the confines of a transaction. When changed
are being
// made to the database, an UPDATE transaction is required.
It is best to
// keep transactions small if possible.
if ( RC_BAD( rc = pDb->transBegin(
XFLM_UPDATE_TRANS, 0)))
{
goto
Exit;
}
bTranStarted = TRUE;
/*
Let's create a document to demonstrate how we use the DOM...
Our document will catalog a music CD. It will look like:
<music>
<cd>
<title>We Are In Love</title>
<artist>Harry Connick
Jr.</artist>
<tracks no="1" title="We Are In
Love"/>
<tracks no="2" title="Only 'Cause I
Don't Have You"/>
</cd>
</music>
To accomplish this, we must define the elements of the document and a new
collection to store the document in.
*/
// Create some element definitions for
our document.
// Create the "music" element definition.
if ( RC_BAD( rc = pDb->createElementDef(
NULL,
"music",
XFLM_NODATA_TYPE,
&uiMusicElementDef)))
{
goto
Exit;
}
// Create the "cd" element definition.
if ( RC_BAD( rc = pDb->createElementDef(
NULL,
"cd",
XFLM_NODATA_TYPE,
&uiCdElementDef)))
{
goto
Exit;
}
// Create the "title" element
definition.
if ( RC_BAD( rc = pDb->createElementDef(
NULL,
"title",
XFLM_TEXT_TYPE,
&uiTitleElementDef)))
{
goto
Exit;
}
// Create the "artist" element
definition.
if ( RC_BAD( rc = pDb->createElementDef(
NULL,
"artist",
XFLM_TEXT_TYPE,
&uiArtistElementDef)))
{
goto
Exit;
}
// Create the "tracks" element
definition.
if ( RC_BAD( rc = pDb->createElementDef(
NULL,
"tracks",
XFLM_NODATA_TYPE,
&uiTracksElementDef)))
{
goto
Exit;
}
// Create the "no" attribute
definition.
if ( RC_BAD( rc = pDb->createAttributeDef(
NULL,
"no",
XFLM_NUMBER_TYPE,
&uiNoAttrDef)))
{
goto
Exit;
}
// Create the "title" attribute
definition.
if ( RC_BAD( rc = pDb->createAttributeDef(
NULL,
"title",
XFLM_TEXT_TYPE,
&uiTitleAttrDef)))
{
goto
Exit;
}
// Create our special music collection
for storing music stuff.
if ( RC_BAD( rc = pDb->createCollectionDef(
"Music Collection",
&uiCollectionDef)))
{
goto
Exit;
}
// We now have all of the definitions
we need to build our document.
// Lets first create a new document, followed by its
members...
// Create the "music" root element
if ( RC_BAD( rc = pDb->createRootElement(
uiCollectionDef,
uiMusicElementDef,
&pMusicElement)))
{
goto
Exit;
}
// Create the "cd" element
if ( RC_BAD( rc = pMusicElement->createNode(
pDb,
ELEMENT_NODE,
uiCdElementDef,
XFLM_FIRST_CHILD,
&pCdElement)))
{
goto
Exit;
}
// Create the "title" element
if ( RC_BAD( rc = pCdElement->createNode(
pDb,
ELEMENT_NODE,
uiTitleElementDef,
XFLM_FIRST_CHILD,
&pCdChild)))
{
goto
Exit;
}
// Set the value for the title.
if (RC_BAD( rc = pCdChild->setNative(
pDb, "We Are In Love")))
{
goto
Exit;
}
// Create the "artist" element
if ( RC_BAD( rc = pCdElement->createNode(
pDb,
ELEMENT_NODE,
uiArtistElementDef,
XFLM_LAST_CHILD,
&pCdChild)))
{
goto
Exit;
}
// Set the value for the title.
if (RC_BAD( rc = pCdChild->setNative(
pDb, "Harry Connick Jr.")))
{
goto
Exit;
}
// Create the first "tracks" element
if ( RC_BAD( rc = pCdElement->createNode(
pDb,
ELEMENT_NODE,
uiTracksElementDef,
XFLM_LAST_CHILD,
&pCdChild)))
{
goto
Exit;
}
// Create the "no." attribute, then the
"title" attribute.
if (RC_BAD( rc = pCdChild->createAttribute(
pDb,
uiNoAttrDef,
&pCdAttr)))
{
goto
Exit;
}
if (RC_BAD( rc = pCdAttr->setUINT(
pDb, (FLMUINT)1)))
{
goto
Exit;
}
if (RC_BAD( rc = pCdChild->createAttribute(
pDb,
uiTitleAttrDef,
&pCdAttr)))
{
goto
Exit;
}
if (RC_BAD( rc = pCdAttr->setNative(
pDb,
"We Are In Love")))
{
goto
Exit;
}
// Create the next "tracks" element
if ( RC_BAD( rc = pCdElement->createNode(
pDb,
ELEMENT_NODE,
uiTracksElementDef,
XFLM_LAST_CHILD,
&pCdChild)))
{
goto
Exit;
}
// An alternate way to create the
attributes and set their values is to use
// the parent element to set the attribute values.
// Create the two attributes.
if (RC_BAD( rc = pCdChild->createAttribute(
pDb,
uiNoAttrDef,
&pCdAttr)))
{
goto
Exit;
}
if (RC_BAD( rc = pCdChild->createAttribute(
pDb,
uiTitleAttrDef,
&pCdAttr)))
{
goto
Exit;
}
// Using the parent of the attributes,
set their values by specifying
// which attribute to set.
if (RC_BAD( rc = pCdChild->setAttributeValueUINT(
pDb,
uiNoAttrDef,
(FLMUINT)2)))
{
goto
Exit;
}
if (RC_BAD( rc = pCdChild->setAttributeValueNative(
pDb,
uiTitleAttrDef,
"Only 'Cause I Don't Have You")))
{
goto
Exit;
}
// It is always good practice to call
documentDone whenever updates to a
// document are completed.
if (RC_BAD( rc = pDb->documentDone(
uiCollectionDef,
pMusicElement->getId())))
{
goto
Exit;
}
// Commit the transaction
if ( RC_BAD( rc = pDb->transCommit()))
{
goto
Exit;
}
bTranStarted= FALSE;
// Now we want to read back our
document, and display it for all
// the world to see...:^)
// Start a read transaction
if ( RC_BAD( rc = pDb->transBegin(
XFLM_READ_TRANS, 0)))
{
goto
Exit;
}
bTranStarted = TRUE;
// Read the nodes. Start with the
document node.
if ( RC_BAD( rc = pDb->getFirstDocument(
uiCollectionDef, &pTmpNode)))
{
goto
Exit;
}
// printDocument is a simple function
that walks through the document
// and displays it, node by node as an XML document. It
assumes the
// node passed in is the root node. If it is not, then the
display will
// look a bit odd, as you will see later in this sample
program.
if (RC_BAD( rc = printDocument(
pDb, pTmpNode)))
{
goto
Exit;
}
// Commit the transaction
if ( RC_BAD( rc = pDb->transCommit()))
{
goto
Exit;
}
bTranStarted = FALSE;
// Start an update transaction
if ( RC_BAD( rc = pDb->transBegin(
XFLM_READ_TRANS, 0)))
{
goto
Exit;
}
bTranStarted = TRUE;
// Let's do a query on this document...
Our query (above) is
// deliberately miss-spelling some of the words. It is
looking for
// the music "tracks" with the title "We Are In Love".
// The syntax ~= means approximately equals, and is a "sounds
like"
// search.
if (RC_BAD( rc = pDbSystem->createIFQuery(
&pQuery)))
{
goto
Exit;
}
if (RC_BAD( rc = pQuery->setCollection(
uiCollectionDef)))
{
goto
Exit;
}
if (RC_BAD( rc = pQuery->setupQueryExpr(
pDb, szQueryString)))
{
goto
Exit;
}
if (RC_BAD( rc = pQuery->getFirst(
pDb, &pTrackNode)))
{
goto
Exit;
}
// Show the results...
printMessage( "Query:");
printMessage( (char *)szQueryString);
// This will print the tracks node,
followed by all of the closing parent
// nodes.
if (RC_BAD( rc = printDocument(
pDb, pTrackNode)))
{
goto
Exit;
}
// Always cleanup...
pQuery->Release();
pQuery = NULL;
// Commit the transaction
if ( RC_BAD( rc = pDb->transCommit()))
{
goto
Exit;
}
bTranStarted = FALSE;
// Let's create an index to make
searching easier. An index is essentially
// just another XML document to XFlaim, however it is created
in the dictionary
// collection rather than in a data collection. There are two
ways to create
// a document in XFlaim. One way (demonstrated above) is to
create each node
// of the document, one at a time. The other is to import the
document.
// Creating the index will demonstrate importing the
document. Our
// index definition is shown as follows:
//
/*
<xflaim:Index
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xflaim="http://www.novell.com/XMLDatabase/Schema"
xs:name="title_IX">
<xflaim:ElementComponent
xs:name="title"
xflaim:DictNum="1"
xflaim:IndexOn="value"/>
</xflaim:Index>"
*/
// For our purposes, we will create a local variable (pszIndex)
which
// holds the index document. We will import that using the
importDocument
// method of the pDb object.
// Import the index...
// We first need to create a BufferIStream object to stream
the document
// from...
// Start an update transaction
if ( RC_BAD( rc = pDb->transBegin(
XFLM_UPDATE_TRANS, 0)))
{
goto
Exit;
}
bTranStarted = TRUE;
if ( RC_BAD( rc = pDbSystem->openBufferIStream(
pszIndex,
strlen( pszIndex),
&pPosIStream)))
{
goto
Exit;
}
if ( RC_BAD( rc = pDb->import(
pPosIStream,
XFLM_DICT_COLLECTION)))
{
goto
Exit;
}
// Commit the transaction
if ( RC_BAD( rc = pDb->transCommit()))
{
goto
Exit;
}
bTranStarted = FALSE;
// Now, let's get some additional
documents in so we can do some more
// interesting stuff using a IF_DataVector. The documents
will be imported
// from the xmlfiles directory. The documents we are
interested in searching
// are the CD music documents. They have the following
format:
/*
<?xml version="1.0"?>
<disc>
<id>00097210</id>
<length>2420</length>
<title>Frank Sinatra / Blue skies</title>
<genre>cddb/jazz</genre>
<track index="1" offset="150">blue skies</track>
.
.
.
</disc>
*/
if ( RC_BAD( rc = pDb->transBegin(
XFLM_UPDATE_TRANS, 0)))
{
goto
Exit;
}
bTranStarted = TRUE;
// We will first need an input file
stream.
uiLoop = 0;
while (strlen( ppszPath[ uiLoop]))
{
if (RC_BAD(
rc = pDbSystem->openFileIStream( ppszPath[ uiLoop], &pIStream)))
{
goto Exit;
}
if (RC_BAD(
rc = pDb->import(
pIStream,
XFLM_DATA_COLLECTION)))
{
goto Exit;
}
uiLoop++;
}
// Commit the transaction
if ( RC_BAD( rc = pDb->transCommit()))
{
goto
Exit;
}
bTranStarted = FALSE;
// Let's get some IF_DataVectors to
work with.
if ( RC_BAD( rc = pDb->transBegin(
XFLM_READ_TRANS, 0)))
{
goto
Exit;
}
bTranStarted = TRUE;
if (RC_BAD( rc = pDbSystem->createIFDataVector(
&pFromKeyV)))
{
goto
Exit;
}
if (RC_BAD( rc = pDbSystem->createIFDataVector(
&pUntilKeyV)))
{
goto
Exit;
}
// We need to get the index.
// Now to search the index above for all document titles in
the index and
// display the document Id for each node and the title. Note
that the index
// number is known to be 1.
if (RC_BAD( rc = pDb->keyRetrieve(
uiIndex, NULL, XFLM_FIRST, pFromKeyV)))
{
goto
Exit;
}
if (RC_BAD( rc = pDb->keyRetrieve(
uiIndex, NULL, XFLM_LAST, pUntilKeyV)))
{
goto
Exit;
}
// Save the UntilKey value to compare
with later.
if (RC_BAD( rc = pUntilKeyV->outputKey(
pDb,
uiIndex,
FALSE,
&ucUntilKeyBuf[0],
MAX_KEY_SIZ,
&uiUntilKeyLen)))
{
goto
Exit;
}
for (;;)
{
// Display the
current Document Id and the title.
ui64DocId = pFromKeyV->getDocumentID();
uiTitleLen = sizeof(ucTitle);
if (RC_BAD(
rc = pFromKeyV->getNative( 0, &ucTitle[0],
&uiTitleLen)))
{
goto Exit;
}
sprintf( (char
*)&ucMsgBuf[0], "DocId:
%I64u\n%s\n", ui64DocId, ucTitle);
printMessage( (char
*)&ucMsgBuf[0]);
// Check to see
if this key matches the last or UntilKeyV value.
if (RC_BAD(
rc = pFromKeyV->outputKey(
pDb,
uiIndex,
FALSE,
&ucCurrentKeyBuf[0],
MAX_KEY_SIZ,
&uiCurrentKeyLen)))
{
goto Exit;
}
if (uiCurrentKeyLen
== uiUntilKeyLen)
{
if (memcmp( ucCurrentKeyBuf, ucUntilKeyBuf,
uiCurrentKeyLen) == 0)
{
break; // We are done!
}
}
// Get the next key.
if (RC_BAD(
rc = pDb->keyRetrieve( uiIndex, pFromKeyV, XFLM_EXCL, pFromKeyV)))
{
goto Exit;
}
}
if( RC_BAD( rc = pDb->transCommit()))
{
goto
Exit;
}
bTranStarted = FALSE;
// Close the database
pDb->Release();
pDb = NULL;
// Close all unused files
if ( RC_BAD( rc = pDbSystem->closeUnusedFiles(
0)))
{
goto
Exit;
}
// Re-open the database
if ( RC_BAD( rc = pDbSystem->dbOpen(
DB_NAME_STR,
NULL,
NULL,
&pDb)))
{
goto
Exit;
}
// Backup the database
if ( RC_BAD( rc = pDb->backupBegin(
XFLM_FULL_BACKUP,
XFLM_READ_TRANS,
0,
&pBackup)))
{
goto
Exit;
}
if ( RC_BAD( rc = pBackup->backup(
BACKUP_NAME_STR,
NULL,
NULL,
NULL)))
{
goto
Exit;
}
if (RC_BAD( rc = pBackup->endBackup()))
{
goto
Exit;
}
pBackup->Release();
pBackup = NULL;
// Close the database again
pDb->Release();
pDb = NULL;
if ( RC_BAD( rc = pDbSystem->closeUnusedFiles(
0)))
{
goto
Exit;
}
// Remove the database
if ( RC_BAD( rc = pDbSystem->dbRemove(
DB_NAME_STR,
NULL,
NULL,
TRUE)))
{
goto
Exit;
}
// Restore the database
if ( RC_BAD( rc = pDbSystem->dbRestore(
DB_NAME_STR,
NULL,
NULL,
BACKUP_NAME_STR,
NULL,
NULL)))
{
goto
Exit;
}
// Rename the database
if ( RC_BAD( rc = pDbSystem->dbRename(
DB_NAME_STR,
NULL,
NULL,
NEW_NAME_STR,
TRUE,
NULL)))
{
goto
Exit;
}
// Copy the database
if ( RC_BAD( rc = pDbSystem->dbCopy(
NEW_NAME_STR,
NULL,
NULL,
DB_NAME_STR,
NULL,
NULL,
NULL)))
{
goto
Exit;
}
// Remove the new database
if ( RC_BAD( rc = pDbSystem->dbRemove(
NEW_NAME_STR,
NULL,
NULL,
TRUE)))
{
goto
Exit;
}
Exit:
if (bTranStarted && pDb)
{
(void)pDb->transAbort();
}
if (pCdChild)
{
pCdChild->Release();
}
if (pCdElement)
{
pCdElement->Release();
}
if ( pMusicElement)
{
pMusicElement->Release();
}
if (pCdAttr)
{
pCdAttr->Release();
}
if (pTrackNode)
{
pTrackNode->Release();
}
if ( pTmpNode)
{
pTmpNode->Release();
}
if (pQuery)
{
pQuery->Release();
}
if ( pPosIStream)
{
pPosIStream->Release();
}
if (pIStream)
{
pIStream->Release();
}
if (pFromKeyV)
{
pFromKeyV->Release();
}
if (pUntilKeyV)
{
pUntilKeyV->Release();
}
if ( pBackup)
{
pBackup->Release();
}
// Close the database object
if ( pDb)
{
pDb->Release();
}
if ( RC_BAD( rc))
{
sprintf( (char
*)ucMsgBuf, "Error %04X -- %s\n",
(unsigned)rc,
(char *)pDbSystem->errorString( rc));
printMessage( (char
*)ucMsgBuf);
}
// Shut down the XFlaim database
engine. This call must be made
// even if the init call failed. No more XFlaim calls should
be made
// by the application.
pDbSystem->exit();
pDbSystem->Release();
return( 0);
}
/***************************************************************************
Desc: Prints a string to stdout
****************************************************************************/
void printMessage(
char *
pszMessage,
FLMUINT
uiLevel)
{
unsigned int
uiLoop;
for (uiLoop =
0; uiLoop < uiLevel; uiLoop++)
{
#ifdef NLM
ConsolePrintf(
" ");
#else
printf( " ");
#endif
}
#ifdef NLM
ConsolePrintf( pszMessage);
#else
printf( "%s\n", pszMessage);
#endif
}
/*=============================================================================
Desc: Simple routine to display the contents of a document.
=============================================================================*/
RCODE printDocument(
IF_Db *
pDb,
IF_DOMNode * pRootNode
)
{
RCODE
rc = NE_XFLM_OK;
FLMBYTE
ucLine[ 200];
FLMBYTE *
pszLine;
FLMBOOL
bHasChildren = FALSE;
FLMBOOL
bHasNextSibling = FALSE;
FLMUINT
uiNodeType;
FLMBOOL
bHadAttributes;
FLMUINT
uiDataType;
char
szName[ 25];
FLMUINT
uiNameLen;
IF_DOMNode * pNode =
pRootNode;
char
szTemp[ 200];
FLMUINT
uiTemp;
FLMBOOL
bUnwinding = FALSE;
FLMBOOL
bHadValue = FALSE;
FLMUINT
uiThisLevel = 0;
FLMUINT
uiNextLevel = 0;
pNode->AddRef();
pszLine = &ucLine[0];
bHadAttributes = FALSE;
while (pNode)
{
bHadValue = FALSE;
if (pszLine
!= &ucLine[0])
{
printMessage(
(char *)ucLine, uiThisLevel);
pszLine =
&ucLine[0];
}
uiThisLevel = uiNextLevel;
uiNodeType = pNode->getNodeType();
// Get the
nameId for the node
if (uiNodeType
== DOCUMENT_NODE)
{
if (!bUnwinding)
{
sprintf( (char *)pszLine,
"<doc");
}
else
{
sprintf( (char *)pszLine,
"</doc>");
}
pszLine +=
strlen( (char *)pszLine);
}
else
{
if (RC_BAD( rc = pNode->getLocalName( pDb, szName,
50, &uiNameLen)))
{
goto Exit;
}
if (!bUnwinding)
{
sprintf( (char *)pszLine,
"<%s", szName);
}
else
{
sprintf( (char *)pszLine,
"</%s>", szName);
}
pszLine +=
strlen( (char *)pszLine);
}
// Not the nicest
thing to do, but what can it works...
if (bUnwinding)
{
goto GetParent;
}
if (RC_BAD(
rc = processAttributes( pDb, pNode, &pszLine)))
{
goto Exit;
}
// Value check.
if (RC_BAD(
rc = pNode->getDataType( pDb, &uiDataType)))
{
goto Exit;
}
switch (uiDataType)
{
case XFLM_TEXT_TYPE:
{
bHadValue = TRUE;
if (RC_BAD( rc = pNode->getNative( pDb, szTemp,
0, 200, &uiTemp)))
{
goto Exit;
}
sprintf( (char *)pszLine,
">%s", szTemp);
pszLine += (uiTemp + 1);
break;
}
case XFLM_NUMBER_TYPE:
{
bHadValue = TRUE;
if (RC_BAD( rc = pNode->getUINT( pDb, &uiTemp)))
{
goto Exit;
}
sprintf( (char *)szTemp, "%u",
uiTemp);
sprintf( (char *)pszLine,
">%s", szTemp);
pszLine += (strlen( (char *)szTemp) +
1);
break;
}
// Could also get binary data, but we won't handle it here.
}
// We need to
know if this node has children to know how to close the line.
if (RC_BAD(
rc = pNode->hasChildren( pDb, &bHasChildren)))
{
goto Exit;
}
// If we had a
value, then close off the line.
if (uiDataType
== XFLM_TEXT_TYPE ||
uiDataType ==
XFLM_NUMBER_TYPE)
{
sprintf( (char
*)pszLine, "</%s>", szName);
}
else
{
sprintf( (char
*)pszLine, "%s>", bHasChildren ?
"" : "/");
}
// Children
if (bHasChildren
&& !bHadValue)
{
// Get the child node.
if (RC_BAD( rc = pNode->getFirstChild( pDb, &pNode)))
{
goto Exit;
}
uiNextLevel++;
continue;
}
// Siblings -
first one may be an attribute.
if (RC_BAD(
rc = pNode->hasNextSibling( pDb, &bHasNextSibling)))
{
goto Exit;
}
if (bHasNextSibling)
{
if (RC_BAD( rc = pNode->getNextSibling( pDb, &pNode)))
{
if (rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = NE_XFLM_OK;
goto GetParent;
}
goto Exit;
}
continue;
}
GetParent:
bUnwinding = FALSE;
if (uiNextLevel)
{
--uiNextLevel;
}
if (RC_BAD(
rc = pNode->getParentNode( pDb, &pNode)))
{
if (rc != NE_XFLM_DOM_NODE_NOT_FOUND)
{
goto Exit;
}
rc =
NE_XFLM_OK;
pNode->Release();
pNode = NULL;
}
else
{
if (RC_BAD( rc = pNode->hasNextSibling( pDb, &bHasNextSibling)))
{
goto Exit;
}
if (bHasNextSibling)
{
if (RC_BAD( rc = pNode->getNextSibling( pDb, &pNode)))
{
goto Exit;
}
continue;
}
bUnwinding =
TRUE;
}
}
// Print the
last line.
printMessage( (char *)ucLine);
Exit:
return( rc);
}
/*=============================================================================
Desc: Formatter for displaying attributes.
=============================================================================*/
RCODE processAttributes(
IF_Db *
pDb,
IF_DOMNode * pNode,
FLMBYTE **
ppszLine
)
{
RCODE
rc = NE_XFLM_OK;
IF_DOMNode * pAttrNode = NULL;
FLMBOOL
bHasAttrs;
FLMBOOL
bHasNextSibling;
char
szName[ 50];
FLMUINT
uiNameLen;
FLMBYTE *
pszLine = *ppszLine;
FLMUINT
uiDataType;
FLMBYTE
szTemp[ 200];
FLMUINT
uiTemp;
if (RC_BAD( rc = pNode->hasAttributes(
pDb, &bHasAttrs)))
{
goto
Exit;
}
if (!bHasAttrs)
{
// rc == NE_XFLM_OK
goto
Exit;
}
// We have attributes. Let's get them and
add them to the line.
if (RC_BAD( rc = pNode->getFirstAttribute(
pDb, &pAttrNode)))
{
goto
Exit;
}
for (;;)
{
if (RC_BAD(
rc = pAttrNode->getLocalName( pDb, szName, 50, &uiNameLen)))
{
goto Exit;
}
sprintf( (char
*)pszLine, " %s", szName);
pszLine += (uiNameLen +
1);
if (RC_BAD(
rc = pAttrNode->getDataType( pDb, &uiDataType)))
{
goto Exit;
}
switch (uiDataType)
{
case XFLM_TEXT_TYPE:
{
if (RC_BAD( rc = pAttrNode->getNative( pDb, (char
*)szTemp, 0, 200, &uiTemp)))
{
goto Exit;
}
sprintf( (char *)pszLine,
"=\"%s\"", szTemp);
pszLine += (uiTemp + 3);
break;
}
case XFLM_NUMBER_TYPE:
{
if (RC_BAD( rc = pAttrNode->getUINT( pDb, &uiTemp)))
{
goto Exit;
}
sprintf( (char *)szTemp, "%u",
uiTemp);
sprintf( (char *)pszLine,
"=\"%s\"", szTemp);
pszLine += (strlen( (char *)szTemp) +
3);
break;
}
// Could also get binary data, but we won't handle it here.
}
// Get the next
attribute
if (RC_BAD(
rc = pAttrNode->hasNextSibling( pDb, &bHasNextSibling)))
{
goto Exit;
}
if (!bHasNextSibling)
{
break;
}
// Get the next
sibling.
if (RC_BAD(
rc = pAttrNode->getNextSibling( pDb, &pAttrNode)))
{
if (rc == NE_XFLM_DOM_NODE_NOT_FOUND)
{
rc = NE_XFLM_OK;
break;
}
goto Exit;
}
}
// Update the line pointer on the way
out.
*ppszLine = pszLine;
Exit:
if (pAttrNode)
{
pAttrNode->Release();
}
return rc;
}