Разбор XML-файлов в .NET

Вячеслав Гринин, February 27, 2010

Заметил я вот какую странную вещь – мало я пишу про ASP.NET, несмотря на то, что сам я в основном программирую именно под ASP.NET. И решил я начинать исправлять эту ситуацию потихоньку. И теперь в нашем блоге будет появляться все больше статей, посвященных ASP.NET, да и вообще технологии .NET. И сегодня будет именно такая статья. Посвящена она работе с XML-файлами.

Вы уже наверное заметили, что я люблю парсить XML-файлы. Да просто формат этот очень уж удобный для передачи и хранения различных данных. Взять вот хотя бы тот же gismeteo-информер, который я уже успел распарсить несколькими различными методами. И все эти методы касались языка JavaScript. А теперь попробуем распарсить его и в .NET. Но давайте уж возьмем не сам по себе информер, а кое-какие другие XML-данные с сайта gismeteo.

Исходные данные: Mozilla с установленным FireBug, открытая в нем страница http://informer.gismeteo.ru/getcode/xml.php. Видите внизу три списка, соответственно: стран, регионов и городов? Так вот, когда Вы в нем выбираете страну, то в списки регионов и городов загружаются регионы и города выбранной страны. При этом происходит запрос на сервер gismeteo вот такого вида: http://informer.gismeteo.ru/getcode/index.php. При этом, в POST-параметрах запроса передаются параметры: a1=156 (для регионов), a2n=156 (для городов). 156 – это код России в справочниках gismeteo.

А назад мы получаем XML-файл вот такого вида (здесь я приведу лишь кусок файла):

<cities>
<city value="11845" old_id="99855">Абаза</city>
<city value="4723" old_id="29865">Абакан</city>
<city value="4659" old_id="29485">Абан</city>
<city value="4546" old_id="28581">Абатский</city>
<city value="4607" old_id="28815">Абдулино</city>
<city value="11657" old_id="99666">Абинск</city>
<city value="12874" old_id="89157">Автуры</city>
<city value="3967" old_id="23383">Агата</city>
</cities>

Итак захотел я распарсить именно этот файл. Скажу даже зачем мне это нужно. А вот нужно мне по названию города на русском языке получить соответствующий XML-документ с данными о погоде в этом городе. А XML этот лежит по вот такому пути: http://informer.gismeteo.ru/xml/99855_1.xml , где 99855 – это аттрибут old_id нужного мне города. Понятно, что разобранный файл я сохраню затем в базу данных, откуда и буду выбирать айдишники нужных мне городов. Наверное, можно было попросить эту базу у gismeteo, но я так и не нашел на их сайте работающих e-mail’ов. :) Да и не ищем мы легких путей. Будем самостоятельно парсить их базу .

Итак, вот готовый код для разбора подобного рода XML-файла:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.XPath;
using System.IO;

namespace ParseXML
{
class Program
{
static void Main(string[] args)
{
// Собственно XML
string xml = @"
<cities>
<city value=""11845"" old_id=""99855"">Абаза</city>
<city value=""4723"" old_id=""29865"">Абакан</city>
<city value=""4659"" old_id=""29485"">Абан</city>
<city value=""4546"" old_id=""28581"">Абатский</city>
<city value=""4607"" old_id=""28815"">Абдулино</city>
<city value=""11657"" old_id=""99666"">Абинск</city>
<city value=""12874"" old_id=""89157"">Автуры</city>
<city value=""3967"" old_id=""23383"">Агата</city>
</cities>";
// ЗАгружаем строку в XPathDocument
XPathDocument xPathDoc = new XPathDocument(new StringReader(xml));
XPathNavigator xPathNav = xPathDoc.CreateNavigator();
// Выбираем нужные узлы
XPathNodeIterator xPathIter = xPathNav.Select("/cities/city");
// Пробегаем по всем узлам
foreach (XPathNavigator nav in xPathIter)
{
// Метод GetAttribute извлекает аттрибут узла
int id = Int32.Parse(nav.GetAttribute("value", ""));
int old_id = Int32.Parse(nav.GetAttribute("old_id", ""));
// Свойство Value узла дает нам содержимое XML-узла, то есть строку,
// которая содержится между открывающим и закрывающим XML-тегами
Console.WriteLine("{0} \t id={1}, \t http://informer.gismeteo.ru/xml/{2}_1.xml",
nav.Value, id, old_id);
}
Console.ReadLine();
}
}
}

