Как получить курс валюты средствами C#
Одному из наших новых корпоративных сервисов требуется регулярно получать актуальный курс валюты. Нас интересуют евро и доллары, особенно сейчас, когда курс стал резко скакать. Чтобы успевать за обновлениями и освободить вечно занятых сотрудников от этой рутиной операции, было решено автоматизировать этот процесс. К счастью, исходный код проекта у нас имеется.
Особого времени на решения этой задачи не было, и я надеялся, что в сети найдется готовый снипет, способный решить проблему за пару минут. Увы, ни к чему хорошему мои поиски не привели. Варианты, попавшие под зоркий глаз Google, демонстрировали банальный анализ страницы центрального банка с перечнем всех доступных курсов валют при помощи регулярного выражения. Не знаю, зачем авторы этих решений мучились с регулярными выражениями, если сайт центрального банка всегда рад отдать интересующую информацию в виде XML/SOAP.
Вариант с SOAP мне показался более затратным (по времени), поэтому было решено получать все необходимые данные в XML. Для этого требуется сделать GET запрос по адресу http://www.cbr.ru/scripts/XML_daily.asp. Ответом будет готовый для анализа XML, содержащий информацию о курсах различных валют (на текущую дату). Кусок такого XML привожу ниже:
<ValCurs Date="18.03.2014" name="Foreign Currency Market">
<Valute ID="R01010">
<NumCode>036</NumCode>
<CharCode>AUD</CharCode>
<Nominal>1</Nominal>
<Name>Австралийский доллар</Name>
<Value>33,2054</Value>
</Valute>
<Valute ID="R01020A">
<NumCode>944</NumCode>
<CharCode>AZN</CharCode>
<Nominal>1</Nominal>
<Name>Азербайджанский манат</Name>
< Value>46,7958</Value>
</Valute>
<Valute ID="R01035">
<NumCode>826</NumCode>
<CharCode>GBP</CharCode>
<Nominal>1</Nominal>
<Name>Фунт стерлингов Соединенного королевства</Name>
<Value>60,9791</Value>
</Valute>
<Valute ID="R01060">
<NumCode>051</NumCode>
<CharCode>AMD</CharCode>
<Nominal>1000</Nominal>
<Name>Армянских драмов</Name>
<Value>88,2613</Value>
</Valute>
<Valute ID="R01090">
<NumCode>974</NumCode>
<CharCode>BYR</CharCode>
<Nominal>10000</Nominal>
<Name>Белорусских рублей</Name>
<Value>37,2654</Value>
</Valute>
Получение курсов валют средствами C#
Решить задачу получения курса средствами C# достаточно просто. Возможно, это не совсем оптимальное решение (я пока не считаю себя экспертом в .NET), но оно работает шустро и прекрасно выполняет поставленную задачу. Разбирать XML я решил при помощи класса XmlTextReader. Вот что у меня получилось:
using System.Xml;
//Инициализируем объекта типа XmlTextReader и
//загружаем XML документ с сайта центрального банка
XmlTextReader reader = new XmlTextReader ("http://www.cbr.ru/scripts/XML_daily.asp" );
//В эти переменные будем сохранять куски XML
//с определенными валютами (Euro, USD)
string USDXml = "" ;
string EuroXML = "" ;
//Перебираем все узлы в загруженном документе
while (reader.Read())
{
//Проверяем тип текущего узла
switch (reader.NodeType)
{
//Если этого элемент Valute, то начинаем анализировать атрибуты
case XmlNodeType.Element:
if (reader.Name == "Valute")
{
if (reader.HasAttributes)
{
//Метод передвигает указатель к следующему атрибуту
while (reader.MoveToNextAttribute())
{
if (reader.Name == "ID")
{
//Если значение атрибута равно R01235, то перед нами информация о курсе доллара
if (reader.Value == "R01235")
{
//Возвращаемся к элементу, содержащий текущий узел атрибута
reader.MoveToElement();
//Считываем содержимое дочерних узлом
USDXml = reader.ReadOuterXml();
}
}
//Аналогичную процедуру делаем для ЕВРО
if (reader.Name == "ID")
{
if (reader.Value == "R01239")
{
reader.MoveToElement();
EuroXML = reader.ReadOuterXml();
}
}
}
}
}
break;
}
}
//Из выдернутых кусков XML кода создаем новые XML документы
XmlDocument usdXmlDocument = new XmlDocument ();
usdXmlDocument.LoadXml(USDXml);
XmlDocument euroXmlDocument = new XmlDocument ();
euroXmlDocument.LoadXml(EuroXML);
//Метод возвращает узел, соответствующий выражению XPath
XmlNode xmlNode = usdXmlDocument.SelectSingleNode( "Valute/Value");
//Считываем значение и конвертируем в decimal. Курс валют получен
decimal usdValue = Convert.ToDecimal(xmlNode.InnerText);
xmlNode = euroXmlDocument.SelectSingleNode( "Valute/Value");
decimal euroValue = Convert.ToDecimal(xmlNode.InnerText);
В принципе, можно было обойтись средствами одного XmlTextReader, но тогда код получился бы более сложным для восприятия. Пришлось бы работать с элементами последовательно и сохранять промежуточные значения для дальнейшего анализа. Смешанный подход позволил избавиться от излишеств.
Кстати, эту же задачу реально решить при помощи одного класса XmlDocument. XML файл с информацией о курсах валют небольшого размера, поэтому использование XmlDocument вполне оправданно. Для больших файлов XmlDocument не подходит, т.к. все данные из файла сразу же загружаются в память и ее элементарно может не хватить.
2014-03-19 в 21:32:57
Интересно!
У меня по работе тоже часто стоит задача в анализе xml. Нам в этом очень помогает механизм JAXB ru.m.wikipedia.org/wiki/Java_Architecture_for_XML_Binding
То есть мы можем определенным xml ставить в соответствии свои java классы и после демаршалинга работать с объектом, который хранит в своих свойствах данные из xml. Нам приходт строка xml. Мы ее демаршалим и получаем наш объект. Очень удобно и не нужно писать свой парсер. Не знаю есть ли подобный механизм под .NET
2014-03-20 в 09:55:33
2Kastor,
Да, в .NET тоже так можно. Насколько мне известно есть несколько способов решения подобной задачи, но самый простой способ - воспользоваться ExpandoObject. Возможность появилась в четвертой версии .NET Framework. С их помощью можно собрать произвольный объект из XML.