Статьи

Android для Windows 8: анализ XML-данных

Скорее всего, приложению Магазина Windows потребуется работать с данными, находящимися в Интернете. Например, приложение может собирать данные из различных источников новостей, используя RSS-каналы. Использование этого типа данных в приложении Магазина Windows очень похоже на использование в приложении Android. В этом посте я покажу вам, как анализировать данные XML из фида в StackOverflow .

Первое, что вам нужно сделать, это выбрать XML-фид, который вы хотите использовать в своем приложении. Для этого раздела будет использоваться лента из StackOverflow.com , ориентированная на Windows 8. Канал доступен по адресу http://stackoverflow.com/feeds/tag/windows-8 .

После того, как вы определили канал, вы захотите проанализировать его, чтобы определить, какие поля представляют интерес для вашего приложения. Ниже приведен пример абстрактной формы фида StackOverflow.com, который мы будем использовать:

<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:creativeCommons="http://backend.userland.com/creativeCommonsRssModule" xmlns:re="http://purl.org/atompub/rank/1.0">
<title type="text">active questions tagged windows-8 - Stack Overflow</title>
 ...
 <entry>
 ...
 </entry>
 <entry>
  <id>http://stackoverflow.com/q/00000000</id>
  <re:rank scheme="http://stackoverflow.com">0</re:rank>
  <title type="text">Windows Store XML Data</title>
  <category scheme="http://stackoverflow.com/feeds/tag/windows-8/tags" term="c#"/>
  <category scheme="http://stackoverflow.com/feeds/tag/windows-8/tags" term="xml"/>
  <category scheme="http://stackoverflow.com/feeds/tag/windows-8/tags" term="windows-8"/>
  <category scheme="http://stackoverflow.com/feeds/tag/windows-8/tags" term="windows-runtime"/>
  <author>
   <name>anonymous</name>
   <uri>http://stackoverflow.com/users/000000</uri>
  </author>
  <link rel="alternate" href="http://stackoverflow.com/questions/00000000/windows-store-xml-data" />
  <published>1900-01-01T00:00:00Z</published>
  <updated>1900-01-01T00:00:00Z</updated>
  <summary type="html">
   <p>How do I use XML in Windows Store apps?</p>
  </summary>
 </entry>
 <entry>
 ...
 </entry>
 ...
</feed>

Для примера мы сосредоточимся на элементах title , link и summary . Первым шагом является создание класса, который представляет данные, с которыми вы хотите работать в вашем приложении. Поскольку мы фокусируемся на элементах заголовка, ссылки и сводки, класс будет выглядеть следующим образом:

public class FeedEntry
{
 public string Title { get; set; }
 public string Link { get; set; }
 public string Summary { get; set; }
}

Следующим шагом является создание класса и метода, которые будут отвечать за синтаксический анализ. Тип возвращаемого значения метода должен быть списком объектов FeedEntry. Возможность будет выглядеть так:

public class StackOverflowXmlParser
{
 ...
 public async Task<List<FeedEntry>> Parse()
 {
  ...
 }
 ...
}

Обратите внимание, что в метод добавлен асинхронный модификатор, и метод возвращает задачу, которая была напечатана в виде списка объектов FeedEntry. Это позволяет методу использовать оператор ожидания для определения точек приостановки. Оператор await сообщает компилятору, что асинхронный метод не может продолжаться после этой точки, пока не будет завершена ожидаемая асинхронная операция. Кроме того, это позволяет вызывающим методам очень просто вызывать метод Parse асинхронным способом, просто используя ключевое слово await .

Android-совет
Использование модификатора async и оператора await в Windows 8 для упрощения асинхронного программирования аналогично использованию класса AsyncTask в Android-разработчике.

Первой задачей в методе Parse будет создание экземпляра набора результатов для возврата к вызывающему методу и проверки состояния сетевого подключения с помощью метода GetConnectionState, описанного в предыдущем разделе. Поскольку это может быть связано с большим объемом данных, мы хотим убедиться, что мы пытаемся получить доступ к каналу только в том случае, если устройство подключено без измерения:

List<FeedEntry> results = new List<FeedEntry>();

//Determine connection state
var connectionState = GetConnectionState();