Вот и все. Думаю, что код этот очень простой и в дополнительном комментировании не нуждается.

Кстати, скачать бесплатно мобильные игры java Вы можете на сайте mobi4uk4a.ru. Я скачал себе набор пасьянсов, теперь есть чем заняться пока еду в метро.

Нам и нашим четвероногим друзьям нужна квалифицированная ветеринарная помощь, ведь только в этом случае можно быть уверенным, что Ваш домашний любимец будет здоров и проживет долгую жизнь рядом с Вами. Не стоит надеяться на “авось”, если Ваш питомец заболел, и ни в коем случае нельзя заниматься самолечением – сразу идите в ветеринарную клинику “Биоконтроль”

На днях нашел замечательный ресурс посвященный фрилансу. Софт, книги, статьи для вебмастера – здесь есть все необходимое для того, чтобы Ваша работа в сфере web доставляла Вам истинное удовольствие.

Парсинг XML в ActionScript 3.0

Вячеслав Гринин, June 21, 2009

Возникла у меня однажды задача – создать Flash-контрол, в котором постоянно сверху вниз прокручивается список неких сайтов, причем при наведении мыши на этот контрол прокручивание останавливается, а содержимое пункта списка, на который наведена мышь, разворачивается, и мы теперь можем наблюдать саму ссылку на сайт и краткое описание сайта внизу. Как-то так:

scroller

Собственно, хотелось создать универсальный контрол, такой, чтобы и список сайтов и все цвета, и скорость прокрутки, и вообще все изменяемые параметры хранились бы где-то отдельно от самого Flash-контрола, чтобы, когда дизайнеру захочется поменять оформление этого котнрола или его содержимое, он бы меня не дергал лишний раз. Разумное желание. И решил я остановиться на хранении всех этих данных в XML-файле.

Файл этот имеет вот такой формат:

<?xml version="1.0" encoding="UTF-8"?>
<config>
<control speed="10" indent="24.9"/>
<sites>
<site name="веб-разработка" link="easy4web.ru" 
url="http://easy4web.ru/" descr="веб-дизайнер и 
веб-программист срывают оковы, освещают темные 
места" height="38"/>
<site name="Яндекс" link="yandex.ru" url="http://yandex.ru/" descr="
Поиск от Яндекс. Найдется все!" height="38"/>
<site name="почта от google" link="gmail.com" url="http://gmail.com/"
 descr="Бесплатная почта от google. Попробуй, не пожалеешь." 
height="38"/>
</sites>
</config>

Здесь мы видим один корневой элемент <config> в который вложены: элемент <control> одержащий в себе атрибуты, касающиеся всего контрола в целом, и элемент <sites> содержащий в себе дочерние узлы <site>, каждый из которых описывает отдельный элемент прокручиваемого в контроле списка.

Осталось теперь разобраться как разобрать этот файл при помощи ActionScript.

Но для начала структурируем немного в виде классов информацию, хранящуюся в XML-файле.

Элемент <site> мы опишем следующим классом (файл SiteItem.as):

package inc{
public class SiteItem extends Object {
public var pName:String;
public var pLink:String;
public var pURL:String;
public var pDescr:String;
public var pHeight:Number;
public function SiteItem(p_Name:String, p_Link:String, p_URL:String, 
p_Descr:String, p_Height:Number){
pName=p_Name;
pLink=p_Link;
pURL=p_URL;
pDescr=p_Descr;
pHeight=p_Height;
}
}
}

Как видно, это просто класс с открытыми полями и одним конструктором. Ничего сложного.

А вот еще один класс, описывающий весь XML-файл (ScrollerParameters.as):

package inc{
public class ScrollerParameters extends Object{
public var list:Array;
public var indent:Number;
public var speed:Number;
public function ScrollerParameters(){
list=new Array();
}
}
}

Здесь также есть набор открытых полей и конструктор.

А вот и сам скрипт разбора XML-данных (scrollrequest.as).

