Click here to Skip to main content
15,896,475 members
Articles / Programming Languages / XML

Parsing XML using a C++ wrapper for SAX2

Rate me:
Please Sign up or sign in to vote.
4.75/5 (25 votes)
3 Aug 2005CPOL15 min read 375.8K   2.9K   77  
A basic C++ wrapper framework for the MSXML SAX2 API is presented.
// Filename: TestXmlSupportDlg.cpp
// S.Chan, Jul 17, 2005

#include "stdafx.h"
#include "TestXmlSupportDlg.h"
#include "TestXmlSupport.h"
#include "resource.h"

#include "XmlTester.h"
#include "BookCatalog.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// Font used in results list box.
static CFont courierFont;

// CAboutDlg
// Dialog used for App About box.
class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

    // Dialog data.
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides.
	//{{AFX_VIRTUAL(CAboutDlg)
	virtual void DoDataExchange(CDataExchange* pDX);
	//}}AFX_VIRTUAL

protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

// CAboutDlg /////////////////////////////////////////////////////////////////

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
    //{{AFX_MSG_MAP(CAboutDlg)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
    //{{AFX_DATA_INIT(CAboutDlg)
    //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CAboutDlg)
    //}}AFX_DATA_MAP
}

// CTestXmlSupportDlg ///////////////////////////////////////////////////////

BEGIN_MESSAGE_MAP(CTestXmlSupportDlg, CDialog)
    //{{AFX_MSG_MAP(CTestXmlSupportDlg)
    ON_WM_SYSCOMMAND()
    ON_WM_PAINT()
    ON_WM_QUERYDRAGICON()
    ON_BN_CLICKED(IDC_SELECT_XML_PATH, OnSelectXmlPathClicked)
    ON_BN_CLICKED(IDC_XML_PARSE, OnParseClicked)
    ON_BN_CLICKED(IDC_XML_ABORT, OnAbortClicked)
    ON_BN_CLICKED(IDC_CLEAR_RESULTS, OnClearClicked)
    ON_BN_CLICKED(IDC_SELECT_XSD_PATH, OnSelectXsdPathClicked)
    ON_BN_CLICKED(IDC_ADD_SCHEMA, OnAddSchema)
    ON_BN_CLICKED(IDC_REMOVE_SCHEMA, OnRemoveSchema)
    ON_BN_CLICKED(IDC_FIND_BOOK, OnFindBook)
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

CTestXmlSupportDlg::CTestXmlSupportDlg(CWnd* pParent /*=NULL*/)
: CDialog(IDD_TESTXMLSUPPORT_DIALOG, pParent)
{
    //{{AFX_DATA_INIT(CTestXmlSupportDlg)
    m_enableSchemaValidation = 0;
    m_enableSchemaLocation = 1;
    m_enableExhaustiveErrors = 0;
    //}}AFX_DATA_INIT

    // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

    // Create the XML tester.
    m_xmlTester = new CXmlTester;
    m_isParsing = false;

    // Create the book catalog.
    m_bookCatalog = new CBookCatalog;
}

CTestXmlSupportDlg::~CTestXmlSupportDlg()
{
    delete m_xmlTester;
    delete m_bookCatalog;
}

void CTestXmlSupportDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);

    //{{AFX_DATA_MAP(CTestXmlSupportDlg)
    DDX_Control(pDX, IDC_XML_PATH, m_xmlPathEdit);
    DDX_Check(pDX, IDC_ENABLE_SCHEMA_VAL, m_enableSchemaValidation);
    DDX_Check(pDX, IDC_USE_SCHEMA_LOCATION, m_enableSchemaLocation);
    DDX_Check(pDX, IDC_EXHAUSTIVE_ERRORS, m_enableExhaustiveErrors);
    DDX_Control(pDX, IDC_PARSING_DELAY, m_parsingDelayEdit);
    DDX_Control(pDX, IDC_XML_RESULTS, m_resultsListBox);
    DDX_Control(pDX, IDC_SCHEMA_NAMESPACE, m_namespaceEdit);
    DDX_Control(pDX, IDC_SCHEMA_XSD_PATH, m_xsdPathEdit);
    DDX_Control(pDX, IDC_BOOK_ID, m_bookIdEdit);
    //}}AFX_DATA_MAP
}

BOOL CTestXmlSupportDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    
    // Add "About..." menu item to system menu.
    
    // IDM_ABOUTBOX must be in the system command range.
    ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
    ASSERT(IDM_ABOUTBOX < 0xF000);
    
    CMenu* pSysMenu = GetSystemMenu(FALSE);
    if (pSysMenu != NULL)
    {
        CString strAboutMenu;
        strAboutMenu.LoadString(IDS_ABOUTBOX);
        if (!strAboutMenu.IsEmpty())
        {
            pSysMenu->AppendMenu(MF_SEPARATOR);
            pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
        }
    }
    
    // Set the icon for this dialog.  The framework does this automatically
    // when the application's main window is not a dialog
    SetIcon(m_hIcon, TRUE);			// Set big icon
    SetIcon(m_hIcon, FALSE);		// Set small icon
    
    // Set the parsing delay to 0.
    m_parsingDelayEdit.SetWindowText("0");

    // Change to a fixed sized font in the results list box
    // and enable its horizontal scrollbar by increasing extent.
    courierFont.CreatePointFont(80, "Courier");
    m_resultsListBox.SetFont(&courierFont);
    m_resultsListBox.SetHorizontalExtent(800);

    return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTestXmlSupportDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
    if ((nID & 0xFFF0) == IDM_ABOUTBOX)
    {
        CAboutDlg dlgAbout;
        dlgAbout.DoModal();
    }
    else
    {
        CDialog::OnSysCommand(nID, lParam);
    }
}

// If you add a minimize button to your dialog, you will need the code below
// to draw the icon.  For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CTestXmlSupportDlg::OnPaint() 
{
    if (IsIconic())
    {
        CPaintDC dc(this); // device context for painting
        
        SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
        
        // Center icon in client rectangle
        int cxIcon = GetSystemMetrics(SM_CXICON);
        int cyIcon = GetSystemMetrics(SM_CYICON);
        CRect rect;
        GetClientRect(&rect);
        int x = (rect.Width() - cxIcon + 1) / 2;
        int y = (rect.Height() - cyIcon + 1) / 2;
        
        // Draw the icon
        dc.DrawIcon(x, y, m_hIcon);
    }
    else
    {
        CDialog::OnPaint();
    }
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTestXmlSupportDlg::OnQueryDragIcon()
{
    return (HCURSOR) m_hIcon;
}

void CTestXmlSupportDlg::OnSelectXmlPathClicked()
{
    // Show a file selector dialog.
    TCHAR szFilters[] = _T ("XML files (*.xml)|*.xml|All files (*.*)|*.*||");
    CFileDialog dlg(TRUE, _T ("xml"), _T ("*.xml"), OFN_FILEMUSTEXIST, szFilters);
    if ( dlg.DoModal() == IDOK )
    {
        // Set the xml path displayed in the edit box.
        CString xmlPath = dlg.GetPathName();
        m_xmlPathEdit.SetWindowText(xmlPath);
    }
}

void CTestXmlSupportDlg::OnParseClicked()
{
    UpdateData(TRUE);

    // Get the XML path supplied by user.
    CString strXmlPath;
    m_xmlPathEdit.GetWindowText(strXmlPath);
    if ( strXmlPath.IsEmpty() )
    {
        AfxMessageBox("You must supply the XML file path (or HTTP URL).");
        return;
    }

    // Clear the results list box.
    m_resultsListBox.ResetContent();

    // Get the parsing delay.
    CString strDelay;
    m_parsingDelayEdit.GetWindowText(strDelay);
    int parsingDelay = atoi((LPCSTR)strDelay);

    // Initialize the XML tester with parsing options.
    m_xmlTester->AttachResultsWnd(&m_resultsListBox);
    m_xmlTester->SetParsingDelay(parsingDelay);
    m_xmlTester->SetAbort(false);
    m_xmlTester->EnableSchemaValidation(m_enableSchemaValidation > 0 ? true : false);
    m_xmlTester->EnableSchemaLocation(m_enableSchemaLocation > 0 ? true : false);
    m_xmlTester->EnableExhaustiveErrors(m_enableExhaustiveErrors > 0 ? true : false);

    // Clear the book catalog.
    m_bookCatalog->DeleteBooks();

    // Do the parsing.
    m_isParsing = true;
    bool result = m_xmlTester->ParseXml((LPCSTR)strXmlPath);
    m_isParsing = false;
    if ( !result )
    {
        m_resultsListBox.InsertString(-1, "Log: Parsing failed.");
    }

    // Parse a second time using the book catalog.
    if ( result )
    {
        m_resultsListBox.InsertString(-1, " ");
        m_resultsListBox.InsertString(-1, "Log: Building book catalog...");

        // Build the book catalog.
        m_bookCatalog->BuildFromXml((LPCSTR)strXmlPath);

        CString msg;
        msg.Format("Log: Book catalog now contains %d books.", m_bookCatalog->GetBookCount());
        m_resultsListBox.InsertString(-1, msg);
    }
}

void CTestXmlSupportDlg::OnAbortClicked()
{
    // Abort was requested.
    if ( m_isParsing )
        m_xmlTester->SetAbort(true);
}

void CTestXmlSupportDlg::OnClearClicked()
{
    // Clear the results list box.
    m_resultsListBox.ResetContent();
}

void CTestXmlSupportDlg::OnSelectXsdPathClicked()
{
    // Show a file selector dialog.
    TCHAR szFilters[] = _T ("XSD files (*.xsd)|*.xsd|All files (*.*)|*.*||");
    CFileDialog dlg(TRUE, _T ("xsd"), _T ("*.xsd"), OFN_FILEMUSTEXIST, szFilters);
    if ( dlg.DoModal() == IDOK )
    {
        // Set the xsd path displayed in the edit box.
        CString xsdPath = dlg.GetPathName();
        m_xsdPathEdit.SetWindowText(xsdPath);
    }
}

void CTestXmlSupportDlg::OnAddSchema()
{
    UpdateData(TRUE);

    // Namespace is allowed to be empty string.
    CString strNamespace;
    m_namespaceEdit.GetWindowText(strNamespace);

    // Get the XSD path.
    CString strXSD;
    m_xsdPathEdit.GetWindowText(strXSD);
    if ( strXSD.IsEmpty() )
    {
        AfxMessageBox("You must supply the XSD file path.");
        return;
    }

    // Add the schema.
    m_xmlTester->AttachResultsWnd(&m_resultsListBox);
    m_xmlTester->AddValidationSchema((LPCSTR)strNamespace, (LPCSTR)strXSD);
}

void CTestXmlSupportDlg::OnRemoveSchema()
{
    UpdateData(TRUE);

    // Namespace is allowed to be empty string.
    CString strNamespace;
    m_namespaceEdit.GetWindowText(strNamespace);

    // Remove the schema.
    m_xmlTester->AttachResultsWnd(&m_resultsListBox);
    m_xmlTester->RemoveValidationSchema((LPCSTR)strNamespace);
}

void CTestXmlSupportDlg::OnFindBook()
{
    UpdateData(TRUE);

    // Get the Book Id.
    CString strBookId;
    m_bookIdEdit.GetWindowText(strBookId);
    if ( strBookId.IsEmpty() )
    {
        AfxMessageBox("The book ID must be supplied.");
        return;
    }

    // Check for empty catalog.
    if ( m_bookCatalog->GetBookCount() == 0 )
    {
        AfxMessageBox("The book catalog is empty.");
        return;
    }

    // Find the book.
    CString msg;
    const CBook* pBook = m_bookCatalog->FindBook((LPCSTR)strBookId);
    if ( pBook == NULL )
    {
        msg.Format("Unable to find book, %s.", strBookId);
        AfxMessageBox(msg);
        return;
    }
    else
    {
        msg = pBook->ToString().c_str();
        AfxMessageBox(msg);
    }
}

// END

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Web Developer
Canada Canada
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions