<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Technology@Work &#187; Cisco</title>
	<atom:link href="http://techwork.ru/tag/cisco/feed/" rel="self" type="application/rss+xml" />
	<link>http://techwork.ru</link>
	<description>Русскоязычная информация о Cloud Computing и других технологиях</description>
	<lastBuildDate>Wed, 16 Sep 2009 09:34:43 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>XML сервисы, часть вторая</title>
		<link>http://techwork.ru/2008/08/28/xml-services-part-2/</link>
		<comments>http://techwork.ru/2008/08/28/xml-services-part-2/#comments</comments>
		<pubDate>Thu, 28 Aug 2008 13:03:10 +0000</pubDate>
		<dc:creator>techworkru</dc:creator>
				<category><![CDATA[Google App Engine]]></category>
		<category><![CDATA[CallManager]]></category>
		<category><![CDATA[Cisco]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[unicode]]></category>
		<category><![CDATA[utf-8]]></category>
		<category><![CDATA[voip]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://techworkru.wordpress.com/?p=323</guid>
		<description><![CDATA[Недавно мы рассматривали создание приложения на платформе App Engine, которое позволяет IP телефонам Cisco получать информацию о прогнозе погоды, новостях и курсе валют.
К сожалению, пользователи, которые же в первые дни появились у этого сервиса, обнаружили в нем два существенных недостатка:

Мы отображаем только погоду только по Москве, хотя сервис у нас глобальный
Существуют проблемы на разных версиях [...]]]></description>
			<content:encoded><![CDATA[<p>Недавно <a href="http://techwork.ru/2008/08/09/xml-services-for-ip-phones/">мы рассматривали</a> создание приложения на платформе App Engine, которое позволяет IP телефонам Cisco получать информацию о прогнозе погоды, новостях и курсе валют.</p>
<p>К сожалению, пользователи, которые же в первые дни появились у этого сервиса, обнаружили в нем два существенных недостатка:</p>
<ul>
<li>Мы отображаем только погоду только по Москве, хотя сервис у нас глобальный</li>
<li>Существуют проблемы на разных версиях прошивок для телефонов, которые ожидают данные на русском языке в кодировке cp-1251.</li>
</ul>
<p>Первый недочет решено было исправить, добавив опциональный параметр <em>city</em> к URL сервиса, равный коду города на сайте <a href="http://gismeteo.ru" target="_blank">ГисМетео</a>, на котором мы берем данные погоды. Таким образом строка для телефонов Питера выглядит как <a href="http://xmlphones.appspot.com/?city=26063" target="_blank">http://xmlphones.appspot.com/?city=26063</a>. Второй аналогично будет называться <em>encode</em> и содержать при необходимости задание кодировки windows-1251.</p>
<p><span id="more-323"></span></p>
<p>Перекодировка в Python делается элегантно. Допустим, у нас через URLFetch получены данные в UTF-8, а вывод требуется в windows-1251:</p>
<pre>
<div class="python" style="font-family:monospace;color:#000000;">resp = <span style="color:#008000;">unicode</span><span style="color:black;">(</span>result.<span style="color:black;">content</span>, <span style="color:#483d8b;">'utf-8'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>
resp = resp.<span style="color:black;">encode</span><span style="color:black;">(</span><span style="color:#483d8b;">"cp1251"</span><span style="color:black;">)</span></div>
</pre>
<p>Ну и наоборот:</p>
<pre>
<div class="python" style="font-family:monospace;color:#000000;">resp = <span style="color:#008000;">unicode</span><span style="color:black;">(</span>result.<span style="color:black;">content</span>, <span style="color:#483d8b;">'cp1251'</span><span style="color:black;">)</span></div>
</pre>
<p>В первом случае мы из байтового массива конструируем объект unicode, который затем кодируем с указанием кодека cp1251. Во втором случае одним действием из байтового массива конструируем также объект unicode с заданием кодека cp1251, но далее просто отдаем его в таком виде платформе App Engine (подразумевается что весь вывод по умолчанию в кодировке UTF-8).</p>
<p>Все кажется замечательным, но тут опять обнаруживается криворукость писателей прошивок некоторых моделей IP телефонов, заключающаяся в том, что телефоны сами добавляют к параметрам запросов дополнительные переменные вида <strong>?locale=English_United_States&amp;name=SEP001B541415EE</strong>, что приводит к проблемам обработке меню сами же телефонами.</p>
<p>Проведенный небольшой эксперимент показал, что если, например, параметры задавать с помощью многоуровневых URL, то все работает отлично. Допустим, кодировку windows-1251 мы будем задавать как <a href="http://xmlphones.appspot.com/windows-1251/">http://xmlphones.appspot.com/windows-1251/</a> (подразумевая, по умолчанию корневой адрес аналогичный <a href="http://xmlphones.appspot.com/utf-8/">http://xmlphones.appspot.com/utf-8/</a>), а город как <a href="http://xmlphones.appspot.com/utf-8/city/26063">http://xmlphones.appspot.com/utf-8/city/26063</a> (и опять это Питер).</p>
<p>Выкидываем из кода несколько обработчиков, привязанных к URL, и заменяем их одним Dispatcher, который будет решать куда направить тот или иной запрос. Так как нашим сервисом уже пользуются люди, старые параметры <em>?encode</em> и <em>?city</em> также оставляем для совместимости, но делаем их второстепенными по сравнению со схемой параметров, заданных через URL.</p>
<p>Вот что получилось в итоге:</p>
<pre>
<div class="python" style="font-family:monospace;color:#000000;"><span style="font-style:italic;color:#808080;"># coding=UTF-8</span>
<span style="font-style:italic;color:#808080;"># -*- coding: utf-8 -*-</span>

<span style="font-weight:bold;color:#ff7700;">import</span> wsgiref.<span style="color:black;">handlers</span>
<span style="font-weight:bold;color:#ff7700;">from</span> google.<span style="color:black;">appengine</span>.<span style="color:black;">ext</span> <span style="font-weight:bold;color:#ff7700;">import</span> webapp
<span style="font-weight:bold;color:#ff7700;">from</span> google.<span style="color:black;">appengine</span>.<span style="color:black;">api</span> <span style="font-weight:bold;color:#ff7700;">import</span> urlfetch
<span style="font-weight:bold;color:#ff7700;">import</span> <span style="color:#dc143c;">os</span>
<span style="font-weight:bold;color:#ff7700;">from</span> google.<span style="color:black;">appengine</span>.<span style="color:black;">ext</span>.<span style="color:black;">webapp</span> <span style="font-weight:bold;color:#ff7700;">import</span> template
<span style="font-weight:bold;color:#ff7700;">from</span> <span style="color:#dc143c;">xml</span>.<span style="color:black;">dom</span> <span style="font-weight:bold;color:#ff7700;">import</span> minidom
<span style="font-weight:bold;color:#ff7700;">import</span> <span style="color:#dc143c;">re</span>
<span style="font-weight:bold;color:#ff7700;">import</span> <span style="color:#dc143c;">time</span>

WEATHER_URL = <span style="color:#483d8b;">'http://informer.gismeteo.ru/rss/%s.xml'</span>

<span style="font-weight:bold;color:#ff7700;">def</span> get_city<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    city = <span style="color:#008000;">self</span>.<span style="color:black;">request</span>.<span style="color:black;">get</span><span style="color:black;">(</span><span style="color:#483d8b;">"city"</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>
    <span style="font-weight:bold;color:#ff7700;">if</span> city <span style="color:#1c6c9d;">==</span> <span style="color:#483d8b;">''</span>:
        <span style="font-style:italic;color:#808080;"># Москва</span>
        city = <span style="color:#483d8b;">'27612'</span>
    ccode = <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'/.+/meteo/(.+)'</span><span style="color:#ff0099;">,</span> <span style="color:#008000;">self</span>.<span style="color:black;">request</span>.<span style="color:black;">path</span><span style="color:black;">)</span>
    <span style="font-weight:bold;color:#ff7700;">if</span> ccode <span style="color:#1c6c9d;">!=</span> <span style="color:#008000;">None</span>:
        <span style="font-weight:bold;color:#ff7700;">return</span> ccode.<span style="color:black;">group</span><span style="color:black;">(</span><span style="color:#ff4500;">1</span><span style="color:black;">)</span>
    <span style="font-weight:bold;color:#ff7700;">else</span>:
        <span style="font-weight:bold;color:#ff7700;">return</span> city

<span style="font-weight:bold;color:#ff7700;">def</span> get_encode_templ<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    encode = <span style="color:#008000;">self</span>.<span style="color:black;">request</span>.<span style="color:black;">get</span><span style="color:black;">(</span><span style="color:#483d8b;">"encode"</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>
    <span style="font-weight:bold;color:#ff7700;">if</span> encode <span style="color:#1c6c9d;">==</span> <span style="color:#483d8b;">'windows-1251'</span><span style="color:#ff0099;">:</span>
        <span style="font-weight:bold;color:#ff7700;">return</span> encode
    <span style="font-weight:bold;color:#ff7700;">else</span>:
        <span style="font-weight:bold;color:#ff7700;">return</span> <span style="color:#483d8b;">'utf-8'</span>

<span style="font-weight:bold;color:#ff7700;">def</span> render_template<span style="color:black;">(</span><span style="color:#008000;">self</span>, templ, template_values=<span style="color:black;">{</span><span style="color:black;">}</span><span style="color:#ff0099;">,</span> encode=<span style="color:#483d8b;">'utf-8'</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    path = <span style="color:#dc143c;">os</span>.<span style="color:black;">path</span>.<span style="color:black;">join</span><span style="color:black;">(</span><span style="color:#dc143c;">os</span>.<span style="color:black;">path</span>.<span style="color:black;">dirname</span><span style="color:black;">(</span>__file__<span style="color:black;">)</span><span style="color:#ff0099;">,</span> <span style="color:#483d8b;">'templates/'</span>+templ<span style="color:black;">)</span>
    resp = template.<span style="color:black;">render</span><span style="color:black;">(</span>path, template_values<span style="color:black;">)</span>
    <span style="font-weight:bold;color:#ff7700;">if</span> encode <span style="color:#1c6c9d;">==</span> <span style="color:#483d8b;">'windows-1251'</span>:
        <span style="font-style:italic;color:#808080;"># Перекодируем из UTF-8 в CP1251</span>
        resp = <span style="color:#008000;">unicode</span><span style="color:black;">(</span>resp, <span style="color:#483d8b;">'utf-8'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>
        resp = resp.<span style="color:black;">encode</span><span style="color:black;">(</span><span style="color:#483d8b;">"cp1251"</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>
    <span style="color:#008000;">self</span>.<span style="color:black;">response</span>.<span style="color:black;">out</span>.<span style="color:black;">write</span><span style="color:black;">(</span>resp<span style="color:black;">)</span>

<span style="font-weight:bold;color:#ff7700;">def</span> is_ipphone<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    <span style="font-weight:bold;color:#ff7700;">if</span> <span style="color:#dc143c;">re</span>.<span style="color:black;">match</span><span style="color:black;">(</span><span style="color:#483d8b;">'Allegro'</span><span style="color:#ff0099;">,</span> <span style="color:#008000;">self</span>.<span style="color:black;">request</span>.<span style="color:black;">headers</span>.<span style="color:black;">get</span><span style="color:black;">(</span><span style="color:#483d8b;">'User-Agent'</span>, <span style="color:#483d8b;">''</span><span style="color:#ff0099;"><span style="color:black;">)</span></span><span style="color:black;">)</span> <span style="color:#1c6c9d;">==</span> <span style="color:#008000;">None</span>:
        <span style="font-weight:bold;color:#ff7700;">return</span> <span style="color:#008000;">False</span>
    <span style="font-weight:bold;color:#ff7700;">else</span>:
        <span style="font-weight:bold;color:#ff7700;">return</span> <span style="color:#008000;">True</span>     

<span style="font-weight:bold;color:#ff7700;">def</span> parse_rss_data<span style="color:black;">(</span>content<span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    result = <span style="color:#483d8b;">''</span>
    dom = minidom.<span style="color:black;">parseString</span><span style="color:black;">(</span>content<span style="color:black;">)</span>
    <span style="font-weight:bold;color:#ff7700;">for</span> item <span style="font-weight:bold;color:#ff7700;">in</span> dom.<span style="color:black;">getElementsByTagName</span><span style="color:black;">(</span><span style="color:#483d8b;">'item'</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
        result = result <span style="color:#1c6c9d;">+</span> item.<span style="color:black;">getElementsByTagName</span><span style="color:black;">(</span><span style="color:#483d8b;">'title'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span><span style="color:black;">[</span><span style="color:#ff4500;">0</span><span style="color:black;">]</span>.<span style="color:black;">firstChild</span>.<span style="color:black;">nodeValue</span> <span style="color:#1c6c9d;">+</span> <span style="color:#483d8b;">'<span style="font-weight:bold;color:#000099;">\n</span>'</span> <span style="color:#1c6c9d;">+</span> item.<span style="color:black;">getElementsByTagName</span><span style="color:black;">(</span><span style="color:#483d8b;">'description'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span><span style="color:black;">[</span><span style="color:#ff4500;">0</span><span style="color:black;">]</span>.<span style="color:black;">firstChild</span>.<span style="color:black;">nodeValue</span> <span style="color:#1c6c9d;">+</span> <span style="color:#483d8b;">'<span style="font-weight:bold;color:#000099;">\n</span><span style="font-weight:bold;color:#000099;">\n</span>'</span>
    <span style="font-weight:bold;color:#ff7700;">return</span> result

<span style="font-weight:bold;color:#ff7700;">def</span> rss_to_text<span style="color:black;">(</span><span style="color:#008000;">self</span>, url<span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    result = urlfetch.<span style="color:black;">fetch</span><span style="color:black;">(</span>url<span style="color:black;">)</span>
    <span style="font-weight:bold;color:#ff7700;">if</span> result.<span style="color:black;">status_code</span> <span style="color:#1c6c9d;">==</span> <span style="color:#ff4500;">200</span>:
        resp = parse_rss_data<span style="color:black;">(</span>result.<span style="color:black;">content</span><span style="color:black;">)</span>
        charset = get_uri_encode<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
        <span style="font-weight:bold;color:#ff7700;">if</span> charset <span style="color:#1c6c9d;">==</span> <span style="color:#483d8b;">'windows-1251'</span>:
            <span style="font-style:italic;color:#808080;"># Перекодируем из UTF-8 в CP1251</span>
            resp = resp.<span style="color:black;">encode</span><span style="color:black;">(</span><span style="color:#483d8b;">"cp1251"</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>
        <span style="color:#008000;">self</span>.<span style="color:black;">response</span>.<span style="color:black;">headers</span><span style="color:black;">[</span><span style="color:#483d8b;">'Content-type'</span><span style="color:black;">]</span>=<span style="color:#483d8b;">'text/plain; charset='</span>+charset
        <span style="color:#008000;">self</span>.<span style="color:black;">response</span>.<span style="color:black;">out</span>.<span style="color:black;">write</span><span style="color:black;">(</span>resp<span style="color:black;">)</span>
    <span style="font-weight:bold;color:#ff7700;">else</span>:
        <span style="color:#008000;">self</span>.<span style="color:black;">redirect</span><span style="color:black;">(</span><span style="color:#483d8b;">'/error.xml'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>

<span style="font-weight:bold;color:#ff7700;">def</span> cbrf<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    charset = get_uri_encode<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
    <span style="color:#008000;">self</span>.<span style="color:black;">response</span>.<span style="color:black;">headers</span><span style="color:black;">[</span><span style="color:#483d8b;">'Content-type'</span><span style="color:black;">]</span>=<span style="color:#483d8b;">'text/plain; charset='</span>+charset
    result = urlfetch.<span style="color:black;">fetch</span><span style="color:black;">(</span><span style="color:#483d8b;">'http://www.cbr.ru/currency_base/D_print.asp?date_req='</span>+<span style="color:#dc143c;">time</span>.<span style="color:black;">strftime</span><span style="color:black;">(</span><span style="color:#483d8b;">'%d.%m.%Y'</span><span style="color:#ff0099;">,</span> <span style="color:#dc143c;">time</span>.<span style="color:black;">localtime</span><span style="color:black;">(</span><span style="color:#ff0099;"><span style="color:black;">)</span></span><span style="color:black;">)</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>
    <span style="font-weight:bold;color:#ff7700;">if</span> result.<span style="color:black;">status_code</span> <span style="color:#1c6c9d;">==</span> <span style="color:#ff4500;">200</span>:
        content = <span style="color:#008000;">unicode</span><span style="color:black;">(</span>result.<span style="color:black;">content</span>, <span style="color:#483d8b;">'windows-1251'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>
        data=<span style="color:#dc143c;">re</span>.<span style="color:black;">split</span><span style="color:black;">(</span><span style="color:#483d8b;">'&lt;td align="right" &gt;036&lt;/td&gt;'</span><span style="color:#ff0099;">,</span> content<span style="color:black;">)</span><span style="color:black;">[</span><span style="color:#ff4500;">1</span><span style="color:black;">]</span>
        <span style="font-weight:bold;color:#ff7700;">for</span> block <span style="font-weight:bold;color:#ff7700;">in</span> <span style="color:#dc143c;">re</span>.<span style="color:black;">split</span><span style="color:black;">(</span><span style="color:#483d8b;">'&lt;tr bgcolor="#ffffff"&gt;'</span><span style="color:#ff0099;">,</span> data<span style="color:black;">)</span><span style="color:#ff0099;">:</span>
            block = <span style="color:#dc143c;">re</span>.<span style="color:black;">sub</span><span style="color:black;">(</span><span style="color:#483d8b;">'<span style="font-weight:bold;color:#000099;">\r</span><span style="font-weight:bold;color:#000099;">\n</span>'</span>, <span style="color:#483d8b;">''</span><span style="color:#ff0099;">,</span> block<span style="color:black;">)</span>
            cells = <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'&lt;td align="left" &gt;&amp;nbsp;&amp;nbsp;(.*?)&lt;/td&gt;&lt;td align="right" &gt;(.*?)&lt;/td&gt;&lt;td&gt;&amp;nbsp;&amp;nbsp;(.*?)&lt;/td&gt;&lt;td align="right"&gt;(.*?)&lt;/td&gt;'</span><span style="color:#ff0099;">,</span> block<span style="color:black;">)</span>
            <span style="font-weight:bold;color:#ff7700;">if</span> cells <span style="color:#1c6c9d;">!=</span> <span style="color:#008000;">None</span>:
                resp = cells.<span style="color:black;">group</span><span style="color:black;">(</span><span style="color:#ff4500;">2</span><span style="color:black;">)</span><span style="color:#1c6c9d;">+</span><span style="color:#483d8b;">' '</span>+cells.<span style="color:black;">group</span><span style="color:black;">(</span><span style="color:#ff4500;">3</span><span style="color:black;">)</span><span style="color:#1c6c9d;">+</span><span style="color:#483d8b;">' = '</span>+cells.<span style="color:black;">group</span><span style="color:black;">(</span><span style="color:#ff4500;">4</span><span style="color:black;">)</span><span style="color:#1c6c9d;">+</span><span style="color:#483d8b;">'<span style="font-weight:bold;color:#000099;">\n</span>'</span>
                <span style="font-weight:bold;color:#ff7700;">if</span> charset <span style="color:#1c6c9d;">==</span> <span style="color:#483d8b;">'windows-1251'</span>:
                    <span style="font-style:italic;color:#808080;"># Перекодируем из UTF-8 в CP1251</span>
                    resp = resp.<span style="color:black;">encode</span><span style="color:black;">(</span><span style="color:#483d8b;">"cp1251"</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>
                <span style="color:#008000;">self</span>.<span style="color:black;">response</span>.<span style="color:black;">out</span>.<span style="color:black;">write</span><span style="color:black;">(</span>resp<span style="color:black;">)</span>
    <span style="font-weight:bold;color:#ff7700;">else</span>:
        <span style="color:#008000;">self</span>.<span style="color:black;">redirect</span><span style="color:black;">(</span><span style="color:#483d8b;">'/error.xml'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>

<span style="font-weight:bold;color:#ff7700;">def</span> error<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    <span style="color:#008000;">self</span>.<span style="color:black;">response</span>.<span style="color:black;">headers</span><span style="color:black;">[</span><span style="color:#483d8b;">'Content-type]'</span><span style="color:black;">]</span>=<span style="color:#483d8b;">'text/plain'</span>
    <span style="color:#008000;">self</span>.<span style="color:black;">response</span>.<span style="color:black;">out</span>.<span style="color:black;">write</span><span style="color:black;">(</span><span style="color:#483d8b;">'Произошла ошибка при работе сервиса'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>

<span style="font-weight:bold;color:#ff7700;">def</span> gismeteo<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    city = get_city<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
    rss_to_text<span style="color:black;">(</span><span style="color:#008000;">self</span>, WEATHER_URL <span style="color:#1c6c9d;">%</span> city<span style="color:black;">)</span>

<span style="font-weight:bold;color:#ff7700;">def</span> yandex_news<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    rss_to_text<span style="color:black;">(</span><span style="color:#008000;">self</span>, <span style="color:#483d8b;">'http://news.yandex.ru/Russia/index.rss'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>

<span style="font-weight:bold;color:#ff7700;">def</span> get_uri_encode<span style="color:black;">(</span><span style="color:#008000;">self</span>, default = <span style="color:#483d8b;">'utf-8'</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    urcode = <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'/windows-1251/.*'</span><span style="color:#ff0099;">,</span> <span style="color:#008000;">self</span>.<span style="color:black;">request</span>.<span style="color:black;">url</span><span style="color:black;">)</span>
    <span style="font-weight:bold;color:#ff7700;">if</span> <span style="color:black;">(</span>urcode <span style="color:#1c6c9d;">!=</span> <span style="color:#008000;">None</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
        <span style="font-weight:bold;color:#ff7700;">return</span> <span style="color:#483d8b;">'windows-1251'</span>
    <span style="font-weight:bold;color:#ff7700;">else</span>:
        <span style="font-weight:bold;color:#ff7700;">return</span> default

<span style="font-weight:bold;color:#ff7700;">def</span> main_page<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    <span style="font-weight:bold;color:#ff7700;">if</span> is_ipphone<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
        citytmpl = get_city<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
        encode = get_encode_templ<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
        urlcity = <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'/(.+)/city/(.+)'</span><span style="color:#ff0099;">,</span> <span style="color:#008000;">self</span>.<span style="color:black;">request</span>.<span style="color:black;">path</span><span style="color:black;">)</span>
        <span style="font-weight:bold;color:#ff7700;">if</span> <span style="color:black;">(</span>urlcity <span style="color:#1c6c9d;">!=</span> <span style="color:#008000;">None</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
            citytmpl = urlcity.<span style="color:black;">group</span><span style="color:black;">(</span><span style="color:#ff4500;">2</span><span style="color:black;">)</span>
        encode = get_uri_encode<span style="color:black;">(</span><span style="color:#008000;">self</span>, encode<span style="color:black;">)</span>
        <span style="color:#008000;">self</span>.<span style="color:black;">response</span>.<span style="color:black;">headers</span><span style="color:black;">[</span><span style="color:#483d8b;">'Content-type'</span><span style="color:black;">]</span>=<span style="color:#483d8b;">'text/xml; charset='</span>+encode
        render_template<span style="color:black;">(</span><span style="color:#008000;">self</span>, <span style="color:#483d8b;">'main.xml'</span>, <span style="color:black;">{</span> <span style="color:#483d8b;">'city'</span><span style="color:#ff0099;">:</span> citytmpl, <span style="color:#483d8b;">'encode'</span><span style="color:#ff0099;">:</span> encode <span style="color:black;">}</span><span style="color:#ff0099;">,</span> encode=encode<span style="color:black;">)</span>
    <span style="font-weight:bold;color:#ff7700;">else</span>:
        <span style="color:#008000;">self</span>.<span style="color:black;">response</span>.<span style="color:black;">headers</span><span style="color:black;">[</span><span style="color:#483d8b;">'Content-type'</span><span style="color:black;">]</span>=<span style="color:#483d8b;">'text/html; charset=utf-8'</span>
        render_template<span style="color:black;">(</span><span style="color:#008000;">self</span>, <span style="color:#483d8b;">'main.html'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>   

<span style="font-weight:bold;color:#ff7700;">class</span> Dispatcher<span style="color:black;">(</span>webapp.<span style="color:black;">RequestHandler</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    <span style="font-weight:bold;color:#ff7700;">def</span> get<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
        <span style="font-style:italic;color:#808080;"># Анализируем только URI до знака ?</span>
        url = <span style="color:#008000;">self</span>.<span style="color:black;">request</span>.<span style="color:black;">url</span>.<span style="color:black;">split</span><span style="color:black;">(</span><span style="color:#483d8b;">'?'</span><span style="color:#ff0099;"><span style="color:black;">)</span></span><span style="color:black;">[</span><span style="color:#ff4500;">0</span><span style="color:black;">]</span>
        <span style="font-weight:bold;color:#ff7700;">if</span> <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'/$'</span><span style="color:#ff0099;">,</span> url<span style="color:black;">)</span><span style="color:#ff0099;">:</span>
            main_page<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
            <span style="font-weight:bold;color:#ff7700;">return</span>
        <span style="font-weight:bold;color:#ff7700;">if</span> <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'/.+/city/.+'</span><span style="color:#ff0099;">,</span> url<span style="color:black;">)</span><span style="color:#ff0099;">:</span>
            main_page<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
            <span style="font-weight:bold;color:#ff7700;">return</span>
        <span style="font-weight:bold;color:#ff7700;">if</span> <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'/utf-8/$'</span><span style="color:#ff0099;">,</span> url<span style="color:black;">)</span><span style="color:#ff0099;">:</span>
            main_page<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
            <span style="font-weight:bold;color:#ff7700;">return</span>
        <span style="font-weight:bold;color:#ff7700;">if</span> <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'/windows-1251/$'</span><span style="color:#ff0099;">,</span> url<span style="color:black;">)</span><span style="color:#ff0099;">:</span>
            main_page<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
            <span style="font-weight:bold;color:#ff7700;">return</span>
        <span style="font-weight:bold;color:#ff7700;">if</span> <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'/(.+)/yandex_news.xml'</span><span style="color:#ff0099;">,</span> url<span style="color:black;">)</span><span style="color:#ff0099;">:</span>
            yandex_news<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
            <span style="font-weight:bold;color:#ff7700;">return</span>
        <span style="font-weight:bold;color:#ff7700;">if</span> <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'/(.+)/meteo.+'</span><span style="color:#ff0099;">,</span> url<span style="color:black;">)</span><span style="color:#ff0099;">:</span>
            gismeteo<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
            <span style="font-weight:bold;color:#ff7700;">return</span>
        <span style="font-weight:bold;color:#ff7700;">if</span> <span style="color:#dc143c;">re</span>.<span style="color:black;">search</span><span style="color:black;">(</span><span style="color:#483d8b;">'/(.+)/cbrf.xml'</span><span style="color:#ff0099;">,</span> url<span style="color:black;">)</span><span style="color:#ff0099;">:</span>
            cbrf<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>
            <span style="font-weight:bold;color:#ff7700;">return</span>
        error<span style="color:black;">(</span><span style="color:#008000;">self</span><span style="color:black;">)</span>

<span style="font-weight:bold;color:#ff7700;">def</span> main<span style="color:black;">(</span><span style="color:black;">)</span><span style="color:#ff0099;">:</span>
    application = webapp.<span style="color:black;">WSGIApplication</span><span style="color:black;">(</span>
                                         <span style="color:black;">[</span><span style="color:#ff0099;"><span style="color:black;">(</span></span><span style="color:#483d8b;">'/.*'</span><span style="color:#ff0099;">,</span> Dispatcher<span style="color:black;">)</span>
                                         <span style="color:black;">]</span><span style="color:#ff0099;">,</span>
                                         debug=<span style="color:#008000;">True</span><span style="color:black;">)</span>
    wsgiref.<span style="color:black;">handlers</span>.<span style="color:black;">CGIHandler</span><span style="color:black;">(</span><span style="color:#ff0099;"><span style="color:black;">)</span></span>.<span style="color:black;">run</span><span style="color:black;">(</span>application<span style="color:black;">)</span>

<span style="font-weight:bold;color:#ff7700;">if</span> __name__ <span style="color:#1c6c9d;">==</span> <span style="color:#483d8b;">'__main__'</span><span style="color:#ff0099;">:</span>
    main<span style="color:black;">(</span><span style="color:#ff0099;"><span style="color:black;">)</span></span></div>
</pre>
<p><strong>Какие еще будут предложения по добавлению новых сервисов?</strong> Напишите комментарий к этой статье.</p>
]]></content:encoded>
			<wfw:commentRss>http://techwork.ru/2008/08/28/xml-services-part-2/feed/</wfw:commentRss>
		<slash:comments>33</slash:comments>
		</item>
		<item>
		<title>XML сервисы для IP телефонов</title>
		<link>http://techwork.ru/2008/08/09/xml-services-for-ip-phones/</link>
		<comments>http://techwork.ru/2008/08/09/xml-services-for-ip-phones/#comments</comments>
		<pubDate>Sat, 09 Aug 2008 14:07:47 +0000</pubDate>
		<dc:creator>techworkru</dc:creator>
				<category><![CDATA[Google App Engine]]></category>
		<category><![CDATA[CallManager]]></category>
		<category><![CDATA[Cisco]]></category>
		<category><![CDATA[voip]]></category>
		<category><![CDATA[XML]]></category>

		<guid isPermaLink="false">http://techworkru.wordpress.com/?p=173</guid>
		<description><![CDATA[Думаю, что специалистам по корпоративной IP телефонии хорошо известно, что с незапамятных времен у лидера рынка Cisco все производимые телефоны имеют возможность отображать внешние данные. Однако на практике этим никто не пользуется, так как хороших приложений немного, а те что есть &#8211; стоят больших денег. Да и возможности телефонов таковы, что приложение с хорошим юзабилити [...]]]></description>
			<content:encoded><![CDATA[<p>Думаю, что специалистам по корпоративной IP телефонии хорошо известно, что с незапамятных времен у лидера рынка Cisco все производимые телефоны имеют возможность отображать внешние данные. Однако на практике этим никто не пользуется, так как хороших приложений немного, а те что есть &#8211; стоят больших денег. Да и возможности телефонов таковы, что приложение с хорошим юзабилити сможет работать только на топовых моделях, которые стоят дороже среднего системного блока.</p>
<p>Мне стало интересно попробовать в работе платформу Google App Engine, чтобы создать небольшой информационный сервис для IP телефонов. Я взял для начала три источника данных: прогноз погоды от сайта GisMeteo, ленту новостей от Яндекса (оба в формате RSS) и официальный сайт Центрального банка РФ, который имеет HTML страницу с курсами валют на заданную дату. Соответственно алгоритм очень прост:</p>
<ul>
<li>с помощью интерфейса URL Fetch загружаем необходимую страницу с данными</li>
<li>парсим ее и извлекаем нужные</li>
<li>отображаем в текстовом виде (XML я использован только для меню)</li>
</ul>
<p>Код получился простой и уместился в один файл:</p>
<pre># coding=UTF-8

import wsgiref.handlers
from google.appengine.ext import webapp
from google.appengine.api import urlfetch
import os
from google.appengine.ext.webapp import template
from xml.dom import minidom
import re

WEATHER_URL = 'http://informer.gismeteo.ru/rss/%s.xml'

def render_template(self, templ, template_values={}):
    path = os.path.join(os.path.dirname(__file__), 'templates/'+templ)
    self.response.out.write(template.render(path, template_values))

def is_ipphone(self):
    if re.match('Allegro', self.request.headers.get('User-Agent', '')) == None:
        return False
    else:
        return True

class MainPage(webapp.RequestHandler):
    def get(self):
        if is_ipphone(self):
            self.response.headers['Content-type']='text/xml; charset=utf-8'
            render_template(self, 'main.xml')
        else:
            self.response.headers['Content-type']='text/html; charset=utf-8'
            render_template(self, 'main.html')

def parse_rss_data(content):
    result = ''
    dom = minidom.parseString(content)
    for item in dom.getElementsByTagName('item'):
        result = result + item.getElementsByTagName('title')[0].firstChild.nodeValue + '\n'
           + item.getElementsByTagName('description')[0].firstChild.nodeValue + '\n\n'
    return result

def rss_to_text(self, url):
    self.response.headers['Content-type']='text/plain; charset=utf-8'
    result = urlfetch.fetch(url)
    if result.status_code == 200:
        self.response.out.write(parse_rss_data(result.content))
    else:
        self.redirect('/error.xml')

class GisMeteo(webapp.RequestHandler):
    def get(self):
        rss_to_text(self, WEATHER_URL % '27612')

class YandexNews(webapp.RequestHandler):
    def get(self):
        rss_to_text(self, 'http://news.yandex.ru/Russia/index.rss')

class CbRF(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-type']='text/plain; charset=windows-1251'
        result = urlfetch.fetch('http://www.cbr.ru/currency_base/D_print.asp?date_req')
        if result.status_code == 200:
            data=re.split('&lt;td align="right" &gt;036&lt;/td&gt;', result.content)[1]
            for block in re.split('&lt;tr bgcolor="#ffffff"&gt;', data):
                cells = re.search('&lt;td align="left" &gt;&amp;nbsp;&amp;nbsp;(.*?)&lt;/td&gt;&lt;td align="right" &gt;(.*?)&lt;/td&gt;&lt;td&gt;&amp;nbsp;&amp;nbsp;(.*?)&lt;/td&gt;&lt;td align="right"&gt;(.*?)&lt;/td&gt;', block)
                if cells != None:
                    self.response.out.write(cells.group(2)+' '+cells.group(3)+' = '+cells.group(4)+'\n')
        else:
            self.redirect('/error.xml')

class Error(webapp.RequestHandler):
    def get(self):
        self.response.headers['Content-type]']='text/plain'
        self.response.out.write('Произошла ошибка при работе сервиса')

def main():
    application = webapp.WSGIApplication(
                                         [('/', MainPage),
                                         ('/error.xml', Error),
                                         ('/yandex_news.xml', YandexNews),
                                         ('/meteo.xml', GisMeteo),
                                         ('/cbrf.xml', CbRF)
                                         ],
                                         debug=True)
    wsgiref.handlers.CGIHandler().run(application)

if __name__ == '__main__':
    main()</pre>
<p>Самый интересный момент в коде: проверка при входе на главную страницу, является ли User-Agent IP телефоном или обычным компьютером и соответственно отображение или меню для телефона, или текста с описанием сервиса для человека. Как это выглядит вживую можно посмотреть на сайте сервиса &#8211; <a href="http://xmlphones.appspot.com" target="_blank">http://xmlphones.appspot.com</a>. Там же находится описание того, что необходимо прописать в Cisco CallManager для отображения данных на телефонах.</p>
<p>Благодаря Google теперь нет необходимости поднимать такой сервис внутри корпоративной сети, его можно эксплуатировать как общедоступный. Посмотреть другие возможности XML сервисов для IP телефонов Cisco можно <a href="http://www.cisco.com/en/US/products/sw/voicesw/ps556/products_programming_usage_guide_chapter09186a00807a35b9.html" target="_blank">здесь</a>.</p>
<p><a href="http://techwork.ru/2008/08/28/xml-services-part-2/">Перейти к второй части этой темы.</a></p>
]]></content:encoded>
			<wfw:commentRss>http://techwork.ru/2008/08/09/xml-services-for-ip-phones/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
	</channel>
</rss>