//Proceed if a non-metered connection is detected
if (connectionState == ConnectionState.NonMetered)
{
 ...

Следующее, что нужно сделать, это определить метод, с помощью которого будет обрабатываться канал. Поскольку мы имеем дело с фидом XML, у нас есть три варианта в .NET:

  1. Пространство имен System.Xml
  2. Пространство имен System.Xml.Linq
  3. System.ServiceModel.Syndication имен

Пространство имен System.Xml обеспечивает основанную на стандартах поддержку для обработки XML. Он дает вам немного контроля над тем, как вы обрабатываете XML, и позволяет вам использовать такие вещи, как схемы XSD, выражения XPath и преобразования XSLT. Это немного больше энергии, чем нам нужно для этой конкретной задачи. Класс SyndicationFeed в пространстве имен System.ServiceModel.Syndication фактически сделает нашу работу невероятно простой, если мы хотим работать со всеми полями в ленте. Однако, поскольку нас интересуют только три поля, мы будем использовать пространство имен System.Xml.Linq. Это пространство имен содержит классы для LINQ (Language INtegrated Query) to XML, который служит интерфейсом программирования XML в памяти, который обеспечивает простую и эффективную обработку документов XML.

Прежде всего, при работе с LINQ to XML необходимо создать несколько объектов XName, которые представляют имена элементов, с которыми мы хотим работать. Эти имена должны включать локальные имена и имена пространств имен.

/Atom namespace
var atomNamespace = "http://www.w3.org/2005/Atom";

//Create the names of the XML elements including the Atom namespace
var entryXName = XName.Get("entry", atomNamespace);
var titleXName = XName.Get("title", atomNamespace);
var linkXName = XName.Get("link", atomNamespace);
var summaryXName = XName.Get("summary", atomNamespace);

Следующим шагом является асинхронная загрузка данных XML в класс XElement . Для этого создайте экземпляр HttpWebRequest и вызовите его метод GetResponseAsync () с помощью ключевого слова await . GetResponseStream () из HttpWebResponse объекта можно затем использовать в нагрузке (…) метод класса XElement.

//Load the XML data asynchronously
var request = HttpWebRequest.CreateHttp("http://stackoverflow.com/feeds/tag/windows-8");
var response = await request.GetResponseAsync();
XElement root = XElement.Load(response.GetResponseStream());

Android-совет
Это похоже на использование Android HttpURLConnection для получения и InputStream

private InputStream downloadXml() throws IOException {
 URL url = new URL('http://stackoverflow.com/feeds/tag/windows-8');
 HttpURLConnection conn = (HttpURLConnection) url.openConnection();
 conn.setRequestMethod("GET");
 conn.setDoInput(true);
 conn.connect();
 return conn.getInputStream();
}

Затем вы должны использовать вывод InputStream в качестве входного параметра в методе setInput класса XmlPullParser .

Как только объект XElement загружен, мы можем использовать LINQ для запроса только элементов ввода и в XElement и сохранить их в списке:

//Load all "entry" elements from the XML into a list
var entries = (from e in root.Elements(entryXName) select e).ToList();

Далее мы начнем перебирать список записей. Первым шагом в итерации является создание нового объекта FeedEntry:

//Iterate all "entry" elements
foreach (var entry in entries)
{
 //Create a new FeedEntry
 var feedEntry = new FeedEntry();
 ...
}

Затем мы присвоим значение свойства Title FeedEntry значению элемента title:

//Get the title
var titleElement = (from e in entry.Elements(titleXName) select e).FirstOrDefault();

if (titleElement != null)
 feedEntry.Title = titleElement.Value;

Android-совет
Эквивалент Android будет вызывать метод getText () класса XmlPullParser, чтобы получить значение текущего элемента.

Аналогичным образом мы присвоим значение свойства Link значению атрибута href элемента link:

//Get the link
var linkElement = (from e in entry.Elements(linkXName) select e).FirstOrDefault();

if (linkElement != null)
{
 var hrefAttribute = linkElement.Attributes("href").FirstOrDefault();

 if (hrefAttribute != null)
  feedEntry.Link = hrefAttribute.Value;
}

Android-совет
Чтобы получить значение атрибута в Android, вы должны использовать метод getAttribueValue () класса XmlPullParser.

Далее мы присвоим значение свойства Summary значению элемента summary и добавим объект в набор результатов, который будет возвращен вызывающему методу:

//Add to the entry to the result set
results.Add(feedEntry);

Последний шаг — вызов метода Parse . Поскольку метод Parse был изменен с помощью ключевого слова async , его можно вызывать асинхронно с помощью оператора await, например:

var parser = new StackOverflowXmlParser();
var entries = await parser.Parse();
//do something with the entries