КАЗАНСКИЙ (ПРИВОЛЖСКИЙ) ФЕДЕРАЛЬНЫЙ УНИВЕРСИТЕТ ИНСТИТУТ ВЫЧИСЛИТЕЛЬНОЙ МАТЕМАТИКИ И ИНФОРМАЦИОННЫХ ТЕХНОЛОГИЙ КАФЕДРА ЭКОНОМИЧЕСКОЙ КИБЕРНЕТИКИ ПИНЯГИНА О.В. Технология XML и ее приложения (XML и все-все-все) Казань – 20** О.В. Пинягина УДК 681.3.06 ББК 32.988 – 018 Печатается по постановлению редакционно-издательского совета Института вычислительной математики и информационных технологий Казанского (Приволжского) федерального университета Рецензенты: ……………………………….. …………………………………. Пинягина О.В. Технология XML и ее приложения: Учебное пособие / О.В. Пинягина – Казань: Казанский государственный университет, 20**. – *** с. В данном учебном пособии рассматриваются основы технологии XML. Приводятся примеры приложений в разных областях программирования. Пособие разрабатывается для поддержки занятий по спецкурсу «Основы XML» и самостоятельной работы студентов, обучающихся по специальности «Математические методы в экономике» и направлениям «Бизнесинформатика», «Прикладная информатика», «Прикладная математика и информатика». Основная задача данного пособия – показать на конкретных примерах, где, с какой целью и каким образом можно и нужно применять XMLтехнологию в современном программировании. Пособие может быть использовано как дополнительная литература по курсам «Интернет-технологии», «Информационные технологии в экономике», «Базы данных», «Программирование в среде 1С:Предприятие», а также при подготовке курсовых и дипломных работ. Казанский государственный университет, 20** Пинягина О.В., 20** 2 Технология XML и ее приложения Содержание Содержание .............................................................................................3 Предисловие ...........................................................................................5 Глава 1. Основы XML ..........................................................................6 СТРУКТУРА XML-ДОКУМЕНТА ....................................................................................................6 Глава 2. DTD ...........................................................................................8 ЭЛЕМЕНТЫ ...................................................................................................................................9 АТРИБУТЫ ..................................................................................................................................11 СУЩНОСТИ .................................................................................................................................12 Глава 3. XML schema ..........................................................................14 Глава 4. Стили для XML-документов: CSS и XSLT ....................16 CSS .............................................................................................................................................17 XSL ............................................................................................................................................19 Глава 5. XML и PHP ...........................................................................26 RSS-КАНАЛЫ..............................................................................................................................26 ОРГАНИЗАЦИЯ RSS-КАНАЛА СЕРВЕРНЫМИ СРЕДСТВАМИ ........................................................27 XML, PHP И MYSQL .................................................................................................................33 DOMXML В PHP4 .....................................................................................................................35 Глава 6. XML и Ajax ...........................................................................38 СЛЕДИТЬ ЗА КЕМ-ТО – ЭТО ТАК НУДНО! .....................................................................................38 ОРГАНИЗАЦИЯ RSS-КАНАЛА КЛИЕНТСКИМИ СРЕДСТВАМИ ......................................................42 Глава 7. XML и SQL server ................................................................48 ЗАГРУЗКА XML-ДАННЫХ ПОСРЕДСТВОМ OPENXML ..............................................................48 ВЫГРУЗКА XML-ДАННЫХ С ПОМОЩЬЮ ДИРЕКТИВЫ FOR XML..............................................51 Глава 8. XML и «1С:Предприятие» .................................................58 ИМПОРТ ДАННЫХ .......................................................................................................................58 ЭКСПОРТ ДАННЫХ ......................................................................................................................59 РАБОТА С WEB-СЕРВИСАМИ .......................................................................................................61 Глава 9. XML и .NET ..........................................................................65 КЛАССЫ XMLNODE, XMLDOCUMENT......................................................................................65 СЕРИАЛИЗАЦИЯ ..........................................................................................................................69 Глава 10. XML и ASP.NET.................................................................77 Выгрузка и загрузка данных в формате XML через файлы ......77 ЗАГРУЗКА ДАННЫХ ИЗ XML-ФАЙЛА В БАЗУ ДАННЫХ ...............................................................77 ВЫГРУЗКА ДАННЫХ В XML-ФАЙЛ .............................................................................................79 Выгрузка и загрузка данных в формате XML в выходной поток /из входного потока………………………………………….81 ВЫГРУЗКА ДАННЫХ ....................................................................................................................81 ЗАГРУЗКА ДАННЫХ .....................................................................................................................83 Выгрузка и загрузка данных в формате XML через webсервисы ..................................................................................................85 ЗАГРУЗКА ДАННЫХ .....................................................................................................................85 ВЫГРУЗКА ДАННЫХ ....................................................................................................................87 Литература ............................................................................................90 3 О.В. Пинягина WEB-ресурсы........................................................................................90 4 Технология XML и ее приложения Работа с XML – это не какая-то будничная и монотонная задача. Она требует артистизма, страсти, экзальтации и эксцентричности. Стивен Холзнер Предисловие Аббревиатура XML расшифровывается как eXtensible Markup Language – расширяемый язык разметки. Считается, что XML идет на смену языку HTML вследствие ограниченных возможностей последнего. Не могу полностью согласиться с этим тезисом – XML не столько заменяет, сколько дополняет HTML. Эти два языка имеют совершенно разные цели. HTML создавался для визуального представления информации в Web и прекрасно справляется с этой задачей. XML же с самого начала был предназначен для четкого представления структуры документа в виде дерева с возможностью легкого доступа к любой его вершине. На сегодняшний день XML фактически является стандартом для обмена данных между приложениями. Современные программные продукты обязательно содержат средства для обработки XMLдокументов. Возможности некоторых из них мы и рассматриваем в данной книге. 5 О.В. Пинягина Глава 1. Основы XML Структура XML-документа Ключевым понятием XML, как и HTML, является тэг – команда, заключенная в угловые скобки. Однако между тэгами HTML и тэгами XML есть существенные различия. С одной стороны, стандартных тэгов XML (кроме управляющих команд) не существует – их придумывает сам разработчик, исходя из потребностей предметной области. С другой стороны, требования к применению тэгов XML гораздо более строгие, чем для HTML. Основные правила здесь следующие: в названиях тэгов регистр символов является существенным: тэги <BOOK> и <book> представляют собой разные команды; каждый тег должен закрываться: если в документе присутствует тэг <book>, значит, ниже по тексту должен быть тэг </book>; допускаются самозакрывающиеся тэги, такие как <book/>; в документе должен быть только один корневой тэг, являющийся контейнером для всех остальных данных; следует строго соблюдать вложенность тэгов-контейнеров: не допускается такая последовательность команд: <book><journal>…</book></journal> (правильно будет, например, <book> … </book><journal> … </journal> или <book><journal> … </journal></book>); значения атрибутов должны быть заключены в одинарные или двойные кавычки; первой строкой документа должна быть управляющая команда с номером версии XML и другими (необязательными) параметрами: <?xml version="1.0"?> 6 Технология XML и ее приложения Документ, удовлетворяющий этим правилам, называется well-formed (хорошо оформленным). Такой документ, например, будет корректно отображаться браузером Internet Explorer 6.0. Замечание: при использовании внутри XML-документа русских букв в управляющей команде обязательно требуется указать их кодировку, например: <?xml version="1.0" encoding="windows-1251"?> Таким образом, хорошо оформленным будет, например, следующий документ: <?xml version="1.0" encoding="windows-1251"?> <CATALOG> <BOOK type="paper" lang="ru"> <TITLE>Война и мир</TITLE> <AUTHOR>Л.Н. Толстой</AUTHOR> <BINDING>массовое издание</BINDING> <PAGES>1000</PAGES> <PRICE>$50</PRICE> </BOOK> <BOOK type="paper" lang="en"> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> <BOOK type="paper"> <TITLE>Moby-Dick</TITLE> <AUTHOR>Herman Melville</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>724</PAGES> <PRICE>$9.95</PRICE> </BOOK> <BOOK type="digital"> <TITLE>Fight Club</TITLE> <AUTHOR>Chuck Palahniuk</AUTHOR> <FORMAT>PDF</FORMAT> <PAGES>194</PAGES> <PRICE>$1.35</PRICE> </BOOK> </CATALOG> 7 О.В. Пинягина Глава 2. DTD Кроме хорошо оформленных (well formed), различают еще и правильные (valid) документы. XML-документ называется правильным, если он является хорошо оформленным и соответствует своему DTD или своей XML схеме. Давайте разберемся, что это означает. DTD расшифровывается как Document Type Definition – определение структуры документа – и представляет собой часть XMLфайла или отдельный файл, содержащий подробные определения для всех тэгов и их атрибутов. Если DTD встроен в XML-документ, то в документе должна быть команда <?xml standalone="yes"?>. Если DTD определен в отдельном файле, то в документе должна быть команда <?xml standalone="no"?> . Встроенный DTD представляет собой команду следующего вида; <!DOCTYPE Корневой тэг [ Описания элементов, атрибутов, сущностей ] > Например, XML-документ со встроенным DTD может выглядеть так: <?xml version="1.0" encoding="windows-1251" standalone="yes"?> <!DOCTYPE CATALOG [ <!ELEMENT CATALOG (#PCDATA)> ] > <CATALOG> Это Правильный Документ </CATALOG> 8 Технология XML и ее приложения Если DTD определен в отдельном файле, то в XML-документе должна быть ссылка на этот файл: <!DOCTYPE CATALOG SYSTEM "book.dtd"> а сам DTD-файл должен содержать только описания элементов, атрибутов и сущностей. Замечание: вместо слова SYSTEM в этой команде может применяться слово PUBLIC – для «публичных» стандартов, принятых W3C. Элементы Элементы являются основными структурными единицами XMLдокумента и соответствуют его тэгам. Определение элемента производится командой <!ELEMENT Имя_тэга (Тип_содержимого)> В качестве типа содержимого может быть указана стандартная конструкция #PCDATA (означающая любые текстовые данные), либо имена вложенных элементов. Например, <?xml version="1.0" encoding="windows-1251" standalone="yes"?> <!DOCTYPE CATALOG [ <!ELEMENT CATALOG (BOOK+)> <!ELEMENT BOOK (#PCDATA)> ] > <CATALOG> <BOOK> Война и мир, Л.Н. Толстой </BOOK> <BOOK> The Adventures of Huckleberry Finn, Mark Twain </BOOK> <BOOK> Moby-Dick, Herman Melville </BOOK> <BOOK> Fight Club, Chuck Palahniuk </BOOK> </CATALOG> 9 О.В. Пинягина После наименований вложенных элементов могут располагаться дополнительные модифицирующие символы. Они показывают, сколько раз этот элемент может появиться в пределах родительского тэга: - знак «+» – один или более раз; - знак «*» – ноль или более раз; - знак «?» – ноль или один раз. Так, в нашем каталоге может быть несколько книг, но не менее одной. Иерархия вложения может быть (и обычно бывает) многоуровневой и разветвленной. При этом порядок элементов в списке вложенных элементов является существенным, т.е., в XML-документе они должны присутствовать именно в этой последовательности. Например: <?xml version="1.0" encoding="windows-1251" standalone="yes"?> <!DOCTYPE CATALOG [ <!ELEMENT CATALOG (BOOK+)> <!ELEMENT BOOK (TITLE,AUTHOR,PAGES,PRICE)> <!ELEMENT TITLE (#PCDATA)> <!ELEMENT AUTHOR (#PCDATA)> <!ELEMENT PAGES (#PCDATA)> <!ELEMENT PRICE (#PCDATA)> ] <CATALOG> <BOOK> <TITLE>Война и мир</TITLE> <AUTHOR>Л.Н. Толстой</AUTHOR> <PAGES>1000</PAGES> <PRICE>$50</PRICE> </BOOK> <BOOK> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR>Mark Twain</AUTHOR> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> <BOOK> <TITLE>Moby-Dick</TITLE> 10 Технология XML и ее приложения <AUTHOR>Herman Melville</AUTHOR> <PAGES>724</PAGES> <PRICE>$9.95</PRICE> </BOOK> <BOOK> <TITLE>Fight Club</TITLE> <AUTHOR>Chuck Palahniuk</AUTHOR> <PAGES>194</PAGES> <PRICE>$1.35</PRICE> </BOOK> </CATALOG> В том случае, если какие-то вложенные элементы являются взаимоисключающими, их нужно заключить в круглые скобки и отделить друг от друга вертикальной чертой, например: <!ELEMENT BOOK (TITLE,AUTHOR,(BINDING | FORMAT),PAGES,PRICE)> Атрибуты Как и HTML-тэги, XML-тэги могут содержать атрибуты. Эти атрибуты можно интерпретировать как свойства объектов, например, <BOOK type="paper" lang="ru"> Атрибуты тоже должны быть определены в DTD. Список атрибутов тэга задается при помощи команды <!ATTLIST …>. Каждый атрибут имеет имя, тип и модификатор, например: <!ATTLIST BOOK lang (ru | en) #IMPLIED type CDATA #REQUIRED > Тип данных может быть строковый (CDATA), перечислимый (список возможных значений в скобках), либо маркер. В нашем примере атрибут type может принимать любое строковое значение, атрибут lang принимает значения ru или en. Модификаторы указывают: #IMPLIED – элемент не является обязательным; #REQUIRED – элемент является обязательным; 11 О.В. Пинягина #FIXED – элемент является константой. Сущности Еще одним ключевым понятием XML являютяся сущности. Сущность – это любой единый и неделимый кусок информации, не анализируемый XML-процессором. Сущности могут представлять собой бинарные файлы, такие, как рисунки, аудио- и видеодокументы, текстовые файлы и многое другое. В DTD сущность объявляется, например, так: <!ENTITY Имя_сущности SYSTEM "Имя_файла"> Для того чтобы вставить сущность в XML-документ, достаточно записать ее имя, предварив его знаком амперсанда (&). Окончательный вид нашего документа с определением элементов, атрибутов и сущностей приведен ниже. <?xml version="1.0" encoding="windows-1251" standalone="yes"?> <!DOCTYPE CATALOG [ <!ELEMENT CATALOG (BOOK+)> <!ELEMENT BOOK (TITLE,AUTHOR,(BINDING | FORMAT),PAGES,PRICE)> <!ATTLIST BOOK lang (ru | en) #IMPLIED type CDATA #REQUIRED> <!ELEMENT TITLE (#PCDATA)> <!ELEMENT AUTHOR (#PCDATA)> <!ELEMENT BINDING (#PCDATA)> <!ELEMENT FORMAT (#PCDATA)> <!ELEMENT PAGES (#PCDATA)> <!ELEMENT PRICE (#PCDATA)> <!ENTITY perevod SYSTEM "Monolog.txt"> ] > <CATALOG> <BOOK type="paper" lang="ru"> <TITLE>Война и мир</TITLE> <AUTHOR>Л.Н. Толстой</AUTHOR> <BINDING>массовое издание</BINDING> <PAGES>1000</PAGES> <PRICE>$50</PRICE> 12 Технология XML и ее приложения </BOOK> <BOOK type="paper" lang="en"> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> <BOOK type="paper"> <TITLE>Moby-Dick</TITLE> <AUTHOR>Herman Melville</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>724</PAGES> <PRICE>$9.95</PRICE> </BOOK> <BOOK type="dig"> <TITLE>Fight Club (&perevod;)</TITLE> <AUTHOR>Chuck Palahniuk</AUTHOR> <FORMAT>PDF</FORMAT> <PAGES>194</PAGES> <PRICE>$1.35</PRICE> </BOOK> </CATALOG> 13 О.В. Пинягина Глава 3. XML schema DTD, конечно, является удобным средством определения структуры документа, но у него есть очевидные ограничения. Так, например, мы не можем средствами DTD указать, что количество страниц должно являться целым положительным числом не более 5000 или задать какой-либо более сложный шаблон для атрибутов. Для таких случаев можно вместо DTD воспользоваться таким понятием, как XML схема. Для предварительной генерации XML схемы можно воспользоваться редакторами XML (например, XMLPad), которые на основе уже имеющегося XML-документа легко создают XML схему. Эту схему можно затем уточнить и модифицировать. Приведем пример. На основе следующего XMl-документа создадим XML схему. <?xml version="1.0" encoding="UTF-8"?> <ALLMEBEL> <MEBEL NAME="Комод Black Stone" PIC="20.jpg" GAB="103, 40, 120" COLOR="Темный" KOMPL="Дуб" KOD="000000020"/> <MEBEL NAME="Стол журнальный Black Stone" PIC="16.jpg" GAB="103, 60, 60" COLOR="Темный, Ваниль" KOMPL="Дуб, Стекло" KOD="000000016"/> <MEBEL NAME="Тумба под ТВ Black Stone" PIC="15.jpg" GAB="103, 50, 50" COLOR="Темный, Ваниль" KOMPL="Дуб" KOD="000000015"/> <MEBEL NAME="Кровать двуспальная Black Stone" PIC="17.jpg" GAB="180, 200, 30" COLOR="Темный" KOMPL="Дуб" KOD="000000017"/> </ALLMEBEL> <?xml version="1.0" encoding="utf-8"?> <xs:schema xmlns:xs=http://www.w3.org/2001/XMLSchema xmlns:wmh="http://www.wmhelp.com/2003/eGenerator" elementFormDefault="qualified"> <xs:element name="ALLMEBEL"> <xs:complexType> <xs:sequence> 14 Технология XML и ее приложения <xs:element ref="MEBEL" maxOccurs="unbounded"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="MEBEL"> <xs:complexType> <xs:attribute name="NAME" type="xs:string" use="required"/> <xs:attribute name="PIC" type="xs:string" use="required"/> <xs:attribute name="GAB" type="xs:string" use="required"/> <xs:attribute name="COLOR" type="xs:string" use="required"/> <xs:attribute name="KOMPL" type="xs:string" use="required"/> <xs:attribute name="KOD" type="xs:string" use="required"/> </xs:complexType> </xs:element> </xs:schema> Подробно об XML-схемах можно прочитать в [2], [3], [6]. 15 О.В. Пинягина Глава 4. Стили для XML-документов: CSS и XSLT Рассмотрим пример XML-документа с информацией о книгах из предыдущей главы. Если просмотреть этот документ в браузере Internet Explorer, то мы увидим примерно такую же картину, как и в текстовом редакторе, только будет добавлена цветовая разметка и рядом с тегами-контейнерами появится символ «минус», означающий, что данный узел можно «свернуть»: <?xml version="1.0" encoding="windows-1251" ?> <!DOCTYPE CATALOG (View Source for full doctype...)> - <CATALOG> - <BOOK type="paper" lang="ru"> <TITLE>Война и мир</TITLE> <AUTHOR>Л.Н. Толстой</AUTHOR> <BINDING>массовое издание</BINDING> <PAGES>1000</PAGES> <PRICE>$50</PRICE> </BOOK> - <BOOK type="paper" lang="en"> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> - <BOOK type="paper"> <TITLE>Moby-Dick</TITLE> <AUTHOR>Herman Melville</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>724</PAGES> <PRICE>$9.95</PRICE> </BOOK> - <BOOK type="digital"> <TITLE>Fight Club (Translated by I.Kormiltcev.)</TITLE> <AUTHOR>Chuck Palahniuk</AUTHOR> <FORMAT>PDF</FORMAT> <PAGES>194</PAGES> <PRICE>$1.35</PRICE> </BOOK> </CATALOG> 16 Технология XML и ее приложения Такой документ, конечно, можно читать, но он не слишком удобен для восприятия. Один из подходов, позволяющий отформатировать документ и привести его в более читабельный вид, состоит в применении стилевых назначений CSS или XSL. Эти технологии являются понятными для большинства современных браузеров. CSS Технология CSS (Cascading Style Sheets) – каскадные стилевые таблицы – была разработана как дополнение языка HTML и позволяет создавать единые стили оформления для целых сайтов. Эту технологию можно применить и для отображения XML-документов. Рассмотрим несколько эклектичный пример форматирования нашего документа с помощью CSS-стилей. Для этого создадим файл style.css со следующими назначениями: BOOK { display: block; background-image: url(Leaf.bmp); margin-top: 10px; border: thin dotted Green; } TITLE { font-weight: bold; font-style: italic; font-size: 14pt; color: #006400; background-color: #F5F5DC; } AUTHOR { font-weight: bold; font-size: 14pt; color: green; } BINDING { display: block; 17 О.В. Пинягина font-size: 12pt; font-weight: bold; } FORMAT { display: block; font-size: 12pt; font-weight: bold; color: blue; } В этом файле мы задаем стилевые назначения для каждого тэга, который мы хотим отобразить в виде, отличающемся от значений по умолчанию. Так, например, контейнер согласно стилевому файлу, <book>, представляет собой блок-прямоугольник (display: фоновым рисунком (background-image: пунктирной рамкой (border: 18 с заданным url(Leaf.bmp)), thin dotted Green) блоками в 10 пикселей (margin-top: block) 10px). зеленой и зазором между Подобным образом Технология XML и ее приложения задаются и стили для тэгов <title>, Обратите внимание, что для тэгов <author>, <format> <price> и <pages> и <binding>. стили не заданы, поэтому информация будет напечатана стилем, принятым в браузере по умолчанию. Этот стилевой файл нужно подключить в XML-документе строкой <?xml-stylesheet type="text/css" href="style.css"?> Следует отметить, что технология CSS имеет некоторые существенные ограничения. Так, в частности, мы не можем изменить порядок следования тэгов в документе, не можем создать гиперссылки и отобразить картинки, не можем даже вывести информацию в виде таблицы. (Хотя в стандарте CSS level2 имеются назначения display:table; display:table-row; display: table-cell; и т.п., но, например, Internet Exporer 6.0 эти назначения не понимает.) Более сложное и изощренное форматирование можно получить, применяя технологию XSL. XSL Технология XSL расшифровывается как eXtensible Stylesheet Language. На сегодняшний момент это официальный стилевой язык для XML. С его помощью можно отформатировать наш документ так, как показано на следующий странице. Для получения такого результата создадим файл style2.xsl со следующим содержимым: <?xml version="1.0" encoding="windows-1251" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <xsl:template match="/"> <HTML> <BODY bgcolor="#ccddee"> <TABLE border="1" cellspacing="0" cellpadding="2" bordercolor="blue"> <tr> 19 О.В. Пинягина <th>Название</th> <th>Автор</th> <th>Цена</th> <th>Страниц</th> </tr> <xsl:apply-templates select="CATALOG/BOOK" /> </TABLE> </BODY> </HTML> </xsl:template> <xsl:template match="BOOK"> <TR> <td> <xsl:value-of select="TITLE" /> </td> <td> <xsl:value-of select="AUTHOR" /> </td> <td> <xsl:value-of select="PRICE" /> </td> <td> <xsl:value-of select="PAGES" /> </td> </TR> </xsl:template> </xsl:stylesheet> Следует заметить, что сам XSL-файл представляет собой хорошо оформленный стандартной. 20 (well-formed) XML-файл. Первая строка является Технология XML и ее приложения Тэг стилевого <xsl:stylesheet> файла. Далее представляет собой корневой элемент XSL-файл содержит набор шаблонов оформления для различных тэгов из XML-файла. Эти шаблоны <xsl:template>. представлены Параметр match="Имя-тэга" тэгу относится данный шаблон. Значение "/" тэгами-контейнерами указывает, к какому означает корневой элемент XML-файла. Внутри шаблона могут присутствовать HTMLтэги. В нашем примере шаблон для корневого элемента содержит шапку таблицы с названиями стоблцов. Далее тэг <xsl:apply-templates select="CATALOG/BOOK" /> означает, что в данном месте должен быть применен шаблон для тэга <book>. Обратите внимание, что здесь не требуется использовать цикл – шаблон будет применен столько раз, сколько тэгов <book> было в документе. Шаблон <xsl:template match="BOOK"> формирует строку HTML-таблицы, в ячейки которой с помощью команд <xsl:value-of> подставляются значения из тэгов, указанных в параметре например, select="PAGES". select, Обратите внимание, что из всех данных о книге мы выбираем только название, автора, цену и количество страниц. Для подключения стилевого файла в XML-документ следует включить строку <?xml-stylesheet type="text/xsl" href="style2.xsl"?> Рассмотрим другой стилевой файл: <?xml version="1.0" encoding="windows-1251" ?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/TR/WD-xsl"> <xsl:template match="/"> <H2>Список книг, отсортированный по автору</H2> <xsl:for-each select="CATALOG/BOOK" order-by="+AUTHOR"> <SPAN STYLE="font-style:italic">Название: </SPAN> 21 О.В. Пинягина <xsl:value-of select="TITLE"/><BR /> <SPAN STYLE="font-style:italic">Автор: </SPAN> <xsl:value-of select="AUTHOR"/><BR /> <SPAN STYLE="font-style:italic">Тип: </SPAN> <xsl:value-of select="BINDING"/> <xsl:value-of select="FORMAT"/><BR /> <SPAN STYLE="font-style:italic">Страниц: </SPAN> <xsl:value-of select="PAGES"/><BR /> <SPAN STYLE="font-style:italic">Цена: </SPAN> <xsl:value-of select="PRICE"/><P /> </xsl:for-each> </xsl:template> </xsl:stylesheet> Обратите внимание, что здесь не задается шаблон для тэга <book>, а вместо этого используется select="CATALOG/BOOK"> цикл, и тэг <xsl:for-each применяется столько раз, сколько в XML- файле было книг. В этом тэге также задана сортировка по автору, в 22 Технология XML и ее приложения порядке возрастания: order-by="+AUTHOR". Для сортировки по убыванию знак «плюс» следует поменять на «минус». На картинке показан результат применения этого стилевого файла. В предыдущих примерах мы применяли стили к XML-тэгам. Что же делать в том случае, когда требуется вывести информацию из атрибутов тэга? Следующий пример даёт ответ на этот вопрос. Обратите внимание также, каким образом выводить в браузер изображения. XML-Документ: <?xml version="1.0" encoding="UTF-8"?> <?xml-stylesheet type="text/xsl" href="style.xsl"?> <ALLMEBEL> <MEBEL NAME="Комод Black Stone" PIC="20.jpg" 23 О.В. Пинягина GAB="103, 40, 120" COLOR="Темный" KOMPL="Дуб" KOD="000000020"/> <MEBEL NAME="Стол журнальный Black Stone" PIC="16.jpg" GAB="103, 60, 60" COLOR="Темный, Ваниль" KOMPL="Дуб, Стекло" KOD="000000016"/> <MEBEL NAME="Тумба под ТВ Black Stone" PIC="15.jpg" GAB="103, 50, 50" COLOR="Темный, Ваниль" KOMPL="Дуб" KOD="000000015"/> <MEBEL NAME="Кровать двуспальная Black Stone" PIC="17.jpg" GAB="180, 200, 30" COLOR="Темный" KOMPL="Дуб" KOD="000000017"/> </ALLMEBEL> Стилевой файл: <?xml version="1.0" encoding="windows-1251"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="/"> <TABLE border="1" bordercolor="blue"> <xsl:for-each select="/ALLMEBEL/MEBEL"> <tr> <td> <P> <SPAN STYLE="font-style:italic">Название: </SPAN> <xsl:value-of select="@NAME"/> <BR/> <SPAN STYLE="font-style:italic">Габариты: </SPAN> <xsl:value-of select="@GAB"/> <BR/> <SPAN STYLE="font-style:italic">Цвет: </SPAN> <xsl:value-of select="@COLOR"/> <BR/> <SPAN STYLE="font-style:italic">Комплектация: </SPAN> <xsl:value-of select="@KOMPL"/> <BR/> </P> </td> <td> <img src="{@PIC}" /> </td> </tr> </xsl:for-each> </TABLE> </xsl:template> </xsl:stylesheet> Итак, стилевые файлы позволяют отформатировать наш XMLдокумент для приведения его к виду, удобному для чтения. Особенно 24 Технология XML и ее приложения мощной здесь является технология XSL, подробнее о которой вы можете узнать из книги [2]. Однако зачастую XML-документ служит не для визуального представления информации в браузере, а для ее дальнейшей обработки, например, для записи в базу данных. В таком случае не обойтись без разработки программ-анализаторов XMLдокументов на каком-либо языке программирования. Некоторые из таких направлений рассмотрены в последующих главах. 25 О.В. Пинягина Глава 5. XML и PHP RSS-каналы Аббревиатуру RSS расшифровывают по-разному. Так или иначе, RSS предназначено для обмена новостями между сайтами. Сайт-хозяин новости размещает ее в формате XML по заданному адресу. После этого любой другой сайт может обратиться к этой новости, отформатировать ее и опубликовать для своих читателей. При этом используется стандартный набор тэгов, специально разработанный для RSS-каналов. Смысл этих тэгов понятен из их названий. Рассмотрим, например, новости-прогноз погоды, которые предоставляет известный сайт Gismeteo.ru. Прогноз погоды для г. Казани содержится в файле http://informer.gismeteo.ru/rss/27595.xml <?xml version="1.0" encoding="windows-1251" ?> -<rss xmlns:gismeteo="http://www.gismeteo.ru" version="2.0"> - <channel> <title>GISMETEO.RU: Погода от ФОБОС и Мэп Мейкер</title> <link>http://www.gismeteo.ru</link> <description>Прогноз погоды по 4500+ городам России и Мира</description> <ttl>60</ttl> - <image> <title>GISMETEO.RU: Погода от ФОБОС и Мэп Мейкер</title> <width>142</width> <height>18</height> <link>http://www.gismeteo.ru</link> <url>http://img.gismeteo.ru/images/gismeteo2.gif</url> </image> - <item> <title>Казань: Утро 12 окт, Пт</title> <link>http://www.gismeteo.ru/towns/27595.htm?1026259</link> <description>пасмурно, небольшой дождь, температура +2..+4 С, давление 745..747 мм рт.ст., ветер Северо-Западный, 4 м/с</description> <category>Погода</category> <enclosure url="http://img.gismeteo.ru/images/cloud.gif" length="2000" type="image/gif" /> <source url="http://informer.gismeteo.ru/rss/27595.xml">GISMETEO.RU: Погода в г. Казань</source> <guid>1090476</guid> </item> - <item> <title>Казань: День 12 окт, Пт</title> <link>http://www.gismeteo.ru/towns/27595.htm?1006293</link> 26 Технология XML и ее приложения <description>малооблачно, без осадков, температура +4..+6 С, давление 749..751 мм рт.ст., ветер Северо-Западный, 3 м/с</description> <category>Погода</category> <enclosure url="http://img.gismeteo.ru/images/sunc.gif" length="2000" type="image/gif" /> <source url="http://informer.gismeteo.ru/rss/27595.xml">GISMETEO.RU: Погода в г. Казань</source> <guid>1030168</guid> </item> ... </channel> </rss> Итак, в XML-файле с данными для RSS-канала корневым является тэг <rss> со служебной информацией, в котором располагается тэг <channel> – непосредственно канал новостей. В нем, прежде всего, содержится общая информация – заголовок новости (<title>), ссылка на сайт (<link>), краткое описание (<description>) и информация о картинке сайта (<image>). Далее в документе располагаются один или несколько тэгов <item>, содержащих составные части новости – в данном случае, прогнозы погоды на день, вечер, ночь и т.п. Каждый тэг <item>, в свою очередь, представляет собой контейнер, содержащий заголовок, ссылку, краткое описание, ссылку на картинку и другие тэги. При публикации новости мы можем использовать либо все эти данные, либо их часть. Заметим, что здесь мы не можем задать в XML-документе ссылку на стилевой файл для представления данных, так как этот документ расположен на чужом сервере. Рассмотрим, как можно организовать обработку такого RSS-файла серверными или клиентскими средствами. Организация RSS-канала серверными средствами Для публикации использовать новости технологию PHP. серверными В РНР есть средствами набор будем функций, 27 О.В. Пинягина позволяющий работать с XML-файлом, как с линейным потоком информации, т.е., по технологии SAX: xml_parser_create() Создает экземпляр обработчика XML. xml_set_element_handler(parser, startElementFunction, endElementFunction) Функция определяет обратные вызовы, которые должен осуществлять обработчик при нахождении открывающих и закрывающих тэгов. startElementFunction определяет функцию для открывающих тэгов, endElementFunction, соответственно, для закрывающих. parser — это объект, возвращенный функцией xml_parser_create(). xml_set_chracter_data_handler(parser, characterDataFunction) Данная функция определяет обратный вызов, осуществляемый при обработке события, связанного с нахождением данных, содержащихся между XML-тэгами. Назначение параметров аналогично xml_set_element_handler(). xml_parse(parser, data, endOfDocument) Эта функция инициализирует анализ переданного ей XML-кода. Параметр endOfDocument должен быть равен true, если параметр data содержит конец документа, или же false, если data не включает в себя документ до конца. Это позволяет обработчику корректно обрабатывать незавершенные тэги и прочие ошибки форматирования документа, возникающие в связи с тем, что переменная data не может содержать данные длиной более 4-х килобайт. xml_parser_free(parser) Функция освобождает память, занятую объектом parser. Прежде всего, создадим класс RSSParser, внутри которого будет выполняться вся работа по разбору XML, и который будет выводить на печать (или же в поток вывода от сервера к браузеру) форматированные HTML-данные. После создания класса получим RSS-данные от сервиса Gismeteo.ru и инициализируем обработчик XML, который будет использовать для событийной обработки класс RSSParser. <? 28 Технология XML и ее приложения class RSSParser { var $insideItem=false; var $tag=""; var $title=""; var $description=""; var $originalLink=""; var $image=""; function mystart($parser, $name, $attrs) { if($this->insideItem) { $this->tag=$name; if($name=="ENCLOSURE") { $this->image=$attrs["URL"]; } } elseif($name=="ITEM") { $this->insideItem=true; } } function myend($parser, $name) { if($name=="ITEM") { printf("<big>%s</big> ", $this->title); printf("<image src='%s'><br> ", $this->image); printf("%s ", $this->description); printf("<a href=\"%s\" target=_blank>больше...</a><hr>", $this->originalLink); $this->title=""; $this->insideItem=false; $this->title=""; $this->description=""; $this->originalLink=""; } else { $this->tag=""; } } function mystr($parser, $data) { if($this->insideItem) { switch($this->tag) 29 О.В. Пинягина { case "TITLE": $this->title=$data; break; case "DESCRIPTION": $this->description=$data; break; case "LINK": $this->originalLink=$data; break; } } } } $xml_parser=xml_parser_create(); $rss_parser= new RSSParser(); xml_set_object($xml_parser, &$rss_parser); xml_set_element_handler ($xml_parser, "mystart", "myend"); xml_set_character_data_handler ($xml_parser, "mystr"); $fp=fopen("http://informer.gismeteo.ru/rss/27595.xml", "r") or die("Error!"); while($data=fread($fp, 4096)) { xml_parse($xml_parser,$data); } fclose($fp); xml_parser_free ($xml_parser) ?> Этот сценарий можно включить в любое место нашего сайта. Результат его работы приведен на следующей странице. Как уже было сказано, прежде всего, в сценарии создается классобработчик RSSParser. В этом классе нужно определить 3 функции – обработчик открывающего тега, обработчик закрывающего тэга и обработчик текстовой информации внутри тэга. Кроме того, в классе определены несколько переменных. Переменная $insideItem флажком для определения, находимся ли мы сейчас внутри тэга служит <item> или нет. Остальные переменные нужны для временного хранения 30 Технология XML и ее приложения содержимого текущих тэгов – заголовка, описания, ссылки на картинку и т.п. В качестве обработчика открывающего тэга определим функцию mystart ($parser, $name, $attrs). Параметр parser — это уже известный объект, созданный функцией xml_parser_create(). Параметр name — название того тэга, который анализирует обработчик XML, а параметр attrs — ассоциативный массив, содержащий атрибуты текущего тэга. Стоит отметить, что имена тэгов в PHP-коде должны задаваться только(!) прописными буквами. Функция myend ($parser, $name) отвечает за обработку события, возникающего при обнаружении закрывающего тэга. Параметр name содержит имя этого тэга. Именно эта функция выводит всю информацию, которую получает класс во время обработки XMLдокумента. Она же обнуляет все внутренние переменные по завершении вывода. 31 О.В. Пинягина Функция mystr ($parser, $data) обрабатывает данные, которые находятся внутри XML-тэгов, присваивая свойствам класса соответствующие значения. Создание класса требуется для того, чтобы передавать параметры из одной функции обратного вызова в другую (их передают свойства класса), не используя директиву global и глобальные переменные. Далее в сценарии мы создаем стандартный XML-анализатор: $xml_parser=xml_parser_create(); создаем объект только что созданного нами класса: $rss_parser= new RSSParser(); назначаем его в качестве обработчика содержимого XML-файла: xml_set_object($xml_parser, &$rss_parser); назначаем обработчики открывающих и закрывающих тэгов: xml_set_element_handler ($xml_parser, "mystart", "myend"); и обработчик содержимого тэга: xml_set_character_data_handler ($xml_parser, "mystr"); Затем мы открываем XML-источник, читаем из него данные и передаем их на обработку функции xml_parse. По окончании работы освобождаем XML-анализатор. Такой подход можно использовать, если в нашем распоряжении есть доступ к серверу и возможность создавать свои серверные сценарии. Как же быть в том случае, если у нас есть возможность создавать и размещать в сети только HTML-страницы? Решение проблемы будет рассмотрено в главе 6. 32 Технология XML и ее приложения XML, PHP и mySQL В следующем примере PHP-сценарий получает в качестве входных данных документ, содержащий информацию о блюдах сегодняшнего меню: <?xml version="1.0" encoding="windows-1251" ?> <Menu> <Course Name="Кофе Мокко" Price="45" Kod="000000007" /> <Course Name="Кофе Эспрессо" Price="55" Kod="000000008" /> <Course Name="Лимонад" Price="30" Kod="000000006" /> <Course Name="Кефир" Price="5" Kod="000000014" /> <Course Name="Пицца Маргарита" Price="120" Kod="000000009" /> <Course Name="Салат Мимоза" Price="60" Kod="000000010" /> <Course Name="Овощной салат" Price="35" Kod="000000011" /> <Course Name="Хлеб" Price="1" Kod="000000012" /> </Menu> Это меню нужно переписать в базу данных mySQL. В базе данных под названием SunnyTown имеется таблица блюд меню, созданная следующей командой: create table menu (kod varchar(9) NOT NULL, data date NOT NULL, name varchar(50), price numeric(6,2), primary key (kod, data)); В следующем сценарии основные действия с выполняются в обработчике mystart. Из атрибутов XML-тэга данными <COURSE> читаются данные о блюде, и выполняется соответствующая команда INSERT. Текущая дата задается с помощью функции mySQL CURDATE(). <? class MYParser { var $insideItem=false; var $tag=""; var $name=""; var $price=0; var $kod=""; 33 О.В. Пинягина function mystart($parser, $name, $attrs) { if($name=="COURSE") { $this->name=$attrs["NAME"]; $this->kod=$attrs["KOD"]; $this->price=$attrs["PRICE"]; $insert="INSERT INTO menu(kod, data, name, price) VALUES('".$this->kod."', CURDATE(),'".$this->name."'," .(0+$this->price). ")"; mysql_query($insert) or die("Insert Error"); } } function myend($parser, $name) {} function mystr($parser, $data) {} } $xml_parser=xml_parser_create(); $my_parser= new MYParser(); xml_set_object($xml_parser, &$my_parser); xml_set_element_handler ($xml_parser, "mystart", "myend"); xml_set_character_data_handler ($xml_parser, "mystr"); $data=$HTTP_RAW_POST_DATA; mysql_connect("localhost", "root", "") or die ("Connecting Error!"); mysql_select_db("SunnyTown") or die ("Database Error!"); $delete="DELETE FROM menu WHERE data=CURDATE()"; mysql_query($delete); xml_parse($xml_parser,$data); xml_parser_free ($xml_parser); print "OK"; ?> В данном примере XML-документ передается внутри POSTзапроса, и обращаться к нему в PHP-сценарии можно с помощью глобальной переменной $HTTP_RAW_POST_DATA. 34 Технология XML и ее приложения DOMXML в PHP4 В отличие от SAX-технологии, в которой XML-документ рассматривается как линейный поток байтов, при использовании DOMтехнологии из XML-документа создается иерерхический объект, т.е., дерево, по узлам которого мы и перемещается в ходе программы. Рассмотрим пример для версии PHP4 (для более новых версий он работать не будет!). Из XML-документа, содержащего список книг <?xml version="1.0" encoding="windows-1251"?> <CATALOG> <BOOK type="paper" lang="ru"> <TITLE>Война и мир</TITLE> <AUTHOR>Л.Н. Толстой</AUTHOR> <BINDING>массовое издание</BINDING> <PAGES>1000</PAGES> <PRICE>$50</PRICE> </BOOK> <BOOK type="paper" lang="en"> <TITLE>The Adventures of Huckleberry Finn</TITLE> <AUTHOR>Mark Twain</AUTHOR> <BINDING>mass market paperback</BINDING> <PAGES>298</PAGES> <PRICE>$5.49</PRICE> </BOOK> <BOOK type="paper"> <TITLE>Moby-Dick</TITLE> <AUTHOR>Herman Melville</AUTHOR> <BINDING>hardcover</BINDING> <PAGES>724</PAGES> <PRICE>$9.95</PRICE> </BOOK> <BOOK type="digital"> <TITLE>Fight Club</TITLE> <AUTHOR>Chuck Palahniuk</AUTHOR> <FORMAT>PDF</FORMAT> <PAGES>194</PAGES> <PRICE>$1.35</PRICE> </BOOK> </CATALOG> мы хотим сформировать такой HTML-документ: 35 О.В. Пинягина <? header("Cache-control: no-cache"); ?> <html> <head><title>BOOK LIST</title></head> <body> <? $dom = xmldocfile ("http://localhost/Inventory.xml"); // читаем XML-файл и создаем объект DOM-дерево $root = $dom->root(); // получаем корень дерева print "<font color='red'><h3>BOOK LIST</h3></font>"; print "<ol>"; $arr=$root->children(); // получаем всех потомков корня for($i=0; $i<sizeof($arr); $i++) // и перебираем их в цикле { if ($arr[$i]->tagname=="BOOK") // действия только для тэга <BOOK> { $arr2=$arr[$i]->children(); // получаем всех потомков текущего узла дерева for($j=0; $j<sizeof($arr2); $j++) { if ($arr2[$j]->tagname=="TITLE") // действия только для тэга <TITLE> { $arr3=$arr2[$j]->children(); // получаем всех потомков текущего узла дерева print "<li>"; print_r($arr3[0]->content); // печатаем содержимое первого потомка - это текст } 36 Технология XML и ее приложения } } } print "</ol>"; ?> </body></html> 37 О.В. Пинягина Глава 6. XML и Ajax Технология AJAX сегодня – одна из самых новых и модных тем в Интернет-программировании. Расшифровывается эта аббревиатура как Asynchronous Javascript and XML. Коротко говоря, эта технология позволяет обращаться к удаленному источнику данных в фоновом режиме, без перезагрузки страницы. Это бывает полезно при необходимости динамического обновления части web-страницы. Обращение происходит посредством объектов XMLHTTPRequest или XMLHTTP. Клиентский сценарий обычно пишут на JavaScript (или VBScript). Следить за кем-то – это так нудно! Типичным примером применения технологии AJAX являются такие приложения, в которых нужно в онлайн-режиме отслеживать состояния движущихся объектов – например, автобусов на маршруте, животного с мобильным маячком на ошейнике (или даже осужденного человека с браслетом на руке). Предположим, например, что некоторый серверный сценарий (php или aspx или jsp – неважно) возвращает XML-документ следующего вида, содержащий информацию о перемещении нашего объекта относительно предыдущего момента времени: <?xml version="1.0" encoding="windows-1251" ?> - <state> <x>1</x> <y>-1</y> </state> 38 Технология XML и ее приложения Нам требуется автоматически обращаться из браузера к этому сценарию с некоторой периодичностью (например, раз в минуту или в секунду) и обновлять содержимое HTML-страницы. Как это можно сделать, показано в следующем документе: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>Следить за кем-то - это так нудно!</title> <script src="spy.js"></script> </head> <body bgcolor="#ddccff" > <div id=object style="position:absolute; top:50; left: 50"><img src="dacat.gif"></div> Состояние: <div id=comment style="background-color:#aaaaff; width:200"></div> </body> </html> 39 О.В. Пинягина В документе мы разместили два объекта <div> – контейнеры для картинки и для текста. Сценарий Javascript вынесен в отдельный файл. В этом файле мы объявляем необходимые переменные, в том числе для кодов возврата: var var var var var var var var req=null; comment=null; object=null; READY_STATE_UNINITIALIZED=0; READY_STATE_LOADING=1; READY_STATE_LOADED=2; READY_STATE_INTERACTIVE=3; READY_STATE_COMPLETE=4; Следующая функция, прежде всего, создает объект для обмена данными с сервером. Для большинства браузеров это объект XMLHttpRequest, и именно его мы сначала пытаемся создать. Если это сделать не удается, то пытаемся создать объект Microsoft.XMLHTTP. Дальнейшая обработка происходит только в том случае, если какойлибо из объектов создан. Мы назначаем в качестве обработчика события onreadystatechange processReqChange, по методу GET (ответ от сервера получен) функцию открываем соединение с сервером функцией и отправляем запрос функцией open send. function loadXMLDoc(url) { if (window.XMLHttpRequest) { req = new XMLHttpRequest(); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); } if (req) { req.onreadystatechange = processReqChange; req.open("GET", url, true); req.send(null); } } Следующая функция периодически (раз в секунду?) проверяет состояние ответа от сервера. Как только это состояние принимает 40 Технология XML и ее приложения значение 4, это означает, что ответ получен, и мы можем его обрабатывать. Далее в переменные comment ссылки на ранее созданные контейнеры addComment, (в нашем и <div> object мы записываем и вызываем функцию в которую передается информация, полученная от сервера случае – это содержимое XML-документа в виде иерархического объекта). function processReqChange(){ var ready=req.readyState; var data=null; if (ready==READY_STATE_COMPLETE){ data=req.responseXML; comment=document.getElementById('comment'); object=document.getElementById('object'); addComment(data); } } Следующая функция отыскивает в XML-объекте узлы x и y function addComment(data){ if (object!=null){ var x=data.getElementsByTagName("x")[0]; var y=data.getElementsByTagName("y")[0]; if(x==null || y==null) return; извлекает из них числовые значения, которые представляют собой направления перемещения объекта: var x=x.firstChild.data; var y=y.firstChild.data; if(x==null || y==null) return; и в зависимости от типа браузера (в разных браузерах почему-то поразному называются свойства, отвечающие за координаты объектов) изменяет с шагом в 10 пикселов координаты картинки, а также печатает эти координаты на экран: if (navigator.appName=="Netscape") { 41 О.В. Пинягина object.style.left=parseInt(object.style.left)+10*x; comment.innerHTML+=" x="+object.style.left; object.style.top=parseInt(object.style.top)+10*y; comment.innerHTML+=" y="+object.style.top+"<br>"; } else { object.style.pixelLeft+=x*10; comment.innerHTML+=" x="+object.style.pixelLeft; object.style.pixelTop+=y*10; comment.innerHTML+=" y="+object.style.pixelTop+"<br>"; } } Перед выходом из данной функции loadXMLDoc назначается вызов функции через 1000 миллисекунд: setTimeout("loadXMLDoc('spy.phtml')", 1000); } А эти действия выполняются при загрузке документа: с задержкой в 1 секунду назначается первый вызов функции loadXMLDoc, в которую передается имя загружаемого файла, а также выдается информация о названии используемого браузера. setTimeout("loadXMLDoc('spy.phtml')", 1000); alert("Вы используете браузер: "+navigator.appName+"."); Организация RSS-канала клиентскими средствами Рассмотрим публикацию RSS-новостей с помощью технологии Ajax. Ниже приведен код HTML-страницы с соответствующим JavaScript-сценарием и результаты их работы. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <title>RSS</title> 42 Технология XML и ее приложения <meta HTTP-EQUIV="Content-Type" Content="text-html; charset=windows-1251"> <script type='text/javascript'> var var var var var var var req=null; console=null; READY_STATE_UNINITIALIZED=0; READY_STATE_LOADING=1; READY_STATE_LOADED=2; READY_STATE_INTERACTIVE=3; READY_STATE_COMPLETE=4; function loadXMLDoc(url) { if (window.XMLHttpRequest) { req = new XMLHttpRequest(); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); } if (req) { req.onreadystatechange = processReqChange; req.open("GET", url, true); req.send(null); } } function processReqChange(){ var ready=req.readyState; var data=null; if (ready==READY_STATE_COMPLETE){ data=req.responseXML; console=document.getElementById('console'); toConsole(data); } } function toConsole(data){ if (console!=null){ var str=""; var root=data.getElementsByTagName("channel")[0]; var n=root.childNodes.length; for(var i=0; i<n; i++) { if(root.childNodes[i].nodeName=="item") { var node=root.childNodes[i]; for(var j=0; j<node.childNodes.length; j++) { if(node.childNodes[j].nodeName=="title") str+="<br><big>"+ 43 О.В. Пинягина node.childNodes[j].firstChild.data+"</big> "; if(node.childNodes[j].nodeName=="enclosure") str+=" <img src='"+ node.childNodes[j].attributes[0].value+"'> "; if(node.childNodes[j].nodeName=="description") str+=node.childNodes[j].firstChild.data; } str+="<hr>"; } } console.innerHTML=str; } } </script> </head> <body bgcolor=#f3a5c7 onload=loadXMLDoc("http://informer.gismeteo.ru/rss/27595.xml ")> <div id='console'></div> </body> </html> Рассмотрим подробно JavaScript-сценарий. документа (событие onLoad) вызывается функция которую передается имя загружаемого RSS-файла "http://informer.gismeteo.ru/rss/27595.xml". 44 При загрузке loadXMLDoc, в Технология XML и ее приложения function loadXMLDoc(url) { if (window.XMLHttpRequest) { req = new XMLHttpRequest(); } else if (window.ActiveXObject) { req = new ActiveXObject("Microsoft.XMLHTTP"); } if (req) { req.onreadystatechange = processReqChange; req.open("GET", url, true); req.send(null); } } Эта функция, прежде всего, создает объект для обмена данными с сервером. Для большинства браузеров это объект XMLHttpRequest, и именно его мы сначала пытаемся создать. Если это сделать не удается, то пытаемся создать объект Microsoft.XMLHTTP. Дальнейшая обработка происходит только в том случае, если какой-либо из объектов создан. Мы назначаем в качестве обработчика события (ответ от сервера получен) функцию соединение с сервером функцией запрос функцией open onreadystatechange processReqChange, по методу GET открываем и отправляем send. Рассмотрим функцию processReqChange: function processReqChange(){ var ready=req.readyState; var data=null; if (ready==READY_STATE_COMPLETE){ data=req.responseXML; console=document.getElementById('console'); toConsole(data); } } Эта функция периодически (раз в секунду?) проверяет состояние ответа от сервера. Как только это состояние принимает значение 4, это означает, что ответ получен, и мы можем его обрабатывать. Далее вызывается функция toConsole, в которую передается информация, 45 О.В. Пинягина полученная от сервера (в нашем случае – содержимое XML-файла в виде иерархического объекта). С этим объектом мы можем, в частности, выполнять следующие действия: - методом getElementsByTagName получить узел дерева по его имени и номеру (среди одноименных узлов); - получить ссылку на все дочерние узлы некоторого узла через свойство childNodes, представляющее собой массив объектов; - получить размер массива через свойство length; - получить имя узла (имя XML-тэга) через свойство nodeName; - получить содержимое узла (текст внутри тэга-контейнера) через свойство firstChild.data; - получить массив атрибутов тэга через свойство attributes; - получить значение i-го атрибута через свойство attributes[i].value. Таким образом, в функции toConsole мы получаем ссылку на узел, соответствующий тэгу <channel>: var root=data.getElementsByTagName("channel")[0]; далее получаем размер массива дочерних узлов var n=root.childNodes.length; и последовательно, в цикле перебираем их друг за другом. Для узлов, соответствующих тэгу <item>, выбираем содержимое тэгов <description>, url а из тэга <enclosure> <title> и выбираем значение атрибута и формируем из всей этой информации символьную строку, добавляя, по необходимости, HTML-тэги. Наконец, присваиваем полученный HTML-код свойству innerHTML объекта console. 46 Технология XML и ее приложения Этот сценарий успешно работает в браузере Internet Explorer. В других браузерах возникает проблема, заключающаяся в запрете доступа к файлам с чужих серверов. Так, например, если мы запускаем страницу с сервера http://kek.ksu.ru, мы не сможем через Ajax загрузить прогноз погоды с сервера http://informer.gismeteo.ru. Вообще говоря, Ajax все-таки в большей степени предназначен для работы в пределах одного и того же сервера. Более подробно о технологии Ajax заинтересованный читатель может узнать, например, из книг [4,5]. 47 О.В. Пинягина Глава 7. XML и SQL server Разработчики SQL server, разумеется, не обошли вниманием модную и удобную в применении технологию XML. По этому поводу уже написаны толстые книги, например, [6]. Рассмотрим несколько направлений этой технологии. Загрузка XML-данных посредством OPENXML Одно из направлений технологии XML в SQL server – это OPENXML. OPENXML представляет собой расширение SQL server для Transact SQL и позволяет создавать из XML-потока данных временные результирующие множества, подобные таблицам. В следующем примере мы напишем хранимую процедуру, которая получает в качестве аргумента XML-поток и выполняет добавление строк в таблицу базы данных. Пусть имеется следующая таблица (меню ресторана) create table menu ( kod varchar(9) NOT NULL, data datetime NOT NULL default getdate(), name varchar(50) NOT NULL, price numeric(6,2) NOT NULL default 0, primary key (kod, data)); На входе хранимая процедура будет получать XML-документ следующей структуры (&quot; означает двойные кавычки): <?xml version="1.0" encoding="windows-1251" ?> <Menu> <Course Name="Кофе &quot;Мокко&quot;" Price="45" Kod="000000007" /> <Course Name="Кофе &quot;Эспрессо&quot;" Price="55" Kod="000000008" /> <Course Name="Лимонад" Price="30" Kod="000000006" /> <Course Name="Кефир" Price="5" Kod="000000014" /> <Course Name="Пицца Маргарита" Price="120" Kod="000000009" /> <Course Name="Салат Мимоза" Price="60" Kod="000000010" /> 48 Технология XML и ее приложения <Course Name="Овощной салат" Price="35" Kod="000000011" /> <Course Name="Хлеб" Price="1" Kod="000000012" /> </Menu> Сам код хранимой процедуры выглядит следующим образом: CREATE PROCEDURE InsertMenuFromXML @sXML TEXT -- текст документа AS DECLARE @iDoc INT -- дескриптор результирующего набора -- создаем результирующий набор из xml-документа EXEC sp_XML_preparedocument @iDoc OUTPUT,@sXML -- возможно, возникла ошибка IF @@Error<>0 BEGIN RETURN END BEGIN TRANSACTION -- стартуем транзакцию -- собственно вставка данных из XML-потока INSERT INTO Menu(Kod,Name,Price) SELECT Kod,Name,Price FROM OPENXML (@iDoc,'/Menu/Course',1) WITH (Kod VARCHAR(9), Name VARCHAR(50), Price numeric(6,2)) -- возможно, возникла ошибка IF @@Error<>0 BEGIN EXEC sp_XML_removedocument @iDoc -- удаляем результирующий набор ROLLBACK TRANSACTION -- отменяем транзакцию! RETURN END EXEC sp_XML_removedocument @iDoc -- удаляем результирующий набор COMMIT TRANSACTION -- фиксируем транзакцию GO В этом примере дополнительных пояснений требуют служебные хранимые процедуры и формат команды INSERT. 49 О.В. Пинягина Служебная процедура sp_XML_preparedocument создает в оперативной памяти результирующее множество из XML-потока. Ее первый параметр – дескриптор результирующего множества, второй параметр – поток XML-данных. В конце программы вызывается процедура sp_XML_removedocument, которая удаляет из памяти результирующее множество. Команда INSERT … FROM OPENXML копирует данные из результирующего множества и добавляет их в указанную таблицу. В этой команде секция FROM OPENXML (@iDoc,'/Menu/Course',1) содержит следующие элементы: @iDoc – дескриптор результирующего набора, из которого читаются данные; ‘/Menu/Course’ – полное имя тэга (от корня документа), из которого читаются данные; 1 – значение аргумента, показывающее, что данные для добавления берутся из атрибутов этого тэга (альтернативное значение 2 указывает на то, что данные берутся из вложенных тэгов данного тэга). Секция WITH содержит описание типов добавляемых данных (см. соответствущий синтаксис в команде CREATE TABLE). После выполнения данной процедуры в таблицу menu будет добавлено 8 строк из XML-документа с информацией о блюдах (дата в этих строках заполняется по умолчанию). Кстати, для просмотра сегодняшнего меню удобно использовать следующее представление: CREATE VIEW todayMenu as SELECT * FROM menu WHERE DATEDIFF(dd,data,GETDATE())=0 50 Технология XML и ее приложения Выгрузка XML-данных с помощью директивы FOR XML С помощью команды SELECT … FOR XML очень легко выгрузить любые данные из таблиц и создать XML-документ. Будем использовать в примерах базу данных Контора «Рога и копыта» из учебника по базам данных. Примеры основаны на следующих таблицах: Таблица "Фирмы" CREATE TABLE k_firm (firm_num firm_name firm_addr firm_phone ) NUMERIC(6) IDENTITY PRIMARY KEY, VARCHAR(100) NOT NULL, VARCHAR(100), NUMERIC(7) Таблица "Договоры" CREATE TABLE k_contract (contract_num NUMERIC(6) IDENTITY PRIMARY KEY, contract_date DATETIME DEFAULT GETDATE(), contract_type CHAR(1) CHECK (contract_type IN ('A','B','C')), firm_num NUMERIC(6) NOT NULL, CONSTRAINT fk_contract_firm_num FOREIGN KEY (firm_num) REFERENCES k_firm (firm_num) ) Таблица "Счета" CREATE TABLE k_bill (bill_num NUMERIC(6) IDENTITY PRIMARY KEY, bill_date DATETIME DEFAULT GETDATE(), bill_term DATETIME DEFAULT GETDATE()+30, bill_peni NUMERIC(6) DEFAULT 0, contract_num NUMERIC(6), bill_sum NUMERIC(6) DEFAULT 0 NOT NULL CONSTRAINT fk_bill_contract_num FOREIGN KEY (contract_num) REFERENCES k_contract (contract_num), CONSTRAINT ch_bill_date CHECK (bill_term-bill_date<91) ) Таблица "Платежи" CREATE TABLE k_payment (payment_num NUMERIC(2) DEFAULT 0, bill_num NUMERIC(6), payment_date DATETIME DEFAULT GETDATE(), 51 О.В. Пинягина payment_sum NUMERIC(9,2), CONSTRAINT pk_payment_num PRIMARY KEY (payment_num, bill_num), CONSTRAINT fk_payment_bill_num FOREIGN KEY (bill_num) REFERENCES k_bill (bill_num) ) Таблица "Товары/услуги" (или "Прайс-лист") CREATE TABLE k_price (price_num NUMERIC(6) IDENTITY PRIMARY KEY, price_name VARCHAR(100) NOT NULL, price_sum NUMERIC(9,2), type_num NUMERIC(6) ) Простейший вариант команды SELECT * FROM k_price FOR XML AUTO Дает следующий результат: <k_price price_num="1" price_name="Материализация духов" price_sum="1000.00" type_num="2" /> <k_price price_num="2" price_name="Раздача слонов" price_sum="100.00" type_num="2" /> <k_price price_num="3" price_name="Слоновий бивень" price_sum="3000.00" type_num="1" /> <k_price price_num="4" price_name="Моржовый клык" price_sum="1093.50" type_num="1" /> <k_price price_num="5" price_name="Копыто Пегаса" price_sum="5000.00" type_num="1" /> Как видим, в этом документе нет корневого тэга – с точки зрения синтаксически корректного XML-документа это ошибка! Для появления корневого тэга добавим в команду ключевое слово ROOT. Кроме того, явно укажем список выводимых столбцов: SELECT price_num, price_name, price_sum FROM k_price FOR XML AUTO, ROOT <root> <k_price price_num="1" price_name="Материализация духов" price_sum="1000.00" /> <k_price price_num="2" price_name="Раздача слонов" price_sum="100.00" /> <k_price price_num="3" price_name="Слоновий бивень" price_sum="3000.00" /> 52 Технология XML и ее приложения <k_price price_num="4" price_name="Моржовый клык" price_sum="1093.50" /> <k_price price_num="5" price_name="Копыто Пегаса" price_sum="5000.00" /> </root> Так уже лучше. Но хотелось бы иметь возможность переименовать корневой тэг. Для этого после ключевого слова ROOT следует добавить новое имя корневого тэга в скобках и одинарных кавычках. Кроме того, можно переименовать и тэг <k_price> – для этого нужно просто задать псевдоним таблицы. SELECT price_num, price_name, price_sum FROM k_price good FOR XML AUTO, ROOT ('price-list') В итоге получим: <price-list> <good price_num="1" price_name="Материализация духов" price_sum="1000.00" /> <good price_num="2" price_name="Раздача слонов" price_sum="100.00" /> <good price_num="3" price_name="Слоновий бивень" price_sum="3000.00" /> <good price_num="4" price_name="Моржовый клык" price_sum="1093.50" /> <good price_num="5" price_name="Копыто Пегаса" price_sum="5000.00" /> </price-list> Во всех предыдущих примерах из каждой строки таблицы создавался отдельный элемент, а поля таблицы становились его атрибутами. Если в команду SELECT поместить ключевое слово ELEMENTS, то из каждого поля таблицы будут создаваться не атрибуты, а отдельные элементы: SELECT price_num, price_name, price_sum FROM k_price good FOR XML AUTO, ROOT ('price-list'), ELEMENTS <price-list> <good> <price_num>1</price_num> <price_name>Материализация духов</price_name> <price_sum>1000.00</price_sum> </good> <good> 53 О.В. Пинягина <price_num>2</price_num> <price_name>Раздача слонов</price_name> <price_sum>100.00</price_sum> </good> <good> <price_num>3</price_num> <price_name>Слоновий бивень</price_name> <price_sum>3000.00</price_sum> </good> <good> <price_num>4</price_num> <price_name>Моржовый клык</price_name> <price_sum>1093.50</price_sum> </good> <good> <price_num>5</price_num> <price_name>Копыто Пегаса</price_name> <price_sum>5000.00</price_sum> </good> </price-list> Теперь рассмотрим примеры выборки из нескольких таблиц. Пусть, например, мы хотим получить документ с информацией о фирмах и заключенных ими договорах: SELECT Фирма.firm_num, RTRIM(firm_name) AS firm_name, RTRIM(firm_addr) AS firm_addr, Договор.contract_num, contract_date FROM k_firm Фирма JOIN k_contract Договор ON Фирма.firm_num=Договор.firm_num ORDER BY Фирма.firm_num FOR XML AUTO, ROOT ('Фирмы') В этом запросе используются две таблицы: Фирмы и Договоры. Поскольку таблица Фирма является родительской таблицей для таблицы Договоры, было бы удобно, чтобы XML-элементы Договоры были вложены в соответствующие им XML-элементы Фирмы. Для этого следует в списке столбцов выборки указывать сначала столбцы родительской таблицы, а затем столбцы дочерней. Кроме того, нужно упорядочить строки по номеру фирмы, иначе для одной и той же фирмы (если у нее есть несколько договоров) могут появиться несколько XML-элементов. Функция RTRIM удаляет лишние правые пробелы в символьной строке. 54 Технология XML и ее приложения <Фирмы> <Фирма firm_num="1" firm_name="Альфа" firm_addr="Москва"> <Договор contract_num="1" contract_date="2011-11-01T00:00:00" /> <Договор contract_num="2" contract_date="2011-10-01T00:00:00" /> <Договор contract_num="3" contract_date="2011-09-01T00:00:00" /> <Договор contract_num="8" contract_date="2012-12-12T00:00:00" /> </Фирма> <Фирма firm_num="2" firm_name="Бета" firm_addr="Казань"> <Договор contract_num="4" contract_date="2011-11-15T00:00:00" /> <Договор contract_num="5" contract_date="2011-08-01T00:00:00" /> </Фирма> <Фирма firm_num="3" firm_name="Гамма" firm_addr="Москва"> <Договор contract_num="6" contract_date="2011-07-15T00:00:00" /> </Фирма> <Фирма firm_num="4" firm_name="Дельта" firm_addr="Москва"> <Договор contract_num="7" contract_date="2011-11-12T00:00:00" /> </Фирма> <Фирма firm_num="5" firm_name="Омега" firm_addr="Москва"> <Договор contract_num="10" contract_date="2012-12-13T00:00:00" /> </Фирма> </Фирмы> В следующем примере рассматривается выборка из четырех взаимосвязанных таблиц: Фирмы, Договоры, Счета и Платежи. Кроме того, изменен стиль даты. Вызов функции CONVERT(CHAR(10),contract_date, 104) преобразует дату договора в символьную строку, используя немецкий стиль даты ДД.ММ.ГГГГ. SELECT k_firm.firm_num, RTRIM(firm_name) AS firm_name, RTRIM(firm_addr) AS firm_addr, k_contract.contract_num, CONVERT(CHAR(10),contract_date, 104) AS contract_date, k_bill.bill_num, CONVERT(CHAR(10),bill_date,104) AS bill_date, bill_sum, payment_num, CONVERT(CHAR(10),payment_date, 104) AS payment_date, payment_sum FROM k_firm JOIN k_contract ON k_firm.firm_num=k_contract.firm_num JOIN k_bill ON k_contract.contract_num=k_bill.bill_num 55 О.В. Пинягина JOIN k_payment ON k_bill.bill_num=k_payment.bill_num ORDER BY k_firm.firm_num FOR XML AUTO, ROOT ('k_firms') Получим результат: <k_firms> <k_firm firm_num="1" firm_name="Альфа" firm_addr="Москва"> <k_contract contract_num="1" contract_date="01.11.2011"> <k_bill bill_num="1" bill_date="12.11.2011" bill_sum="1000"> <k_payment payment_num="1" payment_date="01.12.2011" payment_sum="1000.00" /> </k_bill> </k_contract> <k_contract contract_num="2" contract_date="01.10.2011"> <k_bill bill_num="2" bill_date="12.12.2011" bill_sum="2000"> <k_payment payment_num="1" payment_date="15.12.2011" payment_sum="1000.00" /> </k_bill> </k_contract> <k_contract contract_num="3" contract_date="01.09.2011"> <k_bill bill_num="3" bill_date="12.01.2012" bill_sum="2000"> <k_payment payment_num="1" payment_date="13.01.2012" payment_sum="1500.00" /> <k_payment payment_num="2" payment_date="15.01.2012" payment_sum="500.00" /> </k_bill> </k_contract> <k_contract contract_num="8" contract_date="12.12.2012"> <k_bill bill_num="8" bill_date="12.12.2011" bill_sum="1200"> <k_payment payment_num="1" payment_date="25.12.2011" payment_sum="1000.00" /> </k_bill> </k_contract> </k_firm> <k_firm firm_num="2" firm_name="Бета" firm_addr="Казань"> <k_contract contract_num="4" contract_date="15.11.2011"> <k_bill bill_num="4" bill_date="12.12.2011" bill_sum="6000"> <k_payment payment_num="1" payment_date="12.01.2012" payment_sum="1000.00" /> </k_bill> </k_contract> </k_firm> <k_firm firm_num="4" firm_name="Дельта" firm_addr="Москва"> <k_contract contract_num="7" contract_date="12.11.2011"> <k_bill bill_num="7" bill_date="12.12.2011" bill_sum="1500"> <k_payment payment_num="1" payment_date="05.01.2012" 56 Технология XML и ее приложения payment_sum="100.00" /> <k_payment payment_num="2" payment_date="12.01.2012" payment_sum="900.00" /> </k_bill> </k_contract> </k_firm> </k_firms> 57 О.В. Пинягина Глава 8. XML и «1С:Предприятие» Среда разработки «1С:Предприятие», как и положено уважающей себя среде разработки, имеет средства для работы с XML-документами. Эта технология используется, главным образом, для обмена данными. Импорт данных Пусть, например, у нас есть справочник Города с реквизитами Код, Наименование, Количество, Дата, и мы хотим заполнить этот справочник данными, полученными с некоторого web-сайта в XMLформате: <?xml version="1.0" encoding="utf-8" ?> - <towns> <town kod="000001" name="Казань" num="100" data="01.01.2001 0:00:00" /> <town kod="000002" name="Москва" num="200" data="02.02.2002 0:00:00" /> <town kod="000003" name="Пекин" num="300" data="03.03.2003 0:00:00" /> <town kod="000004" name="Дели" num="400" data="04.04.2004 0:00:00" /> <town kod="000005" name="Тегеран" num="500" data="05.05.2005 0:00:00" /> </towns> Для этого создадим где-нибудь на форме кнопку и назначим ей обработчик: Процедура Импорт(Элемент) //---- получение данных с web-сайта ------------Соединение = Новый HTTPСоединение("localhost:3774"); Соединение.Получить("/WebSite3/Default2.aspx", "towns.xml"); // ----- обработка XML-документа ----------------XML = Новый ЧтениеXML; XML.ОткрытьФайл("towns.xml"); Пока XML.Прочитать() цикл Если XML.Имя="town" и XML.ТипУзла=ТипУзлаXML.НачалоЭлемента Тогда НовыйГород = Справочники.Города.СоздатьЭлемент(); Пока XML.СледующийАтрибут() Цикл Если XML.Имя="name" Тогда НовыйГород.Наименование=XML.Значение; КонецЕсли; Если XML.Имя="kod" Тогда НовыйГород.Код=XML.Значение; КонецЕсли; Если XML.Имя="num" Тогда НовыйГород.количество=XML.Значение; 58 Технология XML и ее приложения КонецЕсли; Если XML.Имя="data" Тогда НовыйГород.Дата=XML.Значение; КонецЕсли; КонецЦикла; НовыйГород.Записать(); КонецЕсли; КонецЦикла; XML.Закрыть(); КонецПроцедуры Объект типа HTTPСоединение используется для установления соединения с web-сайтом, его метод Получить запрашивает выполнение на этом сайте некоторого сценария и записывает результаты в файл. Для чтения из XML-файла используется объект типа ЧтениеXML. Этот объект имеет следующие полезные свойства и методы: УстановитьCтроку (строкаXML) – устанавливает в качестве источника строку с текстом XML-документа ОткрытьФайл (имяXMLФайла) – устанавливает в качестве источника файл с заданным именем Прочитать () – читает текущий узел XML-документа, возвращает истину в случае успеха и ложь, если все узлы закончились. Используется в цикле перебора всех узлов XML-документа. СледующийАтрибут () – читает следующий атрибут текущего узла XML-документа, возвращает истину в случае успеха и ложь, если все узлы закончились. Используется в цикле перебора всех атрибутов узла XML-документа. А также Имя, Значение, ТипУзла и т.п. Экспорт данных Теперь рассмотрим пример создания XML-документа средствами 1С и отправку его для обработки на web-сайт. Пусть у нас есть справочник сотрудников, содержащий реквизиты Код (строка), 59 О.В. Пинягина Наименование (строка), Должность (строка) и Оклад (строка). Мы хотим создать из него такой XML-документ: <?xml version="1.0" encoding="windows-1251" ?> - <Сотрудники> <Сотрудник ФИО="Авоська" Должность="Оператор" Код="000000014" Оклад="20 000" /> <Сотрудник ФИО="Бублик" Должность="Развозчик" Код="000000001" Оклад="12 000" /> <Сотрудник ФИО="Винтик" Должность="Развозчик" Код="000000003" Оклад="15 000" /> <Сотрудник ФИО="Ворчун" Должность="Администратор" Код="000000016" Оклад="38 000" /> <Сотрудник ФИО="Кубышка" Должность="Гл.бухгалтер" Код="000000018" Оклад="45 000" /> <Сотрудник ФИО="Медуница" Должность="Повар" Код="000000010" Оклад="22 000" /> <Сотрудник ФИО="Молчун" Должность="Бухгалтер" Код="000000017" Оклад="32 000" /> <Сотрудник ФИО="Небоська" Должность="Оператор" Код="000000015" Оклад="20 000" /> <Сотрудник ФИО="Незнайка" Должность="Директор" Код="000000019" Оклад="48 000" /> <Сотрудник ФИО="Пончик" Должность="Повар" Код="000000009" Оклад="39 000" /> <Сотрудник ФИО="Растеряйка" Должность="Развозчик" Код="000000005" Оклад="8 000" /> <Сотрудник ФИО="Сиропчик Сахарин Сахариныч" Должность="Повар" Код="000000008" Оклад="30 000" /> <Сотрудник ФИО="Соломка" Должность="Повар" Код="000000011" Оклад="28 000" /> <Сотрудник ФИО="Стекляшкин" Должность="Упаковщик" Код="000000012" Оклад="11 000" /> <Сотрудник ФИО="Торопыжка" Должность="Развозчик" Код="000000004" Оклад="15 000" /> <Сотрудник ФИО="Тюбик" Должность="Упаковщик" Код="000000013" Оклад="11 000" /> <Сотрудник ФИО="Шпунтик" Должность="Развозчик" Код="000000002" Оклад="14 000" /> </Сотрудники> и отправить его на web-сайт для загрузки в базу данных. Создадим гденибудь на форме кнопку и назначим ей обработчик: Процедура ЭкспортНажатие(Элемент) XML= новый ЗаписьXML; XML.ОткрытьФайл("persons.xml","UTF-8"); XML.ЗаписатьОбъявлениеXML(); XML.ЗаписатьНачалоЭлемента("Сотрудники"); Выборка=Справочники.Сотрудники.Выбрать(); 60 Технология XML и ее приложения Пока Выборка.Следующий() цикл XML.ЗаписатьНачалоЭлемента("Сотрудник"); XML.ЗаписатьАтрибут("ФИО", Выборка.Наименование); XML.ЗаписатьАтрибут("Должность", ""+Выборка.Должность); XML.ЗаписатьАтрибут("Код", Выборка.Код); стр=Строка(Выборка.Оклад); стр=СтрЗаменить(стр,Символ(160),""); // уничтожаем разделитель разрядов XML.ЗаписатьАтрибут("Оклад", стр); XML.ЗаписатьКонецЭлемента(); КонецЦикла; XML.ЗаписатьКонецЭлемента(); XML.Закрыть(); Соединение = Новый HTTPСоединение("localhost:3774"); Соединение.ОтправитьДляОбработки("persons.xml","/WebSite3/Default3.aspx", "response.txt"); // --------выведем результат в окно сообщений -------Результат = Новый ТекстовыйДокумент(); Результат.Прочитать("response.txt", "UTF-8"); Сообщить(Результат.ПолучитьТекст()); КонецПроцедуры Метод ОтправитьДляОбработки объекта HTTPСоединение содержит три параметра: имя отправляемого файла, имя вызываемого сценария, имя файла результата. Работа с web-сервисами Web-сервисы представляют собой очень удобную технологию удаленного доступа к данным и программам. Web-сервис можно представить себе как некоторый объект, который имеет свойства и методы и расположен по некоторому Internet-адресу. В некотором смысле это развитие COM-технологий в Internet-программировании. Попробуем выполнить задачи предыдущих параграфов, используя web-сервисы. 61 О.В. Пинягина Пример 1 – экспорт данных. Пусть, например, у нас имеется web-сервис c именем Service. Он содержит единственный метод PersonXML, который получает в качестве параметра XML-документ – список сотрудников и добавляет этих сотрудников в базу данных на серверной стороне. Метод возвращает символьную строку: «ОК» или сообщение об ошибке. Создадим в конфигурации в группе «Общие» новый объект WSссылка, зададим URL импортируемого WSDL (т.е., формальное описание объекта). При разработке web-сервиса средствами ASP.NET, это ссылка примерно такого вида: http://localhost:4426/WebSite4/Service.asmx?WSDL которую можно получить при тестировании web-сервиса из адресной строки браузера (запустите сервис, щелкните по ссылке «Service description», скопируйте адресную строку). Пусть так же, как и в предыдущем параграфе, мы создали документ persons.xml, который содержит информацию о сотрудниках. Теперь в тексте модуля можно обращаться к данному webсервису: // читаем даные из XML-файла в текстовом формате Файл = Новый ТекстовыйДокумент(); Файл.Прочитать("persons.xml"); textXML = Файл.ПолучитьТекст(); // вызываем метод сервиса СервисXML = WSСсылки.WSСсылка1.СоздатьWSПрокси("http://tempuri.org/", "Service", "ServiceSoap" ); // сообщаем результат сообщить (СервисXML.PersonXML(textXML)); Параметры метода СоздатьWSПрокси: - URI пространства имен web-сервиса, - имя web-сервиса, - порт web-сервиса. Получить их можно из описания WS-ссылки, которое показано на картинке: 62 Технология XML и ее приложения Пример 2 – экспорт данных. Пусть, например, у нас имеется web-сервис c именем Service2. Он содержит единственный метод TownXML, который получает из базы данных сведения о городах, формирует из этих данных XML-документ и возвращает его (или возвращает сообщение об ошибке). Создадим в конфигурации в группе «Общие» новый объект WSссылка, зададим URL импортируемого WSDL (т.е., формальное описание объекта). При разработке web-сервиса средствами ASP.NET, это ссылка примерно такого вида: http://localhost:4426/WebSite4/Service2.asmx?WSDL которую можно получить при тестировании web-сервиса из адресной строки браузера (запустите сервис, щелкните по ссылке «Service description», скопируйте адресную строку). Теперь в тексте модуля можно обращаться к данному webсервису: СервисXML = WSСсылки.WSСсылка2.СоздатьWSПрокси ("http://tempuri.org/", "Service2", "Service2Soap" ); результат = СервисXML.TownXML(""); 63 О.В. Пинягина XML = Новый ЧтениеXML; XML.УстановитьСтроку(результат); Параметры метода СоздатьWSПрокси: URI пространства имен webсервиса, имя web-сервиса, порт web-сервиса. Примечание: обратите внимание, что данный метод содержит 1 параметр – пустую строку, хотя по логике вещей никакие параметры данному методу вообще не нужны. Дело в том, что при обращении к методу Web-сервиса, не содержащему никаких параметров, 1C:Предприятие выдает ошибку (глюк?) 64 Технология XML и ее приложения Глава 9. XML и .NET Пространства System.Xml содержат типы для обработки языка XML. Дочерние пространства имен поддерживают сериализацию XMLдокументов или потоков, схемы XSD, XQuery 1.0 и XPath 2.0, а также интерфейс LINQ to XML, который является хранимым в памяти интерфейсом программирования XML, позволяющим удобным образом изменять XML-документы. Классы XMLNode, XMLDocument основных классов из библиотеки Рассмотрим несколько System.Xml. Класс XMLNode – представляет отдельный узел в XMLдокументе. Является базовым классом для XMLDocument. Свойства Attributes ChildNodes FirstChild HasChildNodes InnerText InnerXml LastChild OuterXml Возвращает объект класса XmlAttributeCollection, содержащий атрибуты данного узла. Возвращает все дочерние узлы данного узла. Возвращает первый дочерний узел данного узла. Возвращает значение, показывающее наличие дочерних узлов у текущего узла. Возвращает или задает связанные значения узла, а также все его дочерние узлы. При установке этого свойства все дочерние элементы узла заменяются разобранным содержимым указанной строки. Для листовых узлов InnerText возвращает то же содержимое, что и свойство Value. Возвращает или задает разметку, отражающую только дочерние узлы данного узла. Возвращает последний дочерний узел данного узла. Возвращает разметку, предоставляющую 65 О.В. Пинягина данный узел и все его дочерние узлы. Возвращает объект класса XmlDocument, которому принадлежит данный узел. Возвращает или задает значение узела. OwnerDocument Value Методы AppendChild InsertAfter InsertBefore RemoveAll RemoveChild ReplaceChild Добавляет указанный узел в конец списка дочерних узов данного узела. Вставляет заданный узел сразу после указанного узла. Вставляет заданный узел сразу перед указанным узлом. Удаляет все дочерние узлы и (или) атрибуты текущего узла. Удаляет указанный дочерний узел. Заменяет дочерний узел oldChild на узел newChild. Класс XMLDocument кроме унаследованных от XMLNоde, содержит следующие полезные свойства и методы. Свойства DocumentElement Возвращает корневой XmlElement для документа. PreserveWhitespace Возвращает или задает значение, определяющее, будут ли сохранены пробелы в содержимом элемента. Возвращает или задает объект XmlSchemaSet, Schemas связанный с объектом XmlDocument. Методы CreateAttribute(String) Создает объект XmlAttribute с указанным свойством Name. Создает элемент с указанным именем. CreateElement(String) CreateNode(String, String, Создает XmlNode с помощью указанного типа узла, а также свойств Name и String) NamespaceURI. Создает XmlText с указанным текстом. CreateTextNode Возвращает элемент XmlElement с GetElementById 66 Технология XML и ее приложения GetElementsByTagName(S tring) Load(Stream) Load(String) Load(TextReader) Load(XmlReader) LoadXml Save(Stream) Save(String) Save(TextWriter) Save(XmlWriter) Validate(ValidationEventH andler) WriteContentTo WriteTo указанным идентификатором. Возвращает XmlNodeList, содержащий список всех элементов-потомков, соответствующих указанному свойству Name. Загружает XML-документ из указанного потока. Загружает XML-документ из указанного URL-адреса. Загружает XML-документ из указанного TextReader. Загружает XML-документ из указанного XmlReader. Загружает XML-документ из указанной строки. Сохраняет XML-документ в указанном потоке. Сохраняет XML-документ в указанном файле. Сохраняет XML-документ в указанном TextWriter. Сохраняет XML-документ в указанном XmlWriter. Проверяет XmlDocument по схемам языка XSD, содержащимся в свойстве Schemas. Сохраняет все дочерние узлы XmlDocument в заданном классе XmlWriter. Сохраняет узел XmlDocument в заданном XmlWriter. 67 О.В. Пинягина Рассмотрим пример, в котором данные загружаются из XMLфайла в объект XMLDocument, а затем переносятся в визуальный объект типа DataGridView. public partial class Form1 : Form { XmlDocument xmlDoc; public Form1() { InitializeComponent(); Создаем 2 столбца в объекте DataGridView. dataGridView1.Columns.Add("name", "Название"); dataGridView1.Columns.Add("price", "Цена"); } private void button1_Click(object sender, EventArgs e) { Выбираем XML-файл: OpenFileDialog file = new OpenFileDialog(); file.ShowDialog(); try { xmlDoc = new XmlDocument(); Загружаем данные из файла в объект XMLDocument: xmlDoc.Load(file.FileName); Получаем список узлов с именем “Course”. XmlNodeList nodeList = xmlDoc.GetElementsByTagName("Course"); foreach (XmlNode node in nodeList) 68 Технология XML и ее приложения { Перебираем все узлы из списка и копируем информацию о каждом блюде в таблицу на экране. dataGridView1.Rows.Add (node.Attributes["Name"].Value, node.Attributes["Price"].Value); } } catch (Exception ex) { MessageBox.Show(ex.Message); } } } Сериализация Сериализацией (serialization) обычно называют процесс преобразования объекта в линейную последовательность байтов. Обратное действие, при котором из потока байтов объект восстанавливается в исходном виде, называется десериализацией (deserialization). Сериализация имеет следующие «плюсы»: Доступность. Объект можно сохранить в файле и обращаться к нему в любое время. Время жизни. Сохранение состояния объекта в файл продлевает ему жизнь. Обычно объекты просто хранятся в оперативной памяти компьютера и автоматически уничтожаются по окончании работы программы. Использование в сетевых приложениях. Объекты сложной формы преобразуются в формат, который легко передается через сеть. Надежность. Сохраненный объект можно воссоздать в его первоначальной форме. Сериализация и десериализация в формат XML Для сериализации объектов часто используется формат XML. Этот формат удобен как для автоматической передачи информации между программами, так и для чтения человеком. Сериализованные объекты в 69 О.В. Пинягина виде текста можно переслать по сети или сохранить на диск для дальнейшего использования. Класс XmlSerializer содержится в пространстве имен System.Xml.Serialization. Для того чтобы объект некоторого класса можно было сериализовать с использованием класса XmlSerializer, нужно выполнить следующие требования: Класс, подлежащий сериализации, должен содержать используемый по умолчанию открытый конструктор без параметров. Это условие возникло потому, что при восстановлении объекта в процессе десериализации сначала объект создается конструктором по умолчанию, а затем из входного потока данных читаются открытые свойства. Если конструктор по умолчанию отсутствует, .NET Framework не будет знать, как создать объект. При сериализации сохраняются только открытые свойства, поддерживающие операции get и set, и открытые члены данных. Это объясняется тем, что процесс сериализации не может обращаться к закрытым и доступным только для чтения элементам данных. Предположим, у нас есть класс Message. public class Message { public string from; public string to; public string text; public int priority; public Message() {} public Message (string txt_from, string txt_to, string txt_text, int num_priority) { from = txt_from; to = txt_to; text = txt_text; priority=num_priority; } } Создадим объект этого класса и сериализуем его. . . . Message mes1 = new Message ("Юстас", "Алекс", "Вторник. Новостей нет.", 1); // создаем поток для записи 70 Технология XML и ее приложения StreamWriter writer = new StreamWriter("Message.xml"); // создаем сериализатор XmlSerializer serializer = new XmlSerializer(typeof(Message)); // и сериализуем объект serializer.Serialize(writer, mes1); // закрываем поток для записи writer.Close(); . . . Получим файл Message.xml со следующим содержимым: <?xml version="1.0" encoding="utf-8"?> <Message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <from>Юстас</from> <to>Алекс</to> <text>Вторник. Новостей нет.</text> <priority>1</priority> </Message> Теперь выполним обратное действие: . . . // создаем поток для чтения FileStream reader= new FileStream("Message.xml", FileMode.Open, FileAccess.Read); // создаем десериализатор XmlSerializer deserializer = new XmlSerializer(typeof(Message)); // и десериализуем объект Message mes2 = (Message)deserializer.Deserialize(reader); Console.Write("Сообщение от: "+mes2.from); Console.WriteLine(" к: " + mes2.to); Console.WriteLine("текст: " + mes2.text); Console.WriteLine("приоритет: " + mes2.priority); . . . Усложним структуру класса Message: public class Message { public Person from; public Person to; public String text; public int priority; public Message() {} public Message(Person person_from, Person person_to, string txt_text, int num_priority) { from = person_from; to = person_to; text = txt_text; priority=num_priority; 71 О.В. Пинягина } } public class Person { public string name; public string position; public Person() { } public Person(string txt_name, string txt_position) { name = txt_name; position = txt_position; } } Сериализованный объект будет выглядеть примерно следующим образом: <?xml version="1.0" encoding="utf-8"?> <Message xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> <from> <name>Юстас</name> <position>шпион</position> </from> <to> <name>Алекс</name> <position>разведчик</position> </to> <text>Вторник. Новостей нет.</text> <priority>1</priority> </Message> Сериализация с помощью объектов форматирования Для сериализации объектов более сложной структуры (например, содержащих вложенные объекты, в том числе и других классов) удобно применять так называемые объекты форматирования, или форматтеры. При использовании этой технологии каждый класс, который будет участвовать в сериализации, должен обладать атрибутом [Serializable]. Те элементы объекта, которые сериализовать не нужно, следует пометить атрибутом [NonSerialized]. // Классы Message и Person могут быть сериализованы [Serializable] public class Person 72 Технология XML и ее приложения { public string name; public string position; public Person(string txt_name, string txt_position) { name = txt_name; position = txt_position; } } [Serializable] public class Message { public Person from; public Person to; public String text; public int priority; [NonSerialized] public string color; public Message(Person person_from, Person person_to, string txt_text, int num_priority, string txt_color ) { from = person_from; to = person_to; text = txt_text; priority=num_priority; color = txt_color; } } Графы для отношений объектов Службы сериализации в .NET — это довольно сложные программные модули. С их помощью выполняются многие неочевидные действия: когда объект сериализуется в поток, информация обо всех других объектах, на которые он так или иначе ссылается, также должна сериализоваться. Например, когда сериализуется объект производного класса, ссылки на другие классы, которые есть в базовых классах для этого производного класса, также должны отслеживаться и сохраняться. 73 О.В. Пинягина Набор взаимосвязанных объектов, сериализованных в поток байтов, называется графом объектов (object graph). Графы позволяют фиксировать отношения объектов друг к другу, и они, вообще говоря, не соответствуют классическим моделям отношений классов в объектно-ориентированном программировании. Внутри объектного графа каждому из объектов присваивается уникальный номер, который используется только для служебных целей в графе и которому совершенно не обязательно должно что-то соответствовать в реальном мире. Далее записывается информация о соответствии имени класса этому номеру, информация обо всех отношениях этого класса с другими классами и отношениях других классов между собой. Выбираем объект Formatter Пространство имен System.Runtime.Serialization.Formatters включает в себя еще два пространства имен - *.Binary и *.Soap, каждому из которых соответствует один из двух классов Formatter. Класс ВinаryFormatter сериализует объектный граф в компактном потоке двоичного формата, а класс SoapFormatter представляет граф как текстовое сообщение протокола SOAP (Simple Object Access Protocol — это простой протокол доступа к объектам) в формате XML. 74 Технология XML и ее приложения Класс BinaryFormatter находится в базовой библиотеке mscorlib.dll, поэтому единственное, что нам потребуется для сериализации при помощи такого объекта — указать использование этого пространства имен: // Для сериализации объектов в двоичном формате using System.Runtime.Serialization.Formatters.Binary; Класс SoapFormatter находится в отдельной сборке, поэтому для сохранения объекта в формате SOAP нам потребуется добавить ссылку на сборку System.Runtime.Serializaton.Formatters.Soap.dll (в пункте Add Reference текущего проекта), а затем использовать аналогичную команду: // Для сериализации объектов в формате SOAP using System.Runtime.Serialization.Formatters.Soap; Сериализация в двоичном формате using System.Runtime.Serialization.Formatters.Binary; . . . Message mes1 = new Message( new Person("Юстас","шпион"), new Person("Алекс","разведчик"), "Вторник. Новостей нет.", 1, "red"); // Создаем поток для записи FileStream myStream = File.Create("Message.dat"); // Создаем форматтер BinaryFormatter myBinaryFormat = new BinaryFormatter(); // Помещаем объектный граф в поток в двоичном формате myBinaryFormat.Serialize(myStream, mes1); // Закрываем поток myStream.Close(); Сериализация и десериализация в формате SOAP using System.Runtime.Serialization.Formatters.Soap; . . . Message mes1 = new Message( new Person("Юстас","шпион"), new Person("Алекс","разведчик"), "Вторник. Новостей нет.", 1, "red"); // Создаем поток для записи FileStream myStream = File.Create("Message2.xml"); // Создаем форматтер 75 О.В. Пинягина SoapFormatter myXMLFormat = new SoapFormatter(); // Помещаем объектный граф в поток в SOAP формате myXMLFormat.Serialize(myStream, mes1); // Закрываем поток myStream.Close(); . . . // Восстанавливаем объект из файла SOAP myStream = File.OpenRead("Message2.xml"); Message mes2 = (Message)myXMLFormat.Deserialize(myStream); Console.Write("Сообщение от: " + mes2.from.name); Console.WriteLine(" к: " + mes2.to.name); Console.WriteLine("текст: " + mes2.text); Console.WriteLine("приоритет: " + mes2.priority); myStream.Close(); . . . В результате получим такой файл: <SOAP-ENV:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:clr="http://schemas.microsoft.com/soap/encoding/clr/1.0" SOAPENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"> <SOAP-ENV:Body> <a1:Message id="ref-1" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/ConsoleApplic ation3/ConsoleApplication3%2C%20Version%3D1.0.0.0%2C%20Culture%3 Dneutral%2C%20PublicKeyToken%3Dnull"> <from href="#ref-3"/> <to href="#ref-4"/> <text id="ref-5">Вторник. Новостей нет.</text> <priority>1</priority> </a1:Message> <a1:Person id="ref-3" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/ConsoleApplic ation3/ConsoleApplication3%2C%20Version%3D1.0.0.0%2C%20Culture%3 Dneutral%2C%20PublicKeyToken%3Dnull"> <name id="ref-6">Юстас</name> <position id="ref-7">шпион</position> </a1:Person> <a1:Person id="ref-4" xmlns:a1="http://schemas.microsoft.com/clr/nsassem/ConsoleApplic ation3/ConsoleApplication3%2C%20Version%3D1.0.0.0%2C%20Culture%3 Dneutral%2C%20PublicKeyToken%3Dnull"> <name id="ref-8">Алекс</name> <position id="ref-9">разведчик</position> </a1:Person> </SOAP-ENV:Body> </SOAP-ENV:Envelope> 76 Технология XML и ее приложения Глава 10. XML и ASP.NET Выгрузка и загрузка данных в формате XML через файлы (данный параграф в основном дублирует главу из пособия Разработка web-АРМ на ASP.NET) XML является исключительно удобной и гибкой технологией для обмена данными между приложениями. В ASP.NET есть много разнообразных объектов для работы с XML-данными. В нашем проекте мы рассмотрим только два простых примера. Загрузка данных из XML-файла в базу данных Пусть в отдел комплектования вместе с новыми книгами присылают XML-документ следующего вида: - <books> <book ISBN="5-8959-1091-9111" name_book="Microsoft ASP.NET 2.0 с примерами на C# 2005 для профессионалов" author="М. Мак-Дональд, М. Шпушта" price="500" pages="1408" year="2007" /> <book ISBN="3-91180-009-3111" name_book="Гибкая разработка вебприложений в среде Rails" author="Д. Томас, Д. Х. Хэнссон" price="400" pages="700" year="2008" /> ... </books> Таблица books имеет следующую структуру: Имя столбца Тип (размер) Дополнительно ISBN Nchar(20) Not null, первичный ключ Name_book Nchar(100) Not null Author Nchar(100) Not null Price Decimal(6,2) Not null Year Decimal(4,0) Not null Pages Int Not null Создадим сценарий, который автоматически загружает данные из этого документа в таблицу books. 77 О.В. Пинягина Добавим на страницу источник данных SQLDataSource, единственная цель которого – выполнять команду INSERT: INSERT INTO [books] ([ISBN], [name_book], [author], [price], [pages], [year]) VALUES (@ISBN, @name_book, @author, @price, @pages, @year) Поместим на страницу элемент управления FileUpload из секции Standard, кнопку «Загрузить» и метку с именем Message. Подключим необходимую библиотеку для работы с XML-классами: using System.Xml; Создадим обработчик для кнопки «Загрузить»: protected void Button1_Click(object sender, EventArgs e) { Если файл был загружен: if (this.FileUpload1.HasFile) { try { задаем путь к файлу на диске и сохраняем его. string Name="c:\\upload\\" + FileUpload1.FileName; FileUpload1.SaveAs(Name); На экран будет выдано сообщение: имя и размер загруженного файла: Message.Text = "Имя файла: " + FileUpload1.PostedFile.FileName + "<br>" + FileUpload1.PostedFile.ContentLength + " кб<br>"; 78 Технология XML и ее приложения Создаем объект для последовательного чтения из XML-файла (модель SAX) и читаем его в цикле: XmlTextReader XMLData = new XmlTextReader(Name); while (XMLData.Read()) Если текущий элемент – узел <book> if (XMLData.NodeType == XmlNodeType.Element) if (XMLData.Name == "book") { читаем его атрибуты: string string string string string string ISBN = XMLData.GetAttribute("ISBN"); name_book = XMLData.GetAttribute("name_book"); author = XMLData.GetAttribute("author"); pages = XMLData.GetAttribute("pages"); price = XMLData.GetAttribute("price"); year = XMLData.GetAttribute("year"); и записываем их в параметры запроса INSERT, затем выполняем запрос: SqlDataSource1.InsertParameters["ISBN"].DefaultValue = ISBN; SqlDataSource1.InsertParameters["name_book"].DefaultValue = name_book; SqlDataSource1.InsertParameters["author"].DefaultValue = author; SqlDataSource1.InsertParameters["pages"].DefaultValue = pages; SqlDataSource1.InsertParameters["price"].DefaultValue = price; SqlDataSource1.InsertParameters["year"].DefaultValue = year; SqlDataSource1.Insert(); } } Предусмотрим вывод ошибки, если возникло исключение: catch (Exception ex) { Message.Text = "Ошибка: " + ex.Message.ToString(); } } } Выгрузка данных в XML-файл Предположим, мы хотим выгрузить данные о читателе и его книгах в XML-файл следующего вида: <?xml version="1.0" encoding="utf-8" ?> - <formular> 79 О.В. Пинягина <reader id_reader="18" fio_reader="Петров Петр Петрович" passport="1213 456789" addr_reader="Казань, Ленина, 20-2" tel_reader="123-123-123" email_reader="[email protected]" datebird="11.11.1950 0:00:00" /> <book ISBN="5-8959-1091-9" id_item="1" date_get="21.11.2010 18:12:58" /> <book ISBN="978-5-91180-009-3" id_item="6" date_get="28.11.2010 18:26:08" /> ... </formular> На странице личной карточки читателя создадим новую кнопку с надписью «Формуляр в формате XML» и зададим для нее обработчик: protected void Button5_Click(object sender, EventArgs e) { Читаем данные из карточки читателя (объект DetailsView1): string string string string string string string id_reader = DetailsView1.Rows[0].Cells[1].Text; fio_reader = DetailsView1.Rows[1].Cells[1].Text; passport = DetailsView1.Rows[2].Cells[1].Text; datebird = DetailsView1.Rows[3].Cells[1].Text; addr_reader = DetailsView1.Rows[4].Cells[1].Text; tel_reader = DetailsView1.Rows[5].Cells[1].Text; email_reader = DetailsView1.Rows[6].Cells[1].Text; Создаем объект для записи XML-файла, имя файла – это номер читательского билета: XmlTextWriter XMLData = new XmlTextWriter("C:\\upload\\"+id_reader + ".xml", System.Text.Encoding.UTF8); Записываем информацию о читателе: XMLData.WriteStartDocument(); 80 Технология XML и ее приложения XMLData.WriteStartElement("formular"); XMLData.WriteStartElement("reader"); XMLData.WriteAttributeString("id_reader", id_reader); XMLData.WriteAttributeString("fio_reader", fio_reader); XMLData.WriteAttributeString("passport", passport); XMLData.WriteAttributeString("addr_reader", addr_reader); XMLData.WriteAttributeString("tel_reader", tel_reader); XMLData.WriteAttributeString("email_reader", email_reader); XMLData.WriteAttributeString("datebird", datebird); XMLData.WriteEndElement(); Создаем выборку для книг на руках у читателя: DataView GivenBooks = new DataView(); GivenBooks = (DataView)SqlDataSource3.Select(DataSourceSelectArguments.Empty) ; Перебираем строки выборки и записываем информацию о книгах в XML-документ: int i=0; for (i=0; i < GivenBooks.Count; i++) { XMLData.WriteStartElement("book"); XMLData.WriteAttributeString("ISBN", Convert.ToString(GivenBooks[i]["ISBN"])); XMLData.WriteAttributeString("id_item", Convert.ToString(GivenBooks[i]["id_item"])); XMLData.WriteAttributeString("date_get", Convert.ToString(GivenBooks[i]["date_get"])); XMLData.WriteEndElement(); } Закрываем тэги и файл: XMLData.WriteEndElement(); XMLData.WriteEndDocument(); XMLData.Close(); } Выгрузка и загрузка данных в формате XML в выходной поток /из входного потока Выгрузка данных Пусть, например, у нас есть таблица городов в SQL server: 81 О.В. Пинягина и мы хотим выгрузить из нее данные в формате XML прямо в выходной поток объекта Response. Для этого нужно создать пустую aspx-страницу, т.е., создать страницу типа WebForm и выкинуть из нее всё, кроме директивы Page . . .%> <%@ . Затем следует создать источник данных SQLDataSource и настроить в нем нужный SELECT. И, наконец, обработчик загрузки этой страницы должен выглядеть примерно так: protected void Page_Load(object sender, EventArgs e) { DataView towns = new DataView(); towns = (DataView)SqlDataSource1.Select(DataSourceSelectArguments.Empty) ; XmlTextWriter XMLData = new XmlTextWriter(Response.Output); XMLData.WriteStartDocument(); XMLData.WriteStartElement("towns"); int i=0; for (i = 0; i < towns.Count; i++) { XMLData.WriteStartElement("town"); XMLData.WriteAttributeString("kod", towns[i]["kod"].ToString()); XMLData.WriteAttributeString("name", towns[i]["name"].ToString()); XMLData.WriteAttributeString("num", towns[i]["num"].ToString()); XMLData.WriteAttributeString("data", towns[i]["data"].ToString()); XMLData.WriteEndElement(); } XMLData.WriteEndElement(); } 82 Технология XML и ее приложения Обратите внимание, что объект типа XmlTextWriter напрямую связывается с выходным потоком Response.Output. Поэтому результатом работы этого сценария будет следующая страница: <?xml version="1.0" encoding="utf-8" ?> - <towns> <town kod="000001" name="Казань" num="100" data="01.01.2001 0:00:00" /> <town kod="000002" name="Москва" num="200" data="02.02.2002 0:00:00" /> <town kod="000003" name="Пекин" num="300" data="03.03.2003 0:00:00" /> <town kod="000004" name="Дели" num="400" data="04.04.2004 0:00:00" /> <town kod="000005" name="Тегеран" num="500" data="05.05.2005 0:00:00" /> </towns> Вызывать этот сценарий можно как из браузера, так и из других приложений, например, из «1С:Предприятия». Загрузка данных Пусть, например, мы получаем из какого-то приложения следующий поток данных <?xml version="1.0" encoding="windows-1251" ?> - <Сотрудники> <Сотрудник ФИО="Авоська" Должность="Оператор" Код="000000014" Оклад="20 000" /> <Сотрудник ФИО="Бублик" Должность="Развозчик" Код="000000001" Оклад="12 000" /> <Сотрудник ФИО="Винтик" Должность="Развозчик" Код="000000003" Оклад="15 000" /> <Сотрудник ФИО="Ворчун" Должность="Администратор" Код="000000016" Оклад="38 000" /> <Сотрудник ФИО="Кубышка" Должность="Гл.бухгалтер" Код="000000018" Оклад="45 000" /> <Сотрудник ФИО="Медуница" Должность="Повар" Код="000000010" Оклад="22 000" /> <Сотрудник ФИО="Молчун" Должность="Бухгалтер" Код="000000017" Оклад="32 000" /> <Сотрудник ФИО="Небоська" Должность="Оператор" Код="000000015" Оклад="20 000" /> <Сотрудник ФИО="Незнайка" Должность="Директор" Код="000000019" Оклад="48 000" /> <Сотрудник ФИО="Пончик" Должность="Повар" Код="000000009" Оклад="39 000" /> <Сотрудник ФИО="Растеряйка" Должность="Развозчик" 83 О.В. Пинягина Код="000000005" Оклад="8 000" /> <Сотрудник ФИО="Сиропчик Сахарин Сахариныч" Должность="Повар" Код="000000008" Оклад="30 000" /> <Сотрудник ФИО="Соломка" Должность="Повар" Код="000000011" Оклад="28 000" /> <Сотрудник ФИО="Стекляшкин" Должность="Упаковщик" Код="000000012" Оклад="11 000" /> <Сотрудник ФИО="Торопыжка" Должность="Развозчик" Код="000000004" Оклад="15 000" /> <Сотрудник ФИО="Тюбик" Должность="Упаковщик" Код="000000013" Оклад="11 000" /> <Сотрудник ФИО="Шпунтик" Должность="Развозчик" Код="000000002" Оклад="14 000" /> </Сотрудники> и хотим перенести эти данные в таблицу Persons Для этого нужно создать пустую aspx-страницу, т.е., создать страницу типа WebForm и выкинуть из нее всё, кроме директивы <%@Page . . .%> . Затем следует создать источник данных SQLDataSource и настроить в нем нужный INSERT. И, наконец, обработчик загрузки этой страницы должен выглядеть примерно так: protected void Page_Load(object sender, EventArgs e) { try{ XmlTextReader XMLData = new XmlTextReader(Request.InputStream); while (XMLData.Read()) { if (XMLData.NodeType == XmlNodeType.Element) if (XMLData.Name == "Сотрудник") { string kod = XMLData.GetAttribute("Код"); string name = XMLData.GetAttribute("ФИО"); string salary = XMLData.GetAttribute("Оклад"); string place = XMLData.GetAttribute("Должность"); SqlDataSource1.InsertParameters["kod"]. DefaultValue = kod; 84 Технология XML и ее приложения SqlDataSource1.InsertParameters["name"]. DefaultValue = name; SqlDataSource1.InsertParameters["salary"]. DefaultValue = salary; SqlDataSource1.InsertParameters["place"]. DefaultValue = place; SqlDataSource1.Insert(); } } } catch (Exception ex) { Response.Write("Ошибка: " + ex.Message.ToString()); return; } Response.Write("ОK"); } Обратите внимание, что объект типа XmlTextReader напрямую связывается с входным потоком Request.InputStream. Выгрузка и загрузка данных в формате XML через webсервисы Web-сервисы представляют собой очень удобную технологию удаленного доступа к данным и программам. Web-сервис можно представить себе как некоторый объект, который имеет свойства и методы и расположен по некоторому Internet-адресу. В определенном смысле это развитие COM-технологий в Internet-программировании. Попробуем выполнить задачи предыдущих параграфов, используя web-сервисы. Загрузка данных Создадим web-сервис, который содержит метод PersonXML, принимающий в качестве параметра список сотрудников в формате XML-документа и добавляющий этих сотрудников в таблицу базы данных. Создадим новый Web-сайт, выберем для него тип ASP.NET Web Service. 85 О.В. Пинягина [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class Service : System.Web.Services.WebService { public Service () { //... } Создадим в этом классе метод PersonXML, который качестве параметра символьную строку. принимает в [WebMethod] public string PersonXML(string XML) { try { Поскольку у Web-сервиса нет визуального представления, источник данных приходится создавать программным образом, в том числе следует задать команду для добавления строки в таблицу сотрудников: SqlDataSource SqlDataSource1 = new SqlDataSource(); SqlDataSource1.ConnectionString = "Data Source=.\\SQLEXPRESS; AttachDbFilename=|DataDirectory|\\database.mdf; Integrated Security=True;User Instance=True"; SqlDataSource1.InsertCommand = "INSERT INTO persons(kod, name, salary, place) VALUES (@kod,@name,@salary,@place)"; SqlDataSource1.InsertParameters.Add("kod", ""); SqlDataSource1.InsertParameters.Add("name", ""); SqlDataSource1.InsertParameters.Add("salary", ""); SqlDataSource1.InsertParameters.Add("place", ""); В остальном код процедуры не использованием ASP.NET-страниц. отличается от варианта MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(XML)); XmlTextReader XMLData = new XmlTextReader(ms); while (XMLData.Read()) { if (XMLData.NodeType == XmlNodeType.Element) if (XMLData.Name == "Сотрудник") { string kod = XMLData.GetAttribute("Код"); string name = XMLData.GetAttribute("ФИО"); 86 с Технология XML и ее приложения string salary = XMLData.GetAttribute("Оклад"); string place = XMLData.GetAttribute("Должность"); SqlDataSource1.InsertParameters["kod"]. DefaultValue = kod; SqlDataSource1.InsertParameters["name"]. DefaultValue = name; SqlDataSource1.InsertParameters["salary"]. DefaultValue = salary; SqlDataSource1.InsertParameters["place"]. DefaultValue = place; SqlDataSource1.Insert(); } } return "OK"; } catch (Exception ex) { return ex.Message; } } } Выгрузка данных Создадим web-сервис, который содержит метод TownXML, возвращающий в качестве результата XML-документ с информацией о городах. Создадим новый Web-сайт, выберем для него тип ASP.NET Web Service. [WebService(Namespace = "http://tempuri.org/")] [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)] public class Service2 : System.Web.Services.WebService { public Service2 () { //... } Создадим в этом классе метод TownXML. Примечание: обратите внимание, что данный метод содержит 1 параметр – пустую строку, хотя по логике вещей никакие параметры данному методу вообще не нужны. Дело в том, что при обращении к 87 О.В. Пинягина методу Web-сервиса, не содержащему никаких параметров, из среды «1C:Предприятие», будет выдаваться ошибка (глюк?) [WebMethod] public string TownXML(string dummy) { try { Поскольку у Web-сервиса нет визуального представления, источник данных приходится создавать программным образом, в том числе следует задать команду для получения информации из таблицы городов: SqlDataSource SqlDataSource1 = new SqlDataSource(); SqlDataSource1.ConnectionString = "Data Source=.\\SQLEXPRESS; AttachDbFilename=|DataDirectory|\\database.mdf; Integrated Security=True;User Instance=True"; SqlDataSource1.SelectCommand = "SELECT * FROM towns"; В остальном код процедуры не использованием ASP.NET-страниц. отличается от варианта DataView towns = new DataView(); towns = (DataView)SqlDataSource1.Select (DataSourceSelectArguments.Empty); XmlTextWriter XMLData = new XmlTextWriter("test.xml", Encoding.UTF8); XMLData.WriteStartDocument(); XMLData.WriteStartElement("towns"); int i = 0; for (i = 0; i < towns.Count; i++) { XMLData.WriteStartElement("town"); XMLData.WriteAttributeString("kod", towns[i]["kod"].ToString()); XMLData.WriteAttributeString("name", towns[i]["name"].ToString()); XMLData.WriteAttributeString("num", towns[i]["num"].ToString()); XMLData.WriteAttributeString("data", towns[i]["data"].ToString()); XMLData.WriteEndElement(); } XMLData.WriteEndElement(); XMLData.Close(); 88 с Технология XML и ее приложения StreamReader text = new StreamReader("test.xml", Encoding.UTF8); string str = text.ReadToEnd(); text.Close(); return str; } catch (Exception ex) { return ex.Message; } } } 89 О.В. Пинягина Литература 1. Шапошников И.В. Справочник Web-мастера. XML [Текст]/ И.В. Шапошников – СПб.: БХВ-Петербург, 2001. – 304 с. 2. Холзнер С. XSLT библиотека программиста [Текст]: пер. с англ. / Стивен Холзнер – СПб.: Питер, 2002. – 544 с. 3. Холзнер С. XML. Энциклопедия, 2-е издание [Текст]: пер. с англ. / Стивен Холзнер – СПб.: Питер, 2004. – 1101 с. 4. Дари К., Бринзаре Б., Черчез-Тоза Ф., Бусика М. AJAX и PHP: разработка динамических веб-приложений. — СПб.: Символ Плюс, 2006. 5. Дейв Крейн, Эрик Паскарелло, Даррен Джеймс AJAX в действии: Asynchronous JavaScript and XML. – М.: «Вильямс», 2006. 6. Берк Пол Дж. SQL Server 2000 XML. – М.: БИНОМ. Лаборатория знаний, 2003. – 636 с. WEB-ресурсы 1. Semantic Web Resource Center : http://xml.com 2. Extensible Markup Language (XML): http://www.w3.org/XML/ 90 Технология XML и ее приложения Для заметок 91 О.В. Пинягина Для заметок 92