Developer's Guide
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ex-dom-4.cpp
#include "p6loader.h"
#include "p6domxml.h"
#include "cconsolestream.h"
#include "cfilestream.h"
#include "namespaces.h"
using namespace P6R;
using namespace P6EXAMPLES;
P6DECLARE_CID( p6DOMXML );
P6DECLARE_CID( p6XpathExpression );
P6DECLARE_IID( IFileStreamInit );
P6DECLARE_IID( INamespacesInit );
namespace {
P6R::P6ERR getFileStream(const P6R::P6WCHAR *pszFilepath,P6R::p6IDataStream **ppIface)
{
P6ERR err;
if(P6SUCCEEDED(err = CFileStream::createInstance(NULL,VALIDATECOMPTR(IFileStreamInit,cpFileInit)))) {
if(P6SUCCEEDED(err = cpFileInit->initialize(pszFilepath))) {
err = cpFileInit.queryInterface(IID_p6IDataStream,ppIface);
}
}
return err;
}
P6R::P6ERR getDOMXML(P6R::p6IDataStream *pOutStream,P6R::p6IDOMXML **ppIface)
{
P6ERR err;
if(P6SUCCEEDED(err = p6CreateInstance(NULL,CID_p6DOMXML,VALIDATECOMPTR(p6IDOMXML,cpDOM)))) {
if(P6SUCCEEDED(err = cpDOM->initialize(P6DOMXML_NOFLAGS,pOutStream))) {
//
// Using detach() saves a reference counting operation
// and gives ownership to *ppIface.
//
cpDOM.detach(ppIface);
}
}
return err;
}
P6R::P6ERR getXPathEngine(P6R::p6IDataStream *pOutStream,P6R::p6IXpathExpression **ppIface)
{
P6ERR err;
if(P6SUCCEEDED(err = p6CreateInstance(NULL,CID_p6XpathExpression,VALIDATECOMPTR(p6IXpathExpression,cpXPath)))) {
if(P6SUCCEEDED(err = cpXPath->initialize(P6XPATH_NOFLAGS,pOutStream))) {
//
// Using detach() saves a reference counting operation
// and gives ownership to *ppIface.
//
cpXPath.detach(ppIface);
}
}
return err;
}
P6R::P6ERR getXMLCompile(P6R::p6IXMLCompile **ppIface)
{
P6ERR err;
if(P6SUCCEEDED(err = CNamespaces::createInstance(NULL,VALIDATECOMPTR(INamespacesInit,cpInit)))) {
if(P6SUCCEEDED(err = cpInit->initialize( 10 ))) {
//
// Define the namespace context for the XPath compile
// when XPath is used in XSLT the XSLT processor takes care of this step
//
if (P6SUCCEEDED( err = cpInit->defineNamespace( "start", 4, "http://www.p6r.com/books/type1", (P6UINT32)strlen( "http://www.p6r.com/books/type1" )))) {
if (P6SUCCEEDED( err = cpInit->defineNamespace( "last", 4, "http://www.p6r.com/books/type2", (P6UINT32)strlen( "http://www.p6r.com/books/type2" )))) {
err = cpInit.queryInterface(IID_p6IXMLCompile,ppIface);
}
}
}
}
return err;
}
// Notice how we use the XPath components directly. XPath is also used in our XSLT processor.
//
P6R::P6ERR runDOM( P6R::p6IConsole *pConsole, p6IDataStream *pStreamDebug )
{
P6WCHAR testStr[200];
P6UINT32 count = 0;
P6UINT32 number = 0;
P6INT32 retval = 0;
P6UINT32 length = 0;
P6UINT32 bufSize = 0;
P6ERR err = eOk;
P6ARG args[2];
// Same as a previous example except that here we have
// added two namespaces showing that "item" can be
// different if a namespace is used.
//
const P6CHAR* pXML =
"<?xml version='1.0' encoding='UTF-8' ?>" \
"<book xmlns:start='http://www.p6r.com/books/type1' " \
" xmlns:end='http://www.p6r.com/books/type2'>" \
"<title>P6R book of development</title>" \
"<TOC>" \
" <chapter>One</chapter>" \
" <chapter>Two</chapter>" \
"</TOC>" \
"<chapter>" \
" <section>" \
" <footnote>footnote 1.1.0</footnote>" \
" <para>1 2 3&#233;&#xE9; 4 5 6</para>" \
" <para>7 8 9 10 11</para>" \
" <testcase> abc <![CDATA[ ab&#233;c &gt; 123 ]]> hey there </testcase>" \
" </section>" \
" <section>" \
" <para>a b c d e f g h</para>" \
" <footnote>footnote 1.2.0</footnote>" \
" <footnote id='ab'>footnote 1.2.1</footnote>" \
" </section>" \
"</chapter>" \
"<chapter>" \
" <para>0 0 0 0 0 0 </para>" \
" <section>" \
" <para>i j k l m n o p</para>" \
" <footnote>footnote 1.3.0</footnote>" \
" </section>" \
"</chapter>" \
"<index>" \
" <start:item>Index 1.0</start:item>" \
" <start:item>Index 2.0</start:item>" \
" <abc>" \
" <item>Index 2.1</item>" \
" <item>Index 2.2</item>" \
" </abc>" \
" <item>Index 3.0</item>" \
"</index>" \
"<appendixA>" \
" <end:item>appendix A 1.0</end:item>" \
" <end:item>appendix A 2.0</end:item>" \
"</appendixA>" \
"<appendixB>" \
" <end:item>appendix B 1.0</end:item>" \
" <end:item>appendix B 2.0</end:item>" \
" <end:item>appendix B 3.0</end:item>" \
"</appendixB>" \
"<appendixC>" \
" <end:item>appendix C 1.0</end:item>" \
" <abc>" \
" <item>appendix C 2.0</item>" \
" </abc>" \
"</appendixC>" \
"</book>";
// [A] Create & initialize the components we need
if (P6FAILED( err = p6GetRuntimeIface( VALIDATECOMPTR( p6ISafeString, cpStr )))) return err;
if (P6FAILED( err = getFileStream(P6CTEXT("ctestdomfindnode.html"),cpOutStream.addressof()))) return err;
if (P6FAILED( err = getDOMXML(cpOutStream,cpDOM.addressof()))) return err;
if (P6FAILED( err = getXPathEngine(NULL,cpXPath.addressof()))) return err;
//
// You should look at getXMLCompile(). It sets up a context for
// the XPath compiles.
//
if(P6FAILED(err = getXMLCompile(cpContext.addressof()))) return err;
// [B] Stream the XML document into the DOM parser (can be done with one or many calls to processStream, see SAX2-2 example)
err = cpDOM->parse( cpStream.addressof() );
if (P6SUCCEEDED( err )) err = cpStream->beginStream();
cpStr->strlen( pXML, 100000, &bufSize );
if (P6SUCCEEDED( err )) err = cpStream->processStream( pXML, bufSize );
if (P6SUCCEEDED( err ))err = cpStream->endStream();
cpStream = NULL;
// [D] Here we pass in the "compile time context" so that the defined
// namespace prefixes (e.g., 'start', 'end') can be translated into their
// defined URLs. (Actually an XML QName [Qualified Name] is created.)
// NOTICE: that the prefixes (e.g., 'start', 'end', 'last') do not have to be
// the same since they are replaced by their URLs.
//
err = cpXPath->compileExpression( P6CTEXT("//last:item"), 19, cpContext );
if (P6SUCCEEDED( err = cpXPath->eval( cpDOM, NULL, NULL, &result )))
{
if (result.type != P6XPATH_TYPE_SET) {
P6AI_INT32(&args[1],result.type);
pConsole->writeStdout("Expected [ %1$ ] but got [ %2$ ]\n",&args[0],2,NULL);
return eFail;
}
number = 0;
err = result.pNodeSet->last( &number );
if (number != 6) {
P6AI_UINT32(&args[0],number);
pConsole->writeStdout("Expected [ 6 ] but got [ %1$ ]\n",&args[0],1,NULL);
return eFail;
}
count = 0;
while( P6SUCCEEDED( err ) && P6SUCCEEDED( err = result.pNodeSet->next( cpChild.addressofWithRelease() )))
{
retval = -1;
length = 200;
if (P6SUCCEEDED( err = cpChild->toString( testStr, &length )))
{
switch( count ) {
case 0: err = cpStr->wstrncmp( P6CTEXT("appendix A 1.0"), testStr, 14, &retval ); break;
case 1: err = cpStr->wstrncmp( P6CTEXT("appendix A 2.0"), testStr, 14, &retval ); break;
case 2: err = cpStr->wstrncmp( P6CTEXT("appendix B 1.0"), testStr, 14, &retval ); break;
case 3: err = cpStr->wstrncmp( P6CTEXT("appendix B 2.0"), testStr, 14, &retval ); break;
case 4: err = cpStr->wstrncmp( P6CTEXT("appendix B 3.0"), testStr, 14, &retval ); break;
case 5: err = cpStr->wstrncmp( P6CTEXT("appendix C 1.0"), testStr, 14, &retval ); break;
}
if (retval != 0) {
P6AI_INT32(&args[0],retval);
pConsole->writeStdout("Expected [ 0 ] but got [ %1$ ]\n",&args[0],1,NULL);
}
count++;
}
}
// -> we should hit the end of the nodeset enumerator
if (eEndOfRecord == err) err = eOk;
if (NULL != result.pNodeSet)
{
result.pNodeSet->release();
result.pNodeSet = NULL;
}
}
if (P6FAILED( err )) {
P6AI_ERR(&args[0],err);
pConsole->writeStdout("ERROR: Example failed with [ %1$ ]\n", &args[0], 1, NULL );
}
return err;
}
} // namespace
int main(int argc,char *argv[])
{
P6ERR err = eOk;
p6ComPtr<p6IDataStream> cpDebugStream;
P6ARG args[1];
if(P6SUCCEEDED(err = CConsoleStream::createInstance(NULL,VALIDATECOMPTR(p6IDataStream,cpDebugStream)))) {
if(P6SUCCEEDED(err = p6InitializeLoader(cpDebugStream,9,P6SCLF_NOFLAGS))) {
err = runDOM( cpConsole, cpDebugStream );
P6AI_ERR(&args[0],err);
cpConsole->writeStdout("runDOM result: [ %1$ ]\n",&args[0],1,NULL);
//
// Make sure to release the console interface
// before calling p6CleanupLoader() !! In this
// instance we don't let the smart pointer
// handle the cleanup.
//
cpConsole = NULL;
}
else printf("ERROR: Failed to retrieve console interface [ %x ]\n", err );
}
else printf("ERROR: Failed to initialize the loader [ %x ]\n", err );
}
else printf( "ERROR: Failed to create CConsoleStream [ %x ]\n", err );
return err;
}