Qualche giorno fa ho rilasciato un piccolo strumento software, WinValue 2012, che permette di fare le conversioni delle valute internazionali. Questo semplice programma nasce dallo strumento interno al nostro software gestionale Vikings 2012 Business. I calcoli da fare per la conversione sono molto semplici, infatti in una tabella di un database memorizzeremo i cambi riferiti all’euro, poi basta solo rapportare i valori a quest’ultima valuta.
Il cuore del programma è il piccolo parser che occorre scrivere per prelevare i dati valutari da una pagina web. Nel mio caso ho utilizzato il sito della Banca d’Italia e per questo ho scritto un parser in C++ su MFC per prelevare i dati da una pagina web ( http://uif.bancaditalia.it/UICFEWebroot/cambiUltimiDisp_fw.do?type=14&lingua=it ) che ha una struttura tabellare. Ecco il mio codice racchiuso in una classe parser che raccoglie i valori in vari array.
// File InternetCambi.h #pragma once #include <afxtempl.h> #include <afxinet.h> class CInternetCambi { public: CInternetCambi(); ~CInternetCambi(); protected: CInternetSession m_session; CString m_strUrl; CStringArray m_arrPaese; CStringArray m_arrValuta; CStringArray m_arrSimbolo; CArray m_arrValore; BOOL OpenAndParse(void); BOOL GetOneValue(CStdioFile* pFile, CString strFirst); public: BOOL SetUrl(CString strUrl); CString GetPaese(int index); CString GetValuta(int index); CString GetSimbolo(int index); float GetValore(int index); int GetValuteCount(); }; // File InternetCambi.cpp #include "StdAfx.h" #include "InternetCambi.h" CInternetCambi::CInternetCambi() { m_strUrl.Empty(); } CInternetCambi::~CInternetCambi() { } BOOL CInternetCambi::SetUrl(CString strUrl) { m_strUrl = strUrl; return OpenAndParse(); } BOOL CInternetCambi::GetOneValue(CStdioFile* pFile, CString strFirst) { CString strPaese, strValuta, strSimbolo, strValore; strPaese = strFirst.Mid(16, strFirst.GetLength() - 21); if (!pFile->ReadString(strFirst)) return FALSE; strFirst.Trim(); strValuta = strFirst.Mid(16, strFirst.GetLength() - 21); if (!pFile->ReadString(strFirst)) return FALSE; strFirst.Trim(); strSimbolo = strFirst.Mid(17, strFirst.GetLength() - 22); if (!pFile->ReadString(strFirst)) return FALSE; if (!pFile->ReadString(strFirst)) return FALSE; strFirst.Trim(); strValore = strFirst.Mid(16, strFirst.GetLength() - 21); if (!pFile->ReadString(strFirst)) return FALSE; if (!pFile->ReadString(strFirst)) return FALSE; if (!pFile->ReadString(strFirst)) return FALSE; if (!pFile->ReadString(strFirst)) return FALSE; m_arrPaese.Add(strPaese); m_arrValuta.Add(strValuta); m_arrSimbolo.Add(strSimbolo); m_arrValore.Add((float)_wtof(strValore)); return TRUE; } BOOL CInternetCambi::OpenAndParse() { if (m_strUrl.IsEmpty()) return FALSE; DWORD_PTR dwFlags = 0; if (!::InternetGetConnectedState(&dwFlags, 0)) return FALSE; CHttpFile* pFile = NULL; TRY { pFile = (CHttpFile*)m_session.OpenURL(m_strUrl, 1, INTERNET_FLAG_TRANSFER_BINARY|INTERNET_FLAG_RELOAD); } CATCH (CInternetException, e) { e->ReportError(); m_session.Close(); return FALSE; } END_CATCH if (pFile == NULL) { pFile->Close(); m_session.Close(); delete pFile; return FALSE; } // Dato che siamo in ambiente unicode e il trasferimento // gestisce solo char ecco che faccio la conversione TCHAR szPath[MAX_PATH]; ::GetTempPath(MAX_PATH, szPath); CString strPath(szPath); strPath += _T("\\tempvalute.txt"); CStdioFile file; if (!file.Open(strPath, CFile::modeCreate| CFile::modeWrite|CFile::typeBinary)) return FALSE; CHAR buf[512]; int k; while (k = pFile->Read(buf, 512)) file.Write(buf, k); pFile->Close(); file.Close(); m_session.Close(); delete pFile; if (!file.Open(strPath, CFile::modeRead)) return FALSE; CString strRow, buf1, buf2; bool bInside = false; while (file.ReadString(strRow)) { strRow.Trim(); buf1 = strRow.Left(10); buf2 = strRow.Mid(16, strRow.GetLength() - 21); // Trovo la prima sequenza if (!bInside && buf1 == _T("<td width=") && buf2 == _T("AFGHANISTAN")) bInside = true; if (bInside && buf1 == _T("<td width=") && buf2 == _T("ZIMBABWE")) { if (!GetOneValue(&file, strRow)) return FALSE; bInside = false; } if (bInside) { if (!GetOneValue(&file, strRow)) return FALSE; } } file.Close(); ::DeleteFile(strPath); return TRUE; } CString CInternetCambi::GetPaese(int index) { return m_arrPaese.GetAt(index); } CString CInternetCambi::GetValuta(int index) { return m_arrValuta.GetAt(index); } CString CInternetCambi::GetSimbolo(int index) { return m_arrSimbolo.GetAt(index); } float CInternetCambi::GetValore(int index) { return m_arrValore.GetAt(index); } int CInternetCambi::GetValuteCount() { return (int)m_arrPaese.GetCount(); }
Questo è il codice della classe “CInternetCambi“, di certo è possibile migliorarla, ma il suo lavoro lo compie discretamente, inoltre con molta semplicità è possibile adattarla ad altri linguaggi. Spero che vi possa essere di utilità per lo sviluppo dei vostri software. Come sempre per approfondimenti o altre spiegazioni vi invito ad iscrivervi al forum sulla programmazione.