package inc{
import flash.display.MovieClip;
import flash.net.URLRequest;
import flash.net.URLLoader;
import flash.events.*;
import flash.net.URLLoaderDataFormat;

public class scrollrequest extends MovieClip {
private var xml:XML;
public var parameters:ScrollerParameters=new ScrollerParameters();

public function scrollrequest(url:String) {
var loader:URLLoader=new URLLoader();
loader.dataFormat = URLLoaderDataFormat.TEXT;
loader.addEventListener(Event.COMPLETE, loadXML);
loader.load(new URLRequest(url));
}

private function loadXML(e:Event):void
{
try {
xml=new XML(e.target.data);
parseXML();
}
catch(e:TypeError) {
trace( "Could not parse text into XML" );
trace( e.message );
}
}

private function parseXML(){
var control:XML=xml["control"][0];
parameters.speed=control.attribute("speed");
parameters.indent=control.attribute("indent");
var sites:XMLList=xml["sites"][0].child("site");
for(var i:Number=0; i<sites.length(); i++){
var site=sites[i];
var s=new SiteItem(site.attribute("name"), site.attribute("link"), 
site.attribute("url"), site.attribute("descr"), 
site.attribute("height"));
parameters.list.push(s);
}
notifyListeners("LOAD");
}

private function notifyListeners(ev:String) {
var e:Event = new Event(ev, false, false);
dispatchEvent(e);
}

}

}

Как можно заметить, загрузка XML-файла происходит в конструкторе класса scrollrequest, в принципе, загрузку файла я использую лишь один раз в жизненном цикле этого класса, а потому не стал делать отдельный метод для загрузки файла с сервера.

Для загрузки XML-файла с сервера используется стандартная схема загрузки при помощи класса URLLoader.

Обработчик loadXML срабатывает после полной загрузки файла с сервера и вызывает метод parseXML(), который, собственно, и осуществляет разбор XML-Данных.

Чтобы получить список всех узлов с именем control мы используем оператор “квадратные скобки – “xml["control"], а чтобы получить единственный узел с таким именем нужмно использовать кщк один оператор “квадратные скобки”, чтобы обратиться к первому и единственному элементу в списке узлов. То есть вот так xml["control"][0].

Обращение к конкртеному атрибуту узла происходит посредством метода attribute(‘par’), которому в качестве параметра передается имя атрибута.

Чтобы получить список всех дочерних элементов узла, применяется метод child(‘par’), которому в качестве параметра передается имя дочерних узлов, которые мы хотим увидеть в списке. То есть вот так xml["sites"][0].child(“site”) мы получим массив всех эелементов <site> у которых родителем является элемент <site>.

Пробег по всем элементам списка осущетсвляется обычным циклом for.

Вот и все, что я хотел сегодня рассказать.

Парсинг XML в JavaScript на примере XML-погоды от gismeteo.ru

Вячеслав Гринин, March 20, 2009

Итак, заинтересовала меня тема, как распарсить XML-файл посредством JavaScript. Немного порыскав в поисковиках наткнулся на весьма познавательную статью по этой теме XML в Microsoft Internet Explorer 5.0. Есть у этой статьи маленький недостаток – она посвящена только IE, а мы в нашем блоге твердо решили писать только кроссбраузерный код. Однако, для начала хватило и этой статьи, сначала весь код был написан для IE, и затем была осуществлена безуспешная попытка запустить его также в Opera, Mozilla, Chrome. Но как я уже говорил “не боги горшки обжигают”, все некроссбраузерные баги были успешно найдены и исправлены. Это р-раз.

В качестве подопытного кролика был взят XML-файл, содержащий в себе данные о погоде на ближайшие сутки от Gismeteo.ru. Собственно, открыв эту страницу, и выбрав интересующий вас город, вы можете ниже на той же странице наблюдать содержимое этого XML-файла, и описание его структуры. Это д-два.

Сопоставив первые два пункта уже можно сваять свой собственный парсер XML-документов на JavaScript, однако если вам лень, то читайте статью дальше. В ней я расскажу о том, как провести анализ содержимого XML-файла и отобразить его в том виде, в котором вам хочется. Это т-три.

А вот сразу ссылка на результаты работы моего скрипта. Не расстраивайтесь, что выглядит все так просто, скриптик позволяет посредством шаблонов задать собственный вид отображения результатов, и об этой возможности я расскажу ниже.

Сразу хочу предупредить, что ниже пойдет теоретическая и практическая часть работы с XML-файлами, и если вам не хочется вникать во все эти подробности, то вы можете сразу перейти в самый конец статьи и по предложенной там ссылке скачать готовый скрипт обработки XML-документа, содержащего прогноз погоды от gismeteo.ru. А теперь теория…

Итак, что же такое XML? Wikipedia утверждает, что:

XML (eXtensible Markup Language — расширяемый язык разметки) — рекомендованный консорциумом W3C язык разметки, представляющий собой свод общих синтаксических правил. XML — текстовый формат, предназначенный для хранения структурированных данных, для обмена информацией между программами, а также для создания на его основе более специализированных языков разметки. Целью создания XML было обеспечение совместимости при передаче структурированных данных между разными системами обработки информации, особенно при передаче таких данных через Интернет.

Визуально структура XML может быть представлена как дерево. Важнейшее обязательное требование состоит в том, что документ должен иметь только один корневой элемент (в нашем случае это элемент MMWEATHER). Это значит, что данные всего документа должны быть расположены между единственным начальным корневым тегом и соответствующим ему конечным тегом.

Остальная часть XML-документа состоит из вложенных элементов, которые могут иметь атрибуты и содержимое. Элемент обычно состоит из пары тегов (открывающего и закрывающего), обрамляющих другие элементы. Открывающий тег состоит из имени элемента в угловых скобках, например, <FORECAST> ; закрывающий тег состоит из того же имени в угловых скобках, но перед именем ещё добавляется косая черта, например, </FORECAST>. Содержимым элемента называется всё, что расположено между открывающим и закрывающим тегами, включая текст и другие вложенные элементы.

Кроме содержания у элемента могут быть атрибуты — пары имя-значение, добавляемые в открывающий тег после названия элемента. Например в случае <PHENOMENA cloudiness=”2″ precipitation=”10″ rpower=”0″ spower=”0″/>
элемент PHENOMENA имеет 4 атрибута cloudiness, precipitation, rpower и spower имеющие соответственно значения 2, 10, 0, 0.

Итак, со структурой XML-файла более-менее разобрались. Осталось только понять, каким образом все это богатство обрабатывать в JavaScript. Собственно, в статье XML в Microsoft Internet Explorer 5.0 можно обо всем этом прочесть, но я намерен вкратце обрисовать ниже основные приемы анализа XML-файлов в контексте поставленной в начале статьи задачи – разбора XML-документа, содержащего прогноз погоды на сутки от gismeteo.

  1. Загрузка XML-документа. Хочу сразу заметить, что загрузка любых файлов из JavaScript возможна при соблюдении одного обязательного условия – загружаемый файл должен быть расположен в том же домене, где и сама страница его загружающая. Поэтому невозможно со страницы, расположенной, например, по адресу http://easy4web.ru/samples/gismeteo/ загрузить файл с сайта http://gismeteo.ru. А это означает, что … проблему надо как-то решать. Есть два пути: либо скачать файл с сайта gismeteo.ru на свой домен, либо создать на вашем домене простой PHP-обработчик, который сам будет скачивать файл с другого домена и выдавать его содержимое от своего имени. В предлагаемом мною решении я пошел по второму пути и поэтому чуть ниже приведу вам PHP-скрипт, выполняющий данное действие. А теперь, собственно, о загрузке XML-документов.
    В IE эта операция производится с помощью следующего кода

    xml=new ActiveXObject("Microsoft.XMLDOM");
    xml.async=false;
    xml.load(url);

    После выполнения которого в переменной xml будет храниться обработанный XML-Документ. Конечно, если документ был верно отформатирован. В ином случае будет сгенерировано исключение.
    Во всех остальных браузерах (Opera, Firefox, Chrome) загрузка файлов выглядит иначе:

    xml=new window.XMLHttpRequest();
    xml.open("GET", url, false);
    xml.send("");

    После чего в поле xml.responseXML можно обнаружить обработанный XML-документ. Таким образом, полный текст функции, осуществляющей загрузку XML-документа, будет выглядеть следующим образом:

    function getXMLDocument(url)
    {
        var xml;
        if(window.XMLHttpRequest)
        {
            xml=new window.XMLHttpRequest();
            xml.open("GET", url, false);
            xml.send("");
            return xml.responseXML;
        }
        else
            if(window.ActiveXObject)
            {
                xml=new ActiveXObject("Microsoft.XMLDOM");
                xml.async=false;
                xml.load(url);
                return xml;
            }
            else
            {
                alert("Загрузка XML не поддерживается браузером");
                return null;
            }
    }
  2. Получение коллекции элементов по имени элемента производится использованием метода getElementsByTagName(tagname) объекта XMLDOMDocument. Например, получить массив всех элементов TOWN можно так: xml.getElementsByTagName(“TOWN”). Понятно, что в переменную xml уже должен быть загружен сам XML-документ.
  3. Просмотр коллекции элементов лучше проводить с помощью цикла for, так как итератор nextNode() пригодный для использования в цикле while, увы, не определен для результата, возвращаемого объектом XMLHttpRequest, а значит будет работать только в IE. Вот код для просмотра коллекции элементов циклом for:
    var towns=xml.getElementsByTagName("TOWN");
    if(towns)
    for(var i1=0; i1<towns.length; i1++)
    {
       town=towns[i1];
       // операции над текущим элементом town
    }
  4. Получение атрибутов элемента.
    Вообще, все атрибуты элемента хранятся в его коллекции attributes, однако доступ к ней неудобен, и поэтому я написал простую функцию, которая пробегает по всей коллекции атрибутов и распаковывает ее в удобный для работы массив, позволяющий получить доступ к любому атрибуту через оператор “квадратные скобки”. Вот эта функция:

    function getAttributes(node)
    {
      var ret = new Object();
      if(node.attributes)
      for(var i=0; i<node.attributes.length; i++)
      {
        var attr = node.attributes[i];
        ret[attr.name] = attr.value;
      }
      return ret;
    }

Вот собственно и вся предварительная подготовка. Используя эту информацию, уже можно написать анализатор XML-файлов с прогнозом погоды. Конечно, работа с XML-файлами гораздо сложнее, чем я здесь описал, но для пытливых умов существуют книги, интернет, поисковики.

Вот ссылка на готовый скрипт парсера XML-погоды. Вам следует только обратить внимание на шаблоны (переменная template) в конце файла index.html. Это объект в JSON-нотации, содержащий в себе следующие поля: “town”, “forecast”, “phenomena”, “pressure”, “temperature”, “wind”, “relwet”, “heat”, “t_forecast”, “t_template”. Первые 8 представляют собой строки, в которых хранятся шаблоны отображения конкретных нюансов прогноза: город, дата прогноза, атмосферные явления, давление, температура, ветер, относительную влажность, комфортную температуру. В HTML-разметку каждого шаблона вставляются конкретные данные прогноза, которые имеют вид соответствующих имен атрибутов, взятых в фигурные скобки. Все имена атрибутов вы можете увидеть внизу страницы Gismeteo.ru. Для некоторых числовых атрибутов существуют также их строковые псевдонимы, получаются они путем прибавления к атрибуту префикса “s”. Абсолютно все используемые в шаблонах атрибуты вы можете увидеть в конце HTML-разметки страницы index.html, в тегах <script>.

И еще два шаблона, используемых в переменной template. Это t_forecast и t_template. Первый задает разметку прогноза для конкретного времени суток, а второй – разметку для всех прогнозов одного города.

Понимаю, что последний абзац получился запутанным, но, надеюсь, взглянув в код, вы все поймете самостоятельно. Если же возникают вопросы, то пишите их в комментариях к посту, Отвечу на все.

Где-то в середине статьи я обещал показать код PHP-Обработчика, скачивающего XML с других сайтов. Код этот вы можете увидеть в архиве с исходниками в файле xml.php. Он короткий и в пояснениях не нуждается.

Поиск по блогу:
Подписаться:
Популярные:
Облако тегов:
Разное:
Счетчик: