Summary
This application uses WTL, COM, XML, HTML, DHTML and
JavaScript. It will demonstrate creating a custom command bar that includes two combo boxes and
the creation of XML documents. It will also demonstrate dynamically inserting new elements into
the XML document, transforming it using XSL, and dynamically inserting the
resulting HTML into a HTML page. It will also show how
to use a HTML and images from resources.
Overview
Once upon a time I had a project for a client that involved converting text files containing
summaries of news articles, culled from various sources around the world,
into XML documents. The XML would then be entered into a database. After this
phase was complete I put together a prototype of an editor to create the XML
documents directly without the intermediary text files. For various reasons the
client was never heard from again.
During the development of this prototype I ran into several
problems that I could find no previous examples of so I thought other developers
may find my solutions of value.
Details
The application is written using WTL to keep it a small as possible and
reduce the number redistributable files. It uses an XML based configuration
document to control the contents of some combo boxes. This allows easy
extensibility by the end user.
A splitter frame is used to display a form view in the
left pane and a HTML view in the right pane. On start up the right pane is full
screen.
m_Splitter.SetSinglePaneMode(SPLIT_PANE_RIGHT);
To start a new document select File->New. A dialog
will be displayed asking for the volume and issue. This is used to name the file
and is embedded in the XML document as an attribute of the root element. After
clicking OK a new document is created using MSXML which contains the basic
elements necessary. The test1_1.xml file in the samples shows this basic
file.
You will notice the customized command bar that includes two combo boxes.
This are filled in a startup by reading the config.xml file. The contents are
also used to create the new XML document framework.
After clicking OK on the New Document dialog the left pane is
displayed full screen. The user can then enter the information necessary and
select keywords that apply to the article and select the date. When complete
they click on the Enter button.
After the Enter button is clicked the data is recovered from
the fields using DDX and entered into the previously created XML document
template. To place the article in the document correctly a XPATH search is
formatted from the current combo box selections and the node is selected. The
data is then appended to this node.
CString strSearch;
strSearch.Format(_T("/*/*[@name=\"%s\"]"), m_ComboBar.GetSection());
if( FAILED(m_pNewDoc->selectSingleNode(A2OLE(strSearch), &pSection) ) )
return FALSE;
After this step, the newly created node is transformed by XSL and sent to the
HTML view. To reduce the number of support files and because the XSL was small I
included it a string resource.
CString strXSL;
strXSL.LoadString(IDS_XSL);
short bSuccess;
if( FAILED(m_pXSLDoc->loadXML(A2OLE(strXSL),&bSuccess) ) )
return FALSE;
CComBSTR bstrOutput;
if( SUCCEEDED(pArticle->transformNode(m_pXSLDoc,&bstrOutput) ) )
m_HTMLView.InsertElement(OLE2A(bstrOutput));
Once the transformed XML is sent to the HTML view it is
inserted into the current document. This is accomplished by getting the
IWebBrowser2 interface from the HTML control, finding the body element of the
document and inserting the HTML before the end of the last element. Again to
reduce support files, the HTML page is stored as a resource. Expanding or
collapsing the article is accomplished by JavaScript connected to the image
next to the title.
BOOL CXMLView::GetBody()
{
CComPtr<IWEBBROWSER2> spBrowser;
if( SUCCEEDED(QueryControl(__uuidof(spBrowser), reinterpret_cast<void**>(&spBrowser))) )
{
CComPtr<IDISPATCH> pDisp;
if( SUCCEEDED(spBrowser->get_Document(&pDisp)) && pDisp)
{
element if( SUCCEEDED(pDisp.QueryInterface(&m_pDoc)) && m_pDoc
)
{ if(SUCCEEDED(m_pDoc->get_body(&m_pBody)) && m_pBody )
return TRUE;
}
}
}
return FALSE;
}
void CXMLView::InsertElement(CString strElement)
{
USES_CONVERSION;
if( !m_pBody )
{
if( !GetBody() )
{
MessageBox(_T("Body not found.\n\nPlease close application"), _T("Critical Error"), MB_ICONERROR);
return;
}
}
CComPtr<IDISPATCH> pDisp;
if( SUCCEEDED(m_pBody->get_all(&pDisp)) && pDisp)
{
CComQIPtr<IHTMLELEMENTCOLLECTION>
pColl(pDisp);
if(pColl)
{
long lCount;
if(SUCCEEDED(pColl->get_length(&lCount)) && lCount > 0)
{
ToggleElement(pColl);
pDisp.Release();
CComVariant varName,varIndex(lCount);
pColl->item(varName, varIndex, &pDisp);
CComQIPtr<IHTMLELEMENT> pElement(pDisp);
if(pElement)
pElement->insertAdjacentHTML(A2OLE("beforeEnd"), A2OLE(strElement));
}
}
}
}
Once the document has been
completed it can be saved by selecting File->Save. This will bring up a
Folder selection dialog.
Improvements
There is always room for improvement. Since this was created as a prototype I
left several thing unfinished. In the future I may enhance this to allow editing
of previously created documents.