Различия
Здесь показаны различия между двумя версиями данной страницы.
Следующая версия | Предыдущая версия | ||
fullcircle:36:python_ч_10 [2010/08/07 20:53] создано |
fullcircle:36:python_ч_10 [2011/02/20 16:27] (текущий) |
||
---|---|---|---|
Строка 3: | Строка 3: | ||
//Автор — Грэг Валтерс (Greg Walters)// | //Автор — Грэг Валтерс (Greg Walters)// | ||
</style> | </style> | ||
+ | |||
- [[..:27:python_ч_1|Программа на Python — часть 1]] | - [[..:27:python_ч_1|Программа на Python — часть 1]] | ||
Строка 15: | Строка 16: | ||
- [[..:36:python_ч_10|Программа на Python — часть 10]] | - [[..:36:python_ч_10|Программа на Python — часть 10]] | ||
- [[..:37:python_ч_11|Программа на Python — часть 11]] | - [[..:37:python_ч_11|Программа на Python — часть 11]] | ||
+ | - [[..:38:python_ч_12|Программа на Python — часть 12]] | ||
+ | - [[..:39:python_ч_13|Программа на Python — часть 13]] | ||
+ | - [[..:40:python_ч_14|Программа на Python — часть 14]] | ||
+ | |||
+ | Возможно, вы слышали об XML, однако можете и не знать, что это такое. В этом месяце нашу лекцию мы посвятим XML. Цели лекции: | ||
+ | |||
+ | * познакомить вас с тем, что такое XML; | ||
+ | * показать, как читать и записывать XML-файлы в ваших приложениях; | ||
+ | * подготовить к серьёзному проекту с использованием XML в следующий раз. | ||
+ | |||
+ | Итак, давайте поговорим об XML. XML означает «EXtensible Markup Language» («Расширяемый язык разметки»). Он достаточно похож на HTML. Формат разработан как способ хранения и эффективной передачи данных через интернет или другим образом. XML – это по существу текстовой файл, отформатированный с использованием ваших собственных тэгов и имеющий хорошие средства самодокументирования. Являясь текстом, он может быть сжат для более быстрой и легкой передачи данных. В отличие от HTML, XML сам по себе действий не производит и не связан с визуальным представлением данных. Как я отмечал, XML не требует набора стандартных тэгов: вы можете создавать свои собственные. | ||
+ | |||
+ | Давайте взглянем на типичный пример XML-файла. | ||
+ | <code> | ||
+ | <root> | ||
+ | <node1> Данные… </node1> | ||
+ | <node2 attribute=«something»>Данные Узла 2</node2> | ||
+ | <node3> | ||
+ | <node3sub1> ещё данные </node3sub1> | ||
+ | </node3> | ||
+ | </root> | ||
+ | </code> | ||
+ | Первое, что обращает на себя внимание, – это отступы. На самом деле они просто облегчают восприятие человеком. XML-файл будет рабочим, даже если он выглядит так: | ||
+ | |||
+ | <root><node1> Данные… </node1><node2 attribute=«something»> Данные Узла 2 </node2><node3><node3sub1>ещё данные</node3sub1></node3></root> | ||
+ | |||
+ | Тэги внутри угловых скобок **«< >»** отвечают некоторым правилам. Они должны состоять из одного слова. Каждому открывающему тэгу (например, <root>) должен соответствовать закрывающий, начинающийся с **«/»**. **Кроме того, тэги чувствительны к регистру: <node>, <Node>, <NODE> и <NodE> – различны**, и к каждому из них должен быть свой закрывающий тэг. Наименования тэгов могут содержать буквы, цифры и другие символы, но не могут начинаться с цифры или знака препинания. Избегайте знаков «-», «.», «:» в именах тэгов, так как некоторые программы могут рассматривать их как команды или свойства объекта. Помимо этого, запятые зарезервированы для некоторых других целей. Тэги также можно называть элементами. | ||
+ | |||
+ | Каждый XML-файл – это древовидная структура, начинающаяся с корня и ответвляющаяся от него. Он ДОЛЖЕН иметь корневой элемент – родитель для всех других элементов в файле. Вернёмся к нашему примеру. От корня отходят три дочерних элемента: node1, node2 и node3. Дочерние элементы имеют общий корень, а node3 является родителем для node3sub1. | ||
+ | |||
+ | Рассмотрим второй узел node2. Обратите внимание, что вдобавок к обычной информации внутри угловых скобок содержится атрибут (attribute). В настоящее время многие разработчики избегают использования атрибутов, так как без них элементы эффективнее и удобнее в использовании, но вы обнаружите, что атрибуты до сих пор используются. Мы познакомимся с ними позже. | ||
+ | |||
+ | Ниже приведён полезный пример. | ||
+ | |||
+ | Имеется корневой элемент «people», содержащий два дочерних – «person». Каждый элемент «person» содержит 6 дочерних элементов: «firstname», «lastname», «gender», «address», «city» и «state». На первый взгляд, XML-файл можно рассматривать как базу данных (вспомните несколько последних лекций), и это верное предположение. Некоторые приложения используют XML-файлы как простую структуру базы данных. Не составит труда написать программу для чтения XML-файла. Она должна открыть файл, прочитать его построчно и, в зависимости от элемента, использовать заключённые в нём данные, а затем закрыть файл. Однако есть и более эффективные способы. | ||
+ | |||
+ | В следующем примере мы воспользуемся модулем библиотеки под названием ElementTree. Его можно получить непосредственно из Synaptic, установив python-elementtree. Однако я предпочитаю устанавливать с сайта ElementTree (http://effbot.org/downloads/#elementtree) и непосредственно загружать файл-исходник (elementtree-1.2.6-20050316.tar.gz). После загрузки я с помощью менеджера пакетов извлекаю его во временную папку. Затем в этой папке выполняю «sudo python setup.py install». Эта команда помещает файлы в общую папку python, поэтому в дальнейшем у меня есть возможность использовать модуль и в python 2.5, и в 2.6. Итак, приступим к работе! Создайте папку, которая будет содержать код этого месяца, скопируйте приведённые выше данные в XML-формате в ваш любимый текстовой редактор и сохраните их в эту папку под именем «xmlsample1.xml». | ||
+ | |||
+ | Поговорим о нашем коде. В первую очередь хочется протестировать установленный модуль ElementTree. | ||
+ | |||
+ | <code>import elementtree.ElementTree as ET | ||
+ | |||
+ | tree = ET.parse('xmlsample1.xml') | ||
+ | |||
+ | ET.dump(tree)</code> | ||
+ | |||
+ | Запустив эту программу, мы получим нечто похожее на то, что представлено ниже. | ||
+ | |||
+ | Всё, что делает программа, – позволяет модулю ElementTree открыть файл, разбить на структурные элементы и сохранить в памяти в таком виде. Ничего сверхъестественного. | ||
+ | |||
+ | Теперь заменим наш код на следующий: | ||
+ | |||
+ | <code>import elementtree.ElementTree as ET | ||
+ | |||
+ | tree = ET.parse('xmlsample1.xml') | ||
+ | |||
+ | person = tree.findall('.//person') | ||
+ | |||
+ | for p in person: | ||
+ | |||
+ | for dat in p: | ||
+ | |||
+ | print "Элемент: %s - Данные: %s" %(dat.tag,dat.text)</code> | ||
+ | |||
+ | Запустите код снова. Результат будет таким: | ||
+ | |||
+ | **/usr/bin/python -u "/home/greg/Documents/articles/xml/reader1.py"** | ||
+ | |||
+ | * Элемент: firstname - Данные: Саманта | ||
+ | * Элемент: lastname - Данные: Фэроу | ||
+ | * Элемент: gender - Данные: Женский | ||
+ | * Элемент: address - Данные: ул. Мэйн, д. 123 | ||
+ | * Элемент: city - Данные: Дэнвер | ||
+ | * Элемент: state - Данные: Колорадо | ||
+ | * Элемент: firstname - Данные: Стив | ||
+ | * Элемент: lastname - Данные: Левон | ||
+ | * Элемент: gender - Данные: Мужской | ||
+ | * Элемент: address - Данные: Бульвар Арапахо, 332120 | ||
+ | * Элемент: city - Данные: Дэнвер | ||
+ | * Элемент: state - Данные: Колорадо | ||
+ | |||
+ | Теперь каждая порция данных выводится напротив имени тэга. Эти данные можно легко распечатать. Итак, посмотрим, что делает программа. Модуль ElementTree проанализировал файл и поместил результаты в объект tree. Затем ElementTree нашёл все вхождения тэга person. В нашем примере таких элементов оказалось два, но их могло быть 1 или 1000. Элемент person – дочерний к корневому элементу people. Все данные были разбиты на порции. Затем мы создали простой цикл, перебирающий объекты person. Вложенный в него цикл перебирает данные каждого элемента person, и на экран выводятся результаты, показывающие имя элемента (.tag) и данные (.text). | ||
+ | |||
+ | Рассмотрим более жизненный пример. Я со своей семьёй играю в Геокэшинг. Для тех, кто не знает, Геокэшинг – это «охота за сокровищами», когда «гики» используют мобильные устройства с GPS, чтобы найти нечто, спрятанное кем-то другим. Они публикуют GPS-координаты на веб-сайте, иногда с подсказками, а другие вводят координаты в свои GPS-навигаторы и пытаются найти тайник. По данным Википедии во всём мире существует более миллиона действующих точек кэшинга, таким образом, вероятно, они найдутся и поблизости от вас. Для поиска таких мест я использую два веб-сайта: http://www.geocaching.com/ и http://navicache.com/. Есть и другие сайты, но эти два – наиболее крупные. | ||
+ | |||
+ | Файлы, которые содержат информацию о каждом месте геокэшинга, – это обычно XML-файлы. Существуют программы, которые получают такие данные и передают их в устройство GPS. Некоторые из них действуют как приложения баз данных – позволяют отслеживать вашу деятельность, иногда с использованием карт. Теперь сконцентрируемся на анализе загружаемых файлов. | ||
+ | |||
+ | Я зашел на Navicache и обнаружил последний добавленный тайник в Техасе. Информация из файла показана на предыдущей странице. | ||
+ | |||
+ | Скопируем данные и сохраним их в файл «Cache.loc». Перед началом составления программы внимательно рассмотрим файл. | ||
+ | |||
+ | Первая строка обычно сообщает, что это проверенный XML-файл, её можно проигнорировать. Следующая строка, начинающаяся с «loc», является корневым элементом и содержит атрибуты «version» и «src». Выше я отмечал, что атрибуты иногда используются в файлах. В дальнейшем мы ещё будем иметь дело с ними в этом файле. Корневой элемент тут также может быть проигнорирован. Следующая строка содержит тэг дочернего элемента – маршрутной точки (waypoint). (Маршрутная точка – это место расположения, где можно найти тайник). Из этого элемента можно получить важные сведения: наименование тайника, координаты (долготу и широту), тип тайника и ссылку на интернет-страницу с дополнительной информацией. Элемент с именем содержит кучу полезной информации, но проводить её структурный анализ придётся самостоятельно. Давайте теперь создадим программу для чтения и отображения файла cache.loc, назвав её readacache.py. Начнём с импорта модуля и команд для структурного анализа из предыдущего примера. | ||
+ | |||
+ | <code>import elementtree.ElementTree as ET | ||
+ | |||
+ | tree = ET.parse('Cache.loc')</code> | ||
+ | |||
+ | Нам необходимо получить только данные, находящиеся внутри тэга waypoint. Для этого мы используем функцию .find внутри модуля ElementTree. Результаты работы будут сохранены в объекте w. | ||
+ | |||
+ | <code>w = tree.find('.//waypoint')</code> | ||
+ | |||
+ | Затем нам необходимо просмотреть все данные, для чего используется цикл for. В теле цикла мы ищем элементы name (имя), coord (координаты), type (тип) и link (ссылка). На основании содержащихся в тэге данных, мы извлекаем информацию, чтобы распечатать её в дальнейшем. | ||
+ | |||
+ | <code>for w1 in w: | ||
+ | if w1.tag == "name":</code> | ||
+ | |||
+ | Просмотрим, какие данные можно извлечь из тэга name. | ||
+ | <code> | ||
+ | <name id="N02CAC"><![CDATA[Возьмите Фотографии озера | ||
+ | Виноградной лозы, сделанные g_phillips | ||
+ | |||
+ | Тайник открыт: не ограничено | ||
+ | |||
+ | Тип тайника: обычный | ||
+ | |||
+ | Размер: обычный | ||
+ | |||
+ | Сложность: 1.5 | ||
+ | |||
+ | Местность: 2.0]]></name> | ||
+ | </code> | ||
+ | Это одна очень длинная строка. Идентификатор id установлен как атрибут. Имя тайника – это часть строки после «CDATA» и до «Тайник открыт:». Мы разделим | ||
+ | строку на несколько более мелких частей. | ||
+ | |||
+ | <code>newstring = oldstring[startposition:endposition]</code> | ||
+ | |||
+ | Итак, приведенный код можно использовать для извлечения необходимой информации. | ||
+ | |||
+ | Затем нам следует извлечь идентификатор, который содержится в атрибуте id тэга name. Проверим, имеются ли какие-либо атрибуты (а как мы знаем, они имеются), следующим образом: | ||
+ | |||
+ | <code>if w1.keys(): | ||
+ | for name,value in w1.items(): | ||
+ | if name == 'id': | ||
+ | CacheID = value</code> | ||
+ | |||
+ | Перейдём к работе с тэгами координат, типа и ссылки; соответствующий код показан ниже. В итоге мы выведем полученную информацию, используя код, размещенный в нижнем правом углу. Правее – полный листинг программы. | ||
+ | |||
+ | Теперь вы получили достаточно информации, чтобы суметь реализовать код для чтения большинства XML-файлов. Как всегда, вы можете получить полный код этой лекции на моём веб-сайте http://www.thedesignatedgeek.com. | ||
+ | |||
+ | В следующей лекции мы применим наши знания формата XML для получения и вывода на терминал сведений с замечательного сайта погоды. Наслаждайтесь! | ||
+ | |||
+ | --------------------------------------- | ||
+ | |||
+ | =====Коды:===== | ||
+ | **#1** | ||
+ | <code><people> | ||
+ | <person> | ||
+ | <firstname>Samantha</firstname> | ||
+ | <lastname>Pharoh</lastname> | ||
+ | <gender>Female</gender> | ||
+ | <address>123 Main St.</address> | ||
+ | <city>Denver</city> | ||
+ | <state>Colorado</state> | ||
+ | </person> | ||
+ | <person> | ||
+ | <firstname>Steve</firstname> | ||
+ | <lastname>Levon</lastname> | ||
+ | <gender>Male</gender> | ||
+ | <address>332120 Arapahoe Blvd.</address> | ||
+ | <city>Denver</city> | ||
+ | <state>Colorado</state> | ||
+ | </person> | ||
+ | </people> | ||
+ | </code> | ||
+ | |||
+ | **#2** | ||
+ | <code>/usr/bin/python -u "/home/greg/Documents/articles/xml/reader1.py" | ||
+ | |||
+ | <people> | ||
+ | <person> | ||
+ | <firstname>Samantha</firstname> | ||
+ | <lastname>Pharoh</lastname> | ||
+ | <gender>Female</gender> | ||
+ | <address>123 Main St.</address> | ||
+ | <city>Denver</city> | ||
+ | <state>Colorado</state> | ||
+ | </person> | ||
+ | <person> | ||
+ | <firstname>Steve</firstname> | ||
+ | <lastname>Levon</lastname> | ||
+ | <gender>Male</gender> | ||
+ | <address>332120 Arapahoe Blvd.</address> | ||
+ | <city>Denver</city> | ||
+ | <state>Colorado</state> | ||
+ | </person> | ||
+ | </people></code> | ||
+ | |||
+ | **#3** | ||
+ | <code> | ||
+ | <?xml version="1.0" encoding="ISO-8859-1"?> | ||
+ | <loc version="1.0" src="NaviCache"> | ||
+ | <waypoint> | ||
+ | <name id="N02CAC"><![CDATA[Take Goofy | ||
+ | Pictures at Grapevine Lake by g_phillips | ||
+ | Open Cache: Unrestricted | ||
+ | Cache Type: Normal | ||
+ | Cache Size: Normal | ||
+ | Difficulty: 1.5 | ||
+ | Terrain : 2.0]]></name> | ||
+ | <coord lat="32.9890166666667" lon="-97.0728833333333" /> | ||
+ | <type>Geocache</type> | ||
+ | <link | ||
+ | text="Cache Details"> | ||
+ | http://www.navicache.com/cgi-bin/db/displaycache2.pl | ||
+ | ?CacheID=11436</link> | ||
+ | </waypoint> | ||
+ | </loc> | ||
+ | </code> | ||
+ | |||
+ | **#4** | ||
+ | <code> | ||
+ | # Get text of cache name up to the phrase "Open Cache: " | ||
+ | CacheName = w1.text[:w1.text.find | ||
+ | ("Open Cache: ")-1] | ||
+ | # Get the text between "Open Cache: " and "Cache Type: " | ||
+ | OpenCache = w1.text[w1.text.find | ||
+ | ("Open Cache: ")+12:w1.text.find("Cache Type: ")-1] | ||
+ | # More of the same | ||
+ | CacheType = w1.text[w1.text.find | ||
+ | ("Cache Type: ")+12:w1.text.find | ||
+ | ("Cache Size: ")-1] | ||
+ | CacheSize = w1.text[w1.text.find | ||
+ | ("Cache Size: ")+12:w1.text.find | ||
+ | ("Difficulty: ")-1] | ||
+ | Difficulty= w1.text[w1.text.find | ||
+ | ("Difficulty: ")+12:w1.text.find | ||
+ | ("Terrain : ")-1] | ||
+ | Terrain = w1.text[w1.text.find | ||
+ | ("Terrain : ")+12:] | ||
+ | </code> | ||
+ | |||
+ | **#5** | ||
+ | <code> | ||
+ | elif w1.tag == "coord": | ||
+ | if w1.keys(): | ||
+ | for name,value in w1.items(): | ||
+ | if name == "lat": | ||
+ | Lat = value | ||
+ | elif name == "lon": | ||
+ | Lon = value | ||
+ | elif w1.tag == "type": | ||
+ | GType = w1.text | ||
+ | elif w1.tag == "link": | ||
+ | if w1.keys(): | ||
+ | for name, value in w1.items(): | ||
+ | Info = value | ||
+ | Link = w1.text | ||
+ | |||
+ | print "Cache Name: ",CacheName | ||
+ | print "Cache ID: ",CacheID | ||
+ | print "Open Cache: ",OpenCache | ||
+ | print "Cache Type: ",CacheType | ||
+ | print "Cache Size: ",CacheSize | ||
+ | print "Difficulty: ", Difficulty | ||
+ | print "Terrain: ",Terrain | ||
+ | print "Lat: ",Lat | ||
+ | print "Lon: ",Lon | ||
+ | print "GType: ",GType | ||
+ | print "Link: ",Link | ||
+ | </code> | ||
+ | |||
+ | **#6** | ||
+ | <code> | ||
+ | import elementtree.ElementTree as ET | ||
+ | tree = ET.parse('Cache.loc') | ||
+ | w = tree.find('.//waypoint') | ||
+ | for w1 in w: | ||
+ | if w1.tag == "name": | ||
+ | # Get text of cache name up to the phrase "Open Cache: " | ||
+ | CacheName = w1.text[:w1.text.find | ||
+ | ("Open Cache: ")-1] | ||
+ | # Get the text between | ||
+ | "Open Cache: " and "Cache Type: " | ||
+ | OpenCache = w1.text[w1.text.find | ||
+ | ("Open Cache: ")+12:w1.text.find | ||
+ | ("Cache Type: ")-1] | ||
+ | # More of the same | ||
+ | CacheType = w1.text[w1.text.find | ||
+ | ("Cache Type: ")+12:w1.text.find | ||
+ | ("Cache Size: ")-1] | ||
+ | CacheSize = w1.text[w1.text.find | ||
+ | ("Cache Size: ")+12:w1.text.find | ||
+ | ("Difficulty: ")-1] | ||
+ | Difficulty= w1.text[w1.text.find | ||
+ | ("Difficulty: ")+12:w1.text.find | ||
+ | ("Terrain : ")-1] | ||
+ | Terrain = w1.text[w1.text.find | ||
+ | ("Terrain : ")+12:] | ||
+ | if w1.keys(): | ||
+ | for name,value in w1.items(): | ||
+ | if name == 'id': | ||
+ | CacheID = value | ||
+ | elif w1.tag == "coord": | ||
+ | if w1.keys(): | ||
+ | for name,value in w1.items(): | ||
+ | if name == "lat": | ||
+ | Lat = value | ||
+ | elif name == "lon": | ||
+ | Lon = value | ||
+ | elif w1.tag == "type": | ||
+ | GType = w1.text | ||
+ | elif w1.tag == "link": | ||
+ | if w1.keys(): | ||
+ | for name, value in w1.items(): | ||
+ | Info = value | ||
+ | Link = w1.text | ||
+ | print "Cache Name: ",CacheName | ||
+ | print "Cache ID: ",CacheID | ||
+ | print "Open Cache: ",OpenCache | ||
+ | print "Cache Type: ",CacheType | ||
+ | print "Cache Size: ",CacheSize | ||
+ | print "Difficulty: ", Difficulty | ||
+ | print "Terrain: ",Terrain | ||
+ | print "Lat: ",Lat | ||
+ | print "Lon: ",Lon | ||
+ | print "GType: ",GType | ||
+ | print "Link: ",Link | ||
+ | print "="*25 | ||
+ | |||
+ | print "finished" | ||
+ | </code> | ||
+ | |||
+ | |||
+ | --------------------------------------- | ||
+ | |||
+ | <style center> | ||
+ | //[[..:36|К содержанию номера]]// | ||
+ | |||
+ | //[[:fullcircle|К архиву журналов]]// | ||
+ | </style> | ||
+ | |||
+ | {{tag>howto Full_Circle}} |