• Home
  • Учебник по ExtJS
  • О сайте
  •  



    XML сервисы, часть вторая

    Недавно мы рассматривали создание приложения на платформе App Engine, которое позволяет IP телефонам Cisco получать информацию о прогнозе погоды, новостях и курсе валют.

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

    • Мы отображаем только погоду только по Москве, хотя сервис у нас глобальный
    • Существуют проблемы на разных версиях прошивок для телефонов, которые ожидают данные на русском языке в кодировке cp-1251.

    Первый недочет решено было исправить, добавив опциональный параметр city к URL сервиса, равный коду города на сайте ГисМетео, на котором мы берем данные погоды. Таким образом строка для телефонов Питера выглядит как http://xmlphones.appspot.com/?city=26063. Второй аналогично будет называться encode и содержать при необходимости задание кодировки windows-1251.

    Перекодировка в Python делается элегантно. Допустим, у нас через URLFetch получены данные в UTF-8, а вывод требуется в windows-1251:

    resp = unicode(result.content, 'utf-8') resp = resp.encode("cp1251")

    Ну и наоборот:

    resp = unicode(result.content, 'cp1251')

    В первом случае мы из байтового массива конструируем объект unicode, который затем кодируем с указанием кодека cp1251. Во втором случае одним действием из байтового массива конструируем также объект unicode с заданием кодека cp1251, но далее просто отдаем его в таком виде платформе App Engine (подразумевается что весь вывод по умолчанию в кодировке UTF-8).

    Все кажется замечательным, но тут опять обнаруживается криворукость писателей прошивок некоторых моделей IP телефонов, заключающаяся в том, что телефоны сами добавляют к параметрам запросов дополнительные переменные вида ?locale=English_United_States&name=SEP001B541415EE, что приводит к проблемам обработке меню сами же телефонами.

    Проведенный небольшой эксперимент показал, что если, например, параметры задавать с помощью многоуровневых URL, то все работает отлично. Допустим, кодировку windows-1251 мы будем задавать как http://xmlphones.appspot.com/windows-1251/ (подразумевая, по умолчанию корневой адрес аналогичный http://xmlphones.appspot.com/utf-8/), а город как http://xmlphones.appspot.com/utf-8/city/26063 (и опять это Питер).

    Выкидываем из кода несколько обработчиков, привязанных к URL, и заменяем их одним Dispatcher, который будет решать куда направить тот или иной запрос. Так как нашим сервисом уже пользуются люди, старые параметры ?encode и ?city также оставляем для совместимости, но делаем их второстепенными по сравнению со схемой параметров, заданных через URL.

    Вот что получилось в итоге:

    # coding=UTF-8 # -*- 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 import time WEATHER_URL = 'http://informer.gismeteo.ru/rss/%s.xml' def get_city(self):     city = self.request.get("city")     if city == '':         # Москва         city = '27612'     ccode = re.search('/.+/meteo/(.+)', self.request.path)     if ccode != None:         return ccode.group(1)     else:         return city def get_encode_templ(self):     encode = self.request.get("encode")     if encode == 'windows-1251':         return encode     else:         return 'utf-8' def render_template(self, templ, template_values={}, encode='utf-8'):     path = os.path.join(os.path.dirname(__file__), 'templates/'+templ)     resp = template.render(path, template_values)     if encode == 'windows-1251':         # Перекодируем из UTF-8 в CP1251         resp = unicode(resp, 'utf-8')         resp = resp.encode("cp1251")     self.response.out.write(resp) def is_ipphone(self):     if re.match('Allegro', self.request.headers.get('User-Agent', '')) == None:         return False     else:         return True      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):     result = urlfetch.fetch(url)     if result.status_code == 200:         resp = parse_rss_data(result.content)         charset = get_uri_encode(self)         if charset == 'windows-1251':             # Перекодируем из UTF-8 в CP1251             resp = resp.encode("cp1251")         self.response.headers['Content-type']='text/plain; charset='+charset         self.response.out.write(resp)     else:         self.redirect('/error.xml') def cbrf(self):     charset = get_uri_encode(self)     self.response.headers['Content-type']='text/plain; charset='+charset     result = urlfetch.fetch('http://www.cbr.ru/currency_base/D_print.asp?date_req='+time.strftime('%d.%m.%Y', time.localtime()))     if result.status_code == 200:         content = unicode(result.content, 'windows-1251')         data=re.split('<td align="right" >036</td>', content)[1]         for block in re.split('<tr bgcolor="#ffffff">', data):             block = re.sub('\r\n', '', block)             cells = re.search('<td align="left" >&nbsp;&nbsp;(.*?)</td><td align="right" >(.*?)</td><td>&nbsp;&nbsp;(.*?)</td><td align="right">(.*?)</td>', block)             if cells != None:                 resp = cells.group(2)+' '+cells.group(3)+' = '+cells.group(4)+'\n'                 if charset == 'windows-1251':                     # Перекодируем из UTF-8 в CP1251                     resp = resp.encode("cp1251")                 self.response.out.write(resp)     else:         self.redirect('/error.xml') def error(self):     self.response.headers['Content-type]']='text/plain'     self.response.out.write('Произошла ошибка при работе сервиса') def gismeteo(self):     city = get_city(self)     rss_to_text(self, WEATHER_URL % city) def yandex_news(self):     rss_to_text(self, 'http://news.yandex.ru/Russia/index.rss') def get_uri_encode(self, default = 'utf-8'):     urcode = re.search('/windows-1251/.*', self.request.url)     if (urcode != None):         return 'windows-1251'     else:         return default def main_page(self):     if is_ipphone(self):         citytmpl = get_city(self)         encode = get_encode_templ(self)         urlcity = re.search('/(.+)/city/(.+)', self.request.path)         if (urlcity != None):             citytmpl = urlcity.group(2)         encode = get_uri_encode(self, encode)         self.response.headers['Content-type']='text/xml; charset='+encode         render_template(self, 'main.xml', { 'city': citytmpl, 'encode': encode }, encode=encode)     else:         self.response.headers['Content-type']='text/html; charset=utf-8'         render_template(self, 'main.html')    class Dispatcher(webapp.RequestHandler):     def get(self):         # Анализируем только URI до знака ?         url = self.request.url.split('?')[0]         if re.search('/$', url):             main_page(self)             return         if re.search('/.+/city/.+', url):             main_page(self)             return         if re.search('/utf-8/$', url):             main_page(self)             return         if re.search('/windows-1251/$', url):             main_page(self)             return         if re.search('/(.+)/yandex_news.xml', url):             yandex_news(self)             return         if re.search('/(.+)/meteo.+', url):             gismeteo(self)             return         if re.search('/(.+)/cbrf.xml', url):             cbrf(self)             return         error(self) def main():     application = webapp.WSGIApplication(                                          [('/.*', Dispatcher)                                          ],                                          debug=True)     wsgiref.handlers.CGIHandler().run(application) if __name__ == '__main__':     main()

    Какие еще будут предложения по добавлению новых сервисов? Напишите комментарий к этой статье.

    33 Responses to “XML сервисы, часть вторая”

    1. [...] Перейти к второй части этой темы. [...]

    2. Алексей:

      Скажите, возможен ли сервис статистики звонков из личного кабинета sipnet.ru?

    3. techworkru:

      Возможно все :)
      Напишите кратко откуда нужно получать информацию и в каком виде выдавать.

      У вас как я понимаю, CCM подключен к sipnet.ru?

    4. Алексей:

      к sipnet.ru подключен Cisco 7941G.
      Информацию нужно получить из https://customer.sipnet.ru/cabinet/do_calls (требуется авторизация). Выдать:
      1 29/08/08 12:57 тел:90216ххххххх Turkey Istanbul время зв.1:47

      Собственно все.

    5. Alexey:

      Спасибо все работает. А как можно добавить в меню прогноза погоды несколько городов? Есть вообще такая возможность?

    6. Alexey:

      Подскажит как можно добавить в список прогноза погоды несколько городов? Это возможно?

    7. techworkru:

      Как насчет для каждой группы телефонов иметь собственный Services URL?

    8. Alexey:

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

    9. Vitaliy:

      Можно ли добавить возможность задавать сайт с курсами валют? мы не из России…. :-)

    10. techworkru:

      Какие именно нужны?

    11. techworkru:

      Это то, что требуется?

      Валютаның ресми (нарықтық) бағамы 26-09-2008
      USD / KZT TOD 119.78 0.04
      EUR / KZT TOD 176.39 0.67
      RUB / KZT TOD 4.8 0.02

    12. Vitaliy:

      да, только на русском

    13. DmS:

      Добрый день!
      Подскажите, пожалуйста, как победить ошибку HTTP [403]??
      Железо: UC 500, CUCME 4.2, CP-7940G, Application load P00308000500.

    14. techworkru:

      Какой указан URL сервиса в настройках телефона?

    15. techworkru:

      Во-первых, почему хост задан через IP?
      Во-вторых, какие DNS серверы указываются в настройках телефона?

    16. DmS:

      В качестве DNS-сервера указан соответствующий сервер в локалке. IP-телефон показывает его IP-шник. ПК, который подключен через телефон, показывает тот же IP-шник DNS-сервера. С ПК я спокойно пингую «xmlphones.appspot.com», а если в качестве «url service» пропишу «http://xmlphones.appspot.com», то получу ошибку «Host not found»…

    17. techworkru:

      Попробовали работу сервиса с CUCME 7.0, в блоке telephony-service задан параметр:

      url services http://xmlphones.appspot.com/

      Телефон 7941G имеет доступ в Интернет через NAT.
      К сожалению, при нажатии на кнопку Services выскакивает сначала вспомогательное меню, состоящее с трех пунктов:

      1) CME Service URL
      2) Extension Mobility
      3) My Phone Apps

      А при выборе первого, собственно отображаются сами XML сервисы. Видимо, такова логика работы CUME.

    18. Petrovich:

      На 7945, что в utf, что в windows, всегда вместо букв знаки ???.
      А на 7911 на том же CME все нормально.

    19. olegz:

      то же самое с 7965 (собссно, прошивки-то у них одинаковые с 7945)
      интересно другое: заголовки выдаются нормально: Новости Яндекса, Прогноз погоды, Курсы валют, а вот при заходе в подменю – вопросики вместо всех русских символов

    20. Oleg-y:

      Всё работает под ССМ 6.1, русская локаль стоит. Но на курсе валют ошибка 500

    21. allarm:

      Подтверждаю проблему с 7941 – символы «?» вместо букв, в обоих кодировках. Локаль телефона win-1251.

    22. Oleg-y:

      to allarm.
      а какая версия локали\прошивки стоит на 7941 ?
      у меня
      локаль po-locale-ru_RU-8.3.3.1000-1.cop.sgn
      прошивка SCCP41.8-3-4SR1S
      с этими всё работает, правда…курс валют выдаёт ошибку

    23. Oleg-y:

      По поводу дополнительных сервисов….
      Учитывая популярность некоторых сайтов, осталось добавить «Яндекс пробки» и котировки акций с с сайта Финам (www.finam.ru) . ))))

    24. Oleg-y:

      У меня работа телефонов построена через сквид. В настройках указываешь ИП адрес проксей и всё работает. Сами прокси так-же работают через NAT.

    25. Alex:

      У меня все работает на ура. Подскажите, есть ли возможность выводить информацию и меню на английском. И как можно загрузить новости и курс валют другой страны.

    26. С середины июня где-то курсы валют не работают, видимо какие-то изменения на сервере цб рф произошли на самих страницах, откуда данные забираются…

    27. techworkru:

      К сожалению, этот досадный глюк только что был исправен :(

    28. а на английском это получить никак нельзя?

    29. Алекандр:

      подскажите я указываю код города Тюмень по gismeteo
      url services http://xmlphones.appspot.com/windows-1251/city/4501
      так как код четырехзначный, телефон выплевывает traceback , как исправить?

      пробовал url services http://xmlphones.appspot.com/windows-1251/city/04501

      не помогает, подскажите пожалуйста

    30. Артур Сабитов:

      что покчавает телефон для себя чтобы пользоваться вашими сервисами, какую xml? что с курсом валют(только австралийский доллар)?

    Leave a Reply