Статьи

Полеты над вами и многое другое на Windows Phone с WolframAlpha

Причина, по которой мне нравится WolframAlpha, заключается в том, что это «движок знаний», который позволяет быстро понять множество тем. В частности, самая интересная часть для меня связана с получением списка рейсов, которые в настоящее время находятся над мной. Итак, вот как отслеживать полеты над вами из приложения Windows Phone с помощью WolframAlpha API. Конечно, этот образец построен таким образом, что вы можете легко адаптировать его к любому входному запросу — мне просто нравится отслеживать рейсы.

Первое, что вам нужно сделать, это зайти на https://developer.wolframalpha.com/portal/myapps/ и получить AppID.

ПРИМЕЧАНИЕ. Также загрузите руководство по API .

Структура запроса довольно упрощенная. Все запросы выполняются к одной конечной точке:

http://api.wolframalpha.com/v2/query?input=YOUR QUERY & appid = 0000-000000

Возвращенные данные представлены в формате XML и структурированы в узлах, называемых модулями . Например, давайте посмотрим на запрос о самолетах, которые в настоящее время находятся выше меня:

http://api.wolframalpha.com/v2/query?input=planes над мной прямо сейчас и appid = 0000-000000

Это вернет XML-файл, который выглядит примерно так:

<?xml version='1.0' encoding='UTF-8'?>
<queryresult success='true'
    error='false'
    numpods='3'
    datatypes='Flight'
    timedout=''
    timedoutpods=''
    timing='2.556'
    parsetiming='0.343'
    parsetimedout='false'
    recalculate=''
    id='MSPa50291a18174ad9dd8i5100004b9gia4chgd2h5b5'
    host='http://www4b.wolframalpha.com'
    server='12'
    related='http://www4b.wolframalpha.com/api/v2/relatedQueries.jsp?id=MSPa50301a18174ad9dd8i5100004id6id1d223f71a8&s=12'
    version='2.5'>
 <pod title='Result'
     scanner='Data'
     id='Result'
     position='200'
     error='false'
     numsubpods='1'
     primary='true'>
  <subpod title=''>
   <plaintext> | altitude | angle
Southwest Airlines flight 573 | 41000 feet | 14 degrees up
American Airlines flight 1799 | 34000 feet | 11 degrees up
Frontier Airlines flight 231 | 38000 feet | 11 degrees up
Atlantic Southeast Airlines flight 4641 | 36000 feet | 9.4 degrees up
AirTran Airways flight 443 | 30700 feet | 8.3 degrees up
 | type | slant distance
Southwest Airlines flight 573 | Boeing 737-700 | 31 miles east
American Airlines flight 1799 | McDonnell Douglas MD-83 | 34 miles east-northeast
Frontier Airlines flight 231 | Airbus A319 | 38 miles east-northeast
Atlantic Southeast Airlines flight 4641 | Embraer EMB-145XR | 40 miles north
AirTran Airways flight 443 | Boeing 717-200 | 39 miles west
(locations based on projections of delayed data)
(angles with respect to nominal horizon)</plaintext>
   <img src="http://www4b.wolframalpha.com/Calculate/MSP/MSP50321a18174ad9dd8i5100005e0c7g4i3cigh14b?MSPStoreType=image/gif&s=12"
       alt=' | altitude | angle
Southwest Airlines flight 573 | 41000 feet | 14 degrees up
American Airlines flight 1799 | 34000 feet | 11 degrees up
Frontier Airlines flight 231 | 38000 feet | 11 degrees up
Atlantic Southeast Airlines flight 4641 | 36000 feet | 9.4 degrees up
AirTran Airways flight 443 | 30700 feet | 8.3 degrees up
 | type | slant distance
Southwest Airlines flight 573 | Boeing 737-700 | 31 miles east
American Airlines flight 1799 | McDonnell Douglas MD-83 | 34 miles east-northeast
Frontier Airlines flight 231 | Airbus A319 | 38 miles east-northeast
Atlantic Southeast Airlines flight 4641 | Embraer EMB-145XR | 40 miles north
AirTran Airways flight 443 | Boeing 717-200 | 39 miles west
(locations based on projections of delayed data)
(angles with respect to nominal horizon)'
       title=' | altitude | angle
Southwest Airlines flight 573 | 41000 feet | 14 degrees up
American Airlines flight 1799 | 34000 feet | 11 degrees up
Frontier Airlines flight 231 | 38000 feet | 11 degrees up
Atlantic Southeast Airlines flight 4641 | 36000 feet | 9.4 degrees up
AirTran Airways flight 443 | 30700 feet | 8.3 degrees up
 | type | slant distance
Southwest Airlines flight 573 | Boeing 737-700 | 31 miles east
American Airlines flight 1799 | McDonnell Douglas MD-83 | 34 miles east-northeast
Frontier Airlines flight 231 | Airbus A319 | 38 miles east-northeast
Atlantic Southeast Airlines flight 4641 | Embraer EMB-145XR | 40 miles north
AirTran Airways flight 443 | Boeing 717-200 | 39 miles west
(locations based on projections of delayed data)
(angles with respect to nominal horizon)'
       width='495'
       height='524' />
  </subpod>
  <states count='2'>
   <state name='More'
       input='Result__More' />
   <state name='Show metric'
       input='Result__Show metric' />
  </states>
 </pod>
</queryresult>

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

Стоит отметить, что, хотя XML представляет основной каркас, данные могут быть получены в различных форматах представления. Например, если я хочу получить данные HTML или изображения, отображаемые по разделам (imagemap), я могу добавить параметр формата . Например:

http://api.wolframalpha.com/v2/query?input=planes поверх меня прямо сейчас & appid = 0000-000000 & format = html

В качестве примера ответа вы получите обернутый CDATA узел:

<pod title='Input interpretation'
     scanner='Identity'
     id='Input'
     position='100'
     error='false'
     numsubpods='0'>
  <markup><![CDATA[<div id="pod_0100" class="pod "><hr class="top" /><h2>Input interpretation:</h2><div id="subpod_0100_1" class="sub "width="413"width="413"><div class="output pnt" id="scannerresult_0100_1"><img height="39"width="413" src="http://www4b.wolframalpha.com/Calculate/MSP/MSP32331a181999971gg24g0000184dig7311dc929e?MSPStoreType=image/gif&s=11&w=413&h=39" id="i_0100_1" alt="flights seen from current geoIP location | current time" title="flights seen from current geoIP location | current time"  data-attribution="" /></div><div class="annotpod">
	</div></div>
<hr class="bot" /></div>]]></markup>
 </pod>

Давайте начнем с самого простого ответа представления данных — необработанного XML. Я создал тестовое приложение для Windows Phone, состоящее из одной страницы с элементом управления TextBox для приема ввода пользователя и ListBox для отображения результатов. Когда запрос выполняется, я пытаюсь десериализовать данные в модели QueryResult .

[XmlRoot("queryresult")]
public class QueryResult
{
    [XmlElement("pod")]
    public ObservableCollection<Pod> Pods { get; set; }
}

Pod класс:

public class Pod
{
    [XmlAttribute("title")]
    public string Name { get; set; }
    [XmlElement("subpod")]
    public ObservableCollection<SubPod> SubPods { get; set; }
}

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

Класс SubPod :

public class SubPod
{
    [XmlElement("plaintext")]
    public string Plaintext { get; set; }
    [XmlElement("img")]
    public WImage Image { get; set; }
}

WImage (расшифровывается как WolframImage) — это класс, который используется исключительно для удобства сериализации, чтобы иметь возможность легко считывать данные атрибутов из узла изображения для связанного подпотока.

public class WImage
{
    [XmlAttribute("src")]
    public string Location { get; set; }
}

Данные получают и сериализуют с помощью стандартного сериализатора XML .NET:

WolframAlpha.SendInput(txtInput.Text, result =>
    {
        XmlSerializer serializer = new XmlSerializer(typeof(QueryResult));
        TextReader reader = new StringReader(result);

        Binder.Instance.CurrentQueryResult = serializer.Deserialize(reader) as QueryResult;
        Debug.WriteLine(result);
    });

Вот где это становится интересным. Полученные данные ничего не значат, если они не могут быть показаны пользователю. Однако есть одно небольшое ограничение — Windows Phone не поддерживает готовые изображения GIF. Чтобы привязать изображение к пользовательскому интерфейсу, мне нужно использовать стороннюю библиотеку для скрытия данных, использовать службу или использовать веб-браузер, который будет загружать изображение. Я выбрал последний вариант.

<ListBox ItemsSource="{Binding Path=Instance.CurrentQueryResult.Pods,Source={StaticResource Binder}}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel>
                <TextBlock Style="{StaticResource PhoneTextLargeStyle}" Text="{Binding Name}"></TextBlock>
                <ListBox ItemsSource="{Binding SubPods}">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <TextBlock Text="{Binding Name}"></TextBlock>
                                <phone:WebBrowser Margin="12" Width="400" Height="400"  Tag="{Binding Image.Location}" Loaded="WebBrowser_Loaded"></phone:WebBrowser>
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Когда загружен элемент управления WebBrowser, я могу использовать NaviagateToString для загрузки изображений:

private void WebBrowser_Loaded(object sender, RoutedEventArgs e)
{
    string location = ((WebBrowser)sender).Tag.ToString();
    ((WebBrowser)sender).NavigateToString("<img style=\"width: 100%;\" src=\"" + location + "\" />");
}

ПРИМЕЧАНИЕ. Помните, что сам элемент управления имеет свойство Tag, которое установлено в положение изображения. Таким образом, действительно легко увидеть, какой из элементов WebBrowser отвечает за какое изображение.

В итоге вы получаете такой интерфейс:

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

Вы можете скачать образец здесь (код + XAP) .