На главную Назад
Добро пожаловать, уважаемый посетитель!

 

ГЛАВА 14

РНР и XML

Бесспорно,развитие World Wide Web оказало заметное влияниена способы обмена информацией. Вследствиеогромных размеров этой электронной сетисоблюдение стандартов превратилось изпростого удобства в обязательноетребование - конечно, если вашаорганизация собирается в полной мереиспользовать потенциал Web. Одним из такихстандартов является язык XML (extensible Markup Language)- удобное средство обмена данными междуорганизациями и приложениями.

В началеэтой главы приведены общие сведения о XML,при этом особое внимание уделяется общемусинтаксису языка. Второй раздел посвященсредствам РНР для работы с XML. Мы рассмотримстандартные функции поддержки XML, а такжесхему общего процесса обработки файлов вформате XML. Этот материал позволит вам лучшепонять, чем же так ценен XML и как РНР можетприменяться для разработки полезных иинтересных приложений на базе XML.

Но преждечем переходить к непосредственномуописанию XML, я расскажу о том, как жеразвивались концепции, в конечном счетеприведшие к возникновению формата XML.

Разметкатекста

Какнетрудно предположить по его названию, языкHTML (HyperText MarkUp Language) относится к числу такназываемых языковразметки текста (markup languages).Под термином <разметка> понимается общаяслужебная информация, которая не выводитсявместе с документом, но определяет; какдолжны выглядеть те илииные фрагменты документа. Например, выможете потребовать, чтобы какое-либо слововыводилось жирным иликурсивным шрифтом,вывести отдельный абзац особым шрифтом илиоформлять заголовки увеличенным шрифтом.Текстовый редактор, в котором я ввожу этотабзац, тоже использует особую формуразметки для представления тех атрибутовформатирования, которые я выбираю. Такимобразом, в нем тоже используется особаяразновидность языка разметки. Корочеговоря, язык разметки, используемый моимтекстовым редактором, представляет собойсредство для описания визуальногооформления текста в моих документах.

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

  1. Языкопределяет синтаксис разметки. Например,в соответствии со спецификацией HTMLконструкция <b>text</b> определяетсинтаксически правильную разметку текста,а конструкция <xR5t>text</x4rt> считаетсянеправильной из-за несовпаденияоткрывающего и закрывающего тегов.
  2. Языкопределяет смысл разметки. Конечно,вы знаете, что команда <b>text</b> выводитслово text жирным шрифтом. В данном случаеопределяется смысл, связанный собъявлением некоторого компонентадокумента.

Стремительноеразвитие Web за последние несколько летнаглядно показывает, что самым популярнымязыком разметки текста является HTML. Но какпоявился этот язык? Кто закрепил за тегами<b> и </b> определенный смысл вдокументе? Чтобы ответить на этот вопрос,необходимо познакомиться спредшественником HTML - SGML (Standard Generalized MarkupLanguage).

Язык SGML

SGMLпредставляет собой международный стандартобмена электронной информацией междуразличными аппаратными и программнымикомпонентами. По названию можнопредположить, что SGML - это язык. На самомделе это не совсем так, поскольку SGML вдействительности определяетформализованный набор правил для созданияязыков. На базе SGML были созданы два самыхпопулярных языка разметки - HTML и XML. Как выуже знаете, HTML - плат-форменно- и аппаратно-независимыйязык, предназначенный для форматирования иотображения текста. То же самое можносказать и о XML.

Появлениестандарта SGML было обусловленонеобходимостью совместного использованияданных разными приложениями иоперационными системами. Даже в далеких 60-хгодах у пользователей компьютероввозникало немало проблем с совместимостью.Проанализировав недостатки многихнестандартных языков разметки, трое ученыхиз IBM - Чарльз Гольдфарб (Charles Goldfarb), Эд Мо-шер(Ed Mosher) и Рэй Лори (Ray Lorie) - сформулировалитри общих принципа, обеспечивающихвозможность совместной работы сдокументами в разных операционных системах:

  • Использованиеединых принципов форматирования во всехпрограммах, выполняющих обработкудокументов. Вполнелогичное требование - всем нам хорошоизвестно, как трудно договориться междусобой людям, говорящим на разных языках.Наличие единого набора синтаксическихконструкций и общей семантики заметноупрощает взаимодействие между программами.
  • Специализацияязыков форматирования. Благодарявозможности построенияспециализированного языка на базе наборастандартных правил программист
  • перестаетзависеть от внешних реализаций и ихпредставлений о потребностях конечногопользователя
  • Четкоеопределение формата документа.Правила, определяющие формат документа,задают количество и маркировку языковыхконструкций, используемых в документе.Применение стандартного форматагарантирует, что пользователь будет точнознать структуру содержимого документа.Обратите внимание: речь идет не о формате отображениядокумента, а о егоструктурном формате. Набор правил,описывающих этот формат, называется <определениемтипа документа> (document type definition, DTD).

Эти триправила были заложены в основупредшественника SGML - GML (Generalized Markup Language).Исследования и разработка GML продолжалисьоколо десяти лет, пока в результатесоглашения, заключенного международнойгруппой разработчиков, не появилсястандарт SGML.

В 1980-х годахнеобходимость в общих средствах обменаинформацией непрерывно возрастала, и SGMLвскоре превратился в отраслевой стандарт (в1986 году он был принят в качестве стандартаISO). Даже в наши дни этот стандарт занимаетдостаточно сильные позиции, посколькумногие организации, работающие с огромнымиобъемами информации, полагаются на SGML какна удобное и надежное средство храненияданных. Чтобы подкрепить сказанное, замечу,что Бюро патентов и товарных знаков США (http://www.uspto.gov),Служба внутренних сборов США (http://www.irs.gov) иБиблиотека Конгресса (http://lcweb.loc.gov)используют SGML в своих основных приложениях.Только представьте, какой объемдокументации проходит через этиорганизации за год!

Однимиз лучших ресурсов Интернета, посвященныхSGML, XML и другим языкам раз-метки, являетсясайт Robin Cover/OASIS XML Cover Pages (http://www.oasis-open.org/cover).

Идеяпередачи гипертекстовых документов черезweb-браузер, предложенная Тимом Бернерсом-Ли(Tim Berners-Lee), не требовала многих возможностей,поддерживаемых полной реализацией SGML. Врезультате появился известный языкразметки HTML.

ПришествиеHTML

КонцепцияWorld Wide Web идеально соответствовала идееприменения обобщенного языка разметки дляупрощения обмена информацией в среде,содержащей множество разных аппаратныхконфигураций, операционных систем ипрограммных реализаций. Несомненно,Бернерс-Ли учитывал это обстоятельство,поскольку он смоделировал первую версию HTMLна основе стандарта SGML. HTML унаследовалнекоторые характеристики SGML, в том числепростой обобщенный набор тегов и особуюроль угловых скобок. Простые документы вформате HTML можно прочитать в любойкомпьютерной системе, в которойпредусмотрены средства для просмотратекстовых документов. Все остальное -история.

Тем не менее,у HTML имеется существенный недостаток: он непозволяет разработчику создаватьсобственные типы документов. Результатомстала <война браузеров>, в ходе которойразработчики браузеров начали создаватьсвои собственные усовершенствования языкаHTML. Эти модификации существенноотклонялись от идеи работы с единымстандартом HTML и вызвали настоящий хаоссреди разработчиков, которые хотелисоздавать web-сайты, не зависящие от браузера.Более того, долгий период неопределенностив области стандартов привел к тому, чторазработчики вывели язык из первоначальнозадуманных границ. Думаю, подавляющеебольшинство web-страниц современногоИнтернета вообще не соответствуют текущейспецификации HTML.

Реакциейконсорциума W3 (http://www.w3.org) на быстроухудшающуюся ситуацию стала попыткавернуть развитие HTML на правильный путь -другими словами, вернуться к истокам SGML.Результатом этих усилийстал XML.

XML какнеопровержимое свидетельство эволюции

XML воплощаетвсе усилия, предпринятые W3 в областивыработки Интернет-стандарта, который бысоответствовал трем главным принципам SGML (см.предыдущий раздел). XML, как и SGML, не являетсяязыком; он также представляет собой наборрекомендаций, на базе которых создаютсядругие языки. Точнее говоря, XML являетсяконгломератом из трех отдельныхспецификаций:

  • XML (ExtensibleMarkup Language) -спецификация, определяющая базовыйсинтаксис XML;
  • XSL (ExtensibleStyle Language) -спецификация, направленная на отделениевизуального оформления страницы от еесодержимого за счет применения к документустилей (style sheets), определяющих конкретныеатрибуты форматирования;
  • XLL (ExtensibleLinking Language) -спецификация, определяющая представлениессылок на другие ресурсы.

XML не толькопозволяет разработчикам создаватьспециализированные языки для Интернет-приложений;он также обеспечивает возможность проверкиэтих документов на соответствиеспецификации XML. Более того, XMLдействительно реализует концепцию данных,не зависящих от реализации, посколькуформат отображаемого документа можно точноописать при помощи XSL. Допустим, выпереформатировали свой web-сайт, чтобы онхранился в формате XML. После этого' высможете использовать один стиль дляформатирования исходного текста XML напортативном компьютере типа Palm Pilot, а другой- для форматирования на мониторе обычногокомпьютера. В обоих случаях код XML остаетсяодним и тем же, изменяется только егоформатирование в соответствии сиспользуемым устройством.

Примеромпопулярного языка, созданного на базе XML,является WML (Wireless Markup Language).

Знакомство ссинтаксисом XML

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

Листинг14.1.Примердокумента XML

<?xml version="1.0"?>

<!DOCTYPE cookbookSYSTEM "cookbook.dtd">

<cookbook>

<recipe category="italian">

<title>Spaghetti alla Carbonara</title>

<description>Thistraditional Italian dish is sure to please even the most discriminating

critic.</description>

<ingredients>

<ingredient>2large eggs</ingredient>

<ingredient>4strips of bacon</ingredient>

<ingredient>lclove garlic</ingredient>

<ingredient>12ounces spaghetti</ingredient>

<ingredient>3tablespoons olive oil</ingredient>

</ingredients>

<process>

<step>Combine oiland bacon in large skillet over medium heat. Cook until bacon is

brown and crisp.</step>

<step>whisk eggsin bowl. Set aside.</step>

<step>Cook pastain large pot of boiling water to taste, stirring occasionally.

Add salt as necessary.</step>

<step>Drain pastaand return to pot. adding whisked eggs. Stir over medium-low

heat for 2-3 minutes.</step>

<step>Mix inbacon. Season with salt and pepper to taste.</step>

</process>

</recipe>

</cookbook>

Обратитевнимание на основные компоненты, из которыхсостоит документ XML:

  • пролог XML;
  • теги;
  • атрибуты;
  • ссылки насущности;
  • инструкциипо обработке;
  • комментарии.

Пролог XML

Вседокументы XML начинаются с пролога (prolog).Пролог сообщает, что документ написан на XML,а также указывает, какая версия XML при этомиспользовалась.

Посколькутекущая версия XML имеет номер 1.0, все вашидокументы XML должны начинаться со строки

<?xml version="1.0">

Следующаястрока в листинге 14.1 указывает на внешний DTD.Пока не обращайте на нее внимания - DTDподробно рассматриваются в следующемразделе <Определение типа документа (DTD)>:

<!DOCTYPE cookbookSYSTEM "cookbook.dtd">

Оставшаясячасть листинга 14.1 состоит из элементов,очень похожих на элементы документов HTML.Первый элемент, cookbook, называется корневымэлементом (root element),поскольку в эту пару тегов заключены всеостальные теги документа. Конечно, выможете присвоить корневому элементу любоеимя по своему усмотрению. Главное, о чемследует помнить, - все остальные элементыдолжны находиться внутри пары корневыхтегов.

Пролог можетсодержать другие инструкции. Например,объявление можно расширить, указав, чтодокумент является автономным:

<?xml version="1.0"standalone="yes">

Присваиваниеyes атрибуту standalone сообщает механизмуобработки XML-кода о том, что документ неимпортирует других файлов (например, DTD).

Хотя эторасширение, как и многие другие, приноситнесомненную пользу, я сокращаю описаниесинтаксиса до минимума, чтобы лучшевыделить основную тему этой главы -совместное использование РНР и XML.

Элементы

Оставшаясячасть документа состоит в основном изразличных служебных элементов исоответствующих данных. Служебные элементылегко узнать по угловым скобкам (как вразметке HTML). Элемент может быть пустым илисодержащим информацию; в этом случаеэлемент содержит открывающий и закрывающийтеги. Если элемент не пуст, то в тегивключаются имена, описывающие природуданных. Как видно из листинга 14.1, эти тегиочень похожи на теги документов HTML. Впрочем,следует помнить о некоторых важныхразличиях:

  • Непустыеэлементы должны содержать как открывающий,так и закрывающий тег. В элементах, которыелогически не могут иметь закрывающего тега,используется альтернативная формасинтаксиса <элемент />. Возникает вопрос- у каких элементов нет закрывающего тега?Достаточно вспомнить некоторые тегиформатирования HTML - например, <br>, <hr>и <img>, у них нет парных тегов. Теги этогоформата могут создаваться и в документах XML
  • Элементы XMLдолжны находиться на правильном уровневложенности. Документ XML, приведенный влистинге 14.1, синтаксически правилен;другими словами, теги элементов невстречаются там, где их быть не должно.Например, следующий фрагмент недопустим:

<title>Spaghettialia Carbonara

<ingredients></title>

  • В элементахXML различается регистр символов. Некоторымчитателям это наверняка не понравится.Например, в XML теги <tag>, <Tag> и <TAG>считаются разными тегами. Привыкайтепоскорее - с непривычки это может свестивас с ума.

Атрибуты

Теги XML,по аналогии с тегами HTML, могут обладатьатрибутами. Атрибуты содержатдополнительную информацию о содержании,которая в дальнейшем используется приформатировании или обработке XML. Значенияатрибутов присваиваются в формате <имя=значение>,и, в отличие от HTML, атрибуты XML должныбыть заключены вапострофы или кавычки. В листинге 14.1встречается пример использования атрибута:

<recipe category="italian">

Атрибутсообщает, что данный рецепт (recipe) относитсяк категории <итальянской кухни> (italian).Наличие такой информации упрощаетдальнейшую группировку и обработку данных.

Ссылки насущности

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

Чтобысослаться на некоторую сущность вдокументе HTML, следует указать ее имя спрефиксом <амперсанд> (&) и суффиксом <точкас запятой> (;). Допустим, вы объявилисущность с информацией об авторских правах.После этого на данную сущность можноссылаться следующим образом:

&Соруright:

При этомстрока документа XML может выглядеть так:

<footer>

...прочиеданные колонтитула...

&Copyright:

</footer>

Сущности,как и переменные и шаблоны, частоприменяются в ситуациях, когда некотораяинформация может измениться в будущем илидокумент содержит множество повторяющихсяссылок. Мы вернемся к проблемам объявленияссылок в разделе <Определение типадокумента (DTD)>.

Инструкциипо обработке

Инструкциипо обработке (processinginstructions, PI) представляют собой внешниекоманды, которые выполняются приложением,работающим с документом XML.

В общемслучае синтаксис PI выглядит так:

<?приложениеинструкции?>

Атрибутприложение указывает, какой программеадресованы последующие инструкции.Например, для выполнения команды РНР вдокументе XML можно воспользоватьсяследующей конструкцией:

<?php print "Today'sdate is:".date("m-d-Y");?>

Инструкциипо обработке удобны тем, что они позволяютнескольким приложениям совместно работатьс одним документом.

Комментарии

Комментариипринадлежат к числу основных возможностейлюбого языка. В XML используется тот жесинтаксис комментариев, что и в HTML: 

<!-комментарии->

Итак, мыпроанализировали структуру типичногодокумента XML. Но у документов XML существуетеще один важный аспект - определение типадокумента (DTD).

Определениетипа документа (DTD)

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

Учтите, чтоналичие DTD не является обязательным. Если DTDсуществует, система XML руководствуется импри интерпретации документа XML. Если DTDотсутствует, предполагается, что система XMLдолжна интерпретировать документ пособственным правилам. Впрочем, длядокументов XML все же рекомендуетсясоздавать DTD, поскольку это упрощает ихинтерпретацию и проверку структуры.

DTD можновключить непосредственно в документ XML,сослаться на него по URL или использоватькомбинацию этих двух способов. Принепосредственном включении DTD в документ XMLопределение DTD располагается сразу же послепролога:

<!DOCTYPE имя_корневого_элемента

...прочиеобъявления...

] >

Атрибут имя_корневого_элементасоответствует имени корневого элемента втегах, содержащих весь документ XML. В секции<прочих объявлений> находятся определенияэлементов, атрибутов и т. д.

Возможно, выпредпочитаете разместить DTD в отдельномфайле, чтобы обеспечить модульнуюструктуру программы. Давайте посмотрим, каквыглядит ссылка на внешний DTD в документе XML.Задача решается одной простой командой:

<!DOCTYPE имя_корневого_элементаSYSTEM "some_dtd.dtd">

Как и вслучае с внутренним объявлением DTD, имя_корневого_элементадолжно соответствовать имени корневогоэлемента в тегах, содержащих весь документXML. Атрибут SYSTEM указывает на то, что some_dtd.dtdнаходится на локальном сервере. Впрочем, нафайл some_dtd.dtd также можно сослаться по егоабсолютному URL. Наконец, в кавычкахуказывается URL внешнего DTD, расположенногона локальном или на удаленном сервере.

Как жесоздать DTD для листинга 14.1? Во-первых, мысобираемся создать в документе XML ссылку навнешний DTD. Как упоминалось в предыдущемразделе, ссылка на DTD выглядит так:

<!DOCTYPE cookbookSYSTEM "cookbook.dtd">

Возвращаяськ листингу 14.1, мы видим, что cookbook являетсяименем корневого элемента, a cookbook.dtd -именем DTD-файла. Содержимое DTD показано влистинге 14.2, а ниже приведены подробныеописания всех строк.

Листинг14.2. DTDдля листинга 14.1 (cookbook.dtd)

<?xml version="1.0"?>

<!DOCTYPE cookbook [

<!ELEMENT cookbook (recipe+)>

<!ELEMENT recipe (title,description, ingredients, process)>

<!ELEMENT title (#PCDATA)>

<!ELEMENTdescription (#PCDATA)>

<!ELEMENTingredients (ingredient+)>

<!ELEMENT ingredient (#PCDATA)>

<!ELEMENT process Cstep+)>

<!ELEMENT step (#PCDATA)>

<!ATTLIST recipecategory CDATA #REQUIRED>

] >

Что жеозначает этот загадочный документ?Несмотря на внешнюю сложность, вдействительности он довольно прост.Давайте переберем все содержимое листинга14.2:

<?xml version="1.0"?>

Перед намипролог XML, о котором уже говорилось выше.

<!DOCTYPE cookbook [

Втораястрока сообщает, что далее следует DTD сименем cookbook.

<!ELEMENT cookbook (recipe+)>

Третьястрока описывает элемент XML, в данном случае- корневой элемент cookbook. После него следуетслово recipe, заключенное в круглые скобки. Этоозначает, что в теги cookbook заключаетсявложенный тег с именем recipe. Знак + говорит отом, что в родительских тегахcookbook находится одна или несколько пар теговrecipe. 

<!ELEMENT recipe (title,description, ingredients. process)>

Четвертаястрока описывает тег recipe. В ней сообщается,что в тег recipe входят четыре вложенных тега:title, description, ingredients и process. Поскольку послеимен тегов не указываются признакиповторения (см. следующий раздел), внутритегов recipe должна быть заключена ровно однапара каждого из перечисленных тегов.

<! ELEMENT title (#PCDATA)>

Перед намипервое определение тега, который несодержит вложенных тегов. В соответствии сопределением он содержит #PCDATA, то естьпроизвольные символьные данные, несчитающиеся частью разметки.

<!ELEMENTingredients (ingredient+)>

Всоответствии с определением элемент ingredientsсодержит один или несколько тегов с именемingredient. Обратитесь к листингу 14.1, и вы всепоймете.

<! ELEMENTingredient (#PCDATA)>

Посколькуэлемент ingredient соответствует отдельномуингредиенту, вполне логично, что этотэлемент содержит простые символьные данные.

<! ELEMENT process (step+)>

Элемент processсодержит один или несколько экземпляровэлемента step. 

<! ELEMENT step (#PCDATA)>

Элемент step,как и элемент ingredient, соответствуетотдельному пункту в списке более высокогоуровня. Следовательно, он должен содержатьсимвольные данные.

<!ATTLIST recipecategory CDATA #REQUIRED>

Обратитевнимание: элемент recipe в листинге 14.1содержит атрибут. Этот атрибут, category,определяет общую категорию, к которойотносится рецепт - в приведенном примереэто категория <итальянская кухня> (Italian). Вопределении ATTLIST указывается как имяэлемента, так и имя атрибута. Кроме того,отнесение каждого рецепта к определеннойкатегории упрощает классификацию, поэтомуатрибут объявляется обязательным (#REQUIRED).

]>

Последняястрока просто завершает определение DTD.Определение всегда должно быть должнымобразом завершено, иначе произойдет ошибка.

В завершениеэтого раздела я приведу сводку основныхкомпонентов типичного DTD-файла:

  • объявлениятипов элементов;
  • объявленияатрибутов;
  • ID, IDREF и IDREFS;
  • объявлениясущностей.

Некоторые изэтих компонентов уже встречались нам вописании листинга 14.2. Далее каждыйкомпонент будет описан более подробно.

Объявленияэлементов

Всеэлементы, используемые в документе XML,должны быть определены в DTD, прилагаемом кдокументу. Мы уже встречались с двумяраспространенными разновидностямиопределений: для элемента, содержащегодругие элементы, и элемента, содержащегосимвольные данные. Данное определениесвидетельствует, что элемент содержиттолько символьные данные: 

<! ELEMENT описание(#РСDАТА)>

Следующееопределение элемента process говорит о том, чтоон содержит ровно один вложенный элемент сименем step: 

<!ELEMENT process (step)>

Впрочем,процессы (process) из одного шага (step)встречаются довольно редко - скорее всего,шагов будет несколько. Чтобы указать, чтоэлемент содержит один илинесколько экземпляроввложенного элемента step, следуетвоспользоваться признакомповторения:

<!ELEMENT process (step+)>

Количествовложенных элементов можно задатьнесколькими способами. Полный списокоператоров элементов приведен в табл. 14.1.

Таблица14.1. Операторыэлементов

Признак  Значение
? Ноль илировно один экземпляр 
*Нольили несколько экземпляров 
+Одинили несколько экземпляров
 Ровно одинэкземпляр 
| Один из элементов 
, Перечислениеэлементов

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

<!ELEMENT recipe (title,description, ingredients, process)>

Посколькупризнаки повторения не указаны, каждый тегдолжен встречаться ровноодин раз.

Определениеэлемента уточняется при помощи логическихоператоров. Предположим, вы работаете срецептами, в которые всегда входят макароны(pasta) с одним или несколькими типами сыра (cheese)или мяса (meat). В этом случае элемент ingredientопределяется следующим образом:

<!ELEMENT ingredient(pasta+, (cheese | meat)+)>

Посколькуэлемент pasta обязательно долженприсутствовать в элементе ingredient, онуказывается с признаком повторения +. Затемследует либо элемент cheese, либо элемент meat;мы разделяем альтернативы вертикальнойчертой и заключаем их в круглые скобки сознаком +, поскольку в рецепт всегда входитлибо одно, либо другое.

Существуют идругие разновидности определенийэлементов. Мы рассмотрели лишь простейшиеслучаи. Тем не менее, приведенногоматериала вполне достаточно для пониманияпримеров, приведенных в оставшейся частиэтой главы.

Объявленияатрибутов

Атрибутыэлементов описываютзначения, связываемые с элементами.Элементы XML, как и элементы HTML, могут иметьноль, один или несколько атрибутов. Общийсинтаксис объявления атрибутов выглядитследующим образом:

<!ATTLIST имя_элементаимя_атри6ута1 тип_данных1 флаг1

Имя_элементаопределяет имя элемента, включаемое в тег.Затем перечисляются атрибуты, связанные сданным элементом. Объявление каждогоатрибута состоит из трех основныхкомпонентов: имени, типа данных и флага,определяющего особенности данногоатрибута. Вместо многоточия (...) могут бытьрасположены объявления других атрибутов.

Простоеобъявление атрибута уже встречалось нам влистинге 14.2:

<!ATTLIST recipecategory CDATA #REQUIRED>

Тем не менее,как видно из приведенного общегоопределения, допускается одновременноеобъявление нескольких атрибутов. Допустим,в дополнение к атрибуту category вы хотитесвязать с элементом recipe дополнительныйатрибут difficulty (сложность приготовления).Оба атрибута объявляются в одном списке:

<!ATTLIST recipecategory CDATA #REQUIRED difficulty CDATA #REQUIRED>

Форматироватьобъявления подобным образом необязательно;тем не менее, многострочные объявлениянагляднее однострочных. Кроме того,поскольку оба атрибута являютсяобязательными, тег reci ре не можетограничиться каким-нибудь одним атрибутом,он должен включать в себя оба атрибутасразу. Например, следующий тег будетсчитаться неверным: <recipe difficulty="hard">

Почему?Потому что в нем отсутствует атрибут category.Правильный тег должен содержать обаатрибута:

<recipe category="Italian"difficulty="hard">

Особыеусловия обработки атрибута описываютсятремя флагами, перечисленными в табл. 14.2.

Таблица14.2.Флагиатрибутов

Флаг

Описание
#FIXED

 Во всехэкземплярах элемента в документе атрибутуможет присваиваться только одноконкретное значение

#IMPLIED

  Еслиатрибут не указан в элементе, используетсязначение по умолчанию 

#REQUIRED

 Атрибутявляется обязательным и долженприсутствовать во всех экземплярах элемента вдокументе

Типыатрибутов

Атрибутэлемента может объявляться с определеннымтипом. Типы атрибутов описаны далее.

Атрибуты CDATA

Очень частоатрибуты содержат общие символьные данные.Такие атрибуты называются атрибутами CDATA.Следующий пример уже встречался в началеэтого раздела:

<!ATTLIST recipecategory COATA #REQUIRED>

Атрибуты ID,IDREF и IDREFS

Идеяоднозначного представления данных (например,информации о пользователе или товаре,хранящейся в базе данных) посредствомидентификаторов неоднократно встречаласьв предыдущих главах книги. Идентификаторытакже часто используются в XML, посколькуперекрестные ссылки между документамиприменяются не только в общих задачахобработки данных, но и в World Wide Web (гиперссылки).

Идентификаторыэлементов присваиваются атрибуту ID.Допустим, вы хотите связать с каждымрецептом уникальный идентификатор.Соответствующий фрагмент DTD можетвыглядеть так:

<!ELEMENT recipe (title,description, ingredients, process)>

<!ATTLIST reciperecipe-id ID #REQUIRED>

<!ELEMENT recipe-refEMPTY>

<!ATTLIST recipe-refgo IDREF #REQUIRED>

После этогообъявление элемента recipe в документе можетвыглядеть так:

<recipe recipe-id="ital003"> 

<title>Spaghetti alla Carbonara</title>

Рецептоднозначно определяется идентификаторомital003. Следует помнить, что атрибут redpe-idотносится к типу ID, поэтому ital003 не можетиспользоваться в качестве значенияатрибута recipe-id другого элемента, впротивном случае документ будет считатьсясинтаксически неверным. Теперь допустим,что позднее вы захотели сослаться на этотрецепт из другого документа - скажем, изсписка любимых рецептов пользователя.Именно здесь в игру вступают перекрестныессылки и атрибут IDREF. Атрибуту IDREFприсваивается идентификатор, используемыйдля ссылок на элемент, - по аналогии с тем,как URL используется для идентификациистраницы в гиперссылке. Рассмотримследующий фрагмент кода XML:

<favoriteRecipes> 

<recipe-ref go="ital003"> 

</favoriteRecipes>

В процессеобработки документа XML элемент заменяетсяболее наглядной ссылкой на рецепт суказанным идентификатором (например,названием рецепта). Вероятно, он будетотформатирован в виде гиперссылки, чтобыупростить переход к указанному рецепту.

Перечисляемыеатрибуты

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

<!ATTLIST recipecategory (Italian | French | Japanese | Chinese) #REQUIRED difficulty (easy |medium | hard) #REQUIRED)

Обратитевнимание: при использовании списковдопустимых значений включать в объявлениетип CDATA не нужно, поскольку всеперечисленные значения относятся к форматуCDATA.

Перечисляемыеатрибуты со значением по умолчанию

Иногдабывает удобно объявить для атрибутазначение по умолчанию. Скорее всего, вам ужеприходилось делать это раньше припостроении форм с раскрывающимися списками.Например, если большинство рецептов в вашейповаренной книге относится к итальянскойкухне, атрибут recipe будет часто относиться ккатегории Italian. В этом случае категорию Italianможно назначить по умолчанию: 

<!ATTLIST recipecategory (Italian | French | Japanese | Chinese) "Itaian">

Если атрибутcategory не задан явно, по умолчанию ему присваиваетсязначение Italian.

Атрибуты ENTITYи ENTITIES

Данные вдокументах XML не всегда являются текстовыми- документ может содержать и двоичнуюинформацию (например, графику). На такиеданные можно ссылаться при помощи атрибутаentity. Например, в описании элемента descriptionможно указать атрибут recipePicture с графическимизображением:

<!ATTLISTdescription recipePicture ENTITY #IMPLIED>

Также можнообъявить сразу несколько сущностей,заменив ENTITY на ENTITIES. Значения разделяютсяпробелами.

АтрибутыNMTOKEN и NMTOKENS

АтрибутыNMTOKEN представляют собой строки из символов,входящих в ограниченный набор. Объявлениеатрибута с типом NMTOKEN предполагает, чтозначение атрибута соответствуетустановленным ограничениям. Как правило,значение атрибута NMTOKEN состоит из одногослова:

<!ATTLIST recipecategory NMTOKEN #REQUIRED>

Можнообъявить сразу несколько атрибутов,заменив NMTOKEN на NMTOKENS. Значения разделяютсяпробелами.

Объявлениясущностей

Объявлениесущности напоминает команду define внекоторых языках программирования, включаяРНР. Ссылки на сущности кратко упоминалисьв предыдущем разделе <Знакомство ссинтаксисом XML>. На всякий случай напомню,что ссылка на сущность используется вкачестве замены для другого фрагментасодержания. В процессе обработки документаXML все вхождения сущности заменяютсясодержанием, которое она представляет.Существует два вида сущностей: внутренние ивнешние.

Внутренниесущности

Внутренниесущности напоминают строковые переменные,связывающие имя с фрагментом текста.Например, если вы хотите определить имя дляссылки на информацию об авторских правах,можно объявить сущность следующего вида:

<!ENTITY Copyright"Copyright 2000 YourCompanyName. All Rights Reserved.">

В процессеобработки документа все экземпляры &Соруrightзаменяются текстом . Весь код XML в заменяющем текстеобрабатывается так, словно онприсутствовал в исходном документе.

Внутренниесущности удобны в ситуациях, когда выпланируете использовать сущность вотносительно небольшом количестведокументов XML. При большом количестведокументов лучше воспользоваться внешнимисущностями.

Внешниесущности

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

<!ENTITY Copyright SYSTEM "http://yoursite.com/administer/copyright.xml">

Припоследующей обработке документа XML всессылки &Соруright заменяются содержимымдокумента copyright.xml. Весь код XML в заменяющемтексте обрабатывается так, словно онприсутствовал в исходном документе.

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

<!ENTITYfood_picture SYSTEM http://yoursite.com/food/logo.gif>

Как и впредыдущем примере, все ссылки &food_pictureзаменяются графическим изображением, накоторое указывает ссылка. Поскольку данныеявляются двоичными, а не текстовыми, они неинтерпретируются.

Ресурсы,посвященные XML

Хотяприведенного выше материала вполнедостаточно для понимания базовой структурыдокументов XML, данное описание не являетсяполным. Ниже приведены ссылки на ресурсыИнтернета, содержащие более подробнуюинформацию:

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

Но стоитпознакомиться с базовой стратегией работыс XML в РНР, и все оказывается на удивлениепросто.

РНР и ХМL

Для работы сXML в РНР используется пакет Джеймса Кларка (JamesClark) Expat (XML Parser Toolkit) - cm. http://www.jclark.com/xml. Expatвключается в поставку Apache 1.3.7 и болеепоздних версий, поэтому вам не придетсяспециально загружать его, если выиспользуете свежую версию Apache. Чтобывоспользоваться функциональнымивозможностями XML в РНР, необходимонастроить РНР с ключом -with-xml.

РазработкуExpat 2.0 в настоящее время ведет Кларк Купер (ClarkCooper). За дополни- тельной информациейобращайтесь по адресу http://expat.sourceforge.net.

На первыйвзгляд задача обработки данных XML на РHР (илина любом другом языке) выглядит устрашающе,но на самом деле большая часть работывыполняется за вас стандартными средствамиРНР. Вам остается лишь определить новыефункции для своих DTD и затем применить их внесложном процессе обработки кода XML.

Прежде чемпереходить к рассмотрению функций РНР,предназначенных для работы с XML, необходимопознакомиться с основными компонентамидокумента XML. Это поможет вам лучше понять,почему эти функции являются незаменимойчастью любой программы обработки XML-кода. Насамом общем уровне документ XML содержиткомпоненты девяти видов:

  • открывающиетеги;
  • атрибуты;
  • символьныеданные;
  • закрывающиетеги;
  • инструкциипо обработке;
  • синтаксическиеобъявления;
  • внешниессылки на сущности;
  • необработанныесущности;
  • прочиекомпоненты (комментарии, объявления XML и т. д.).

Дляэффективной обработки документов XMLнеобходимо определить пользовательскиефункции-обработчики (handlers), обрабатывающиекаждый из перечисленных компонентов.Определенные функции подключаются кпроцессу обработки XML стандартнымисредствами РНР. Общий процесс обработкикода XML в РНР состоит из пяти этапов:

  1. Определитепользовательские функции. Разумеется, есливы собираетесь постоянно работать сдокументами XML, эти функции достаточнонаписать всего один раз и в дальнейшем лишьвносить в них необходимые изменения.
  2. Создайтеанализатор (parser) кода XML, который будетиспользоваться для обработки документа.Анализатор создается вызовом функцииxml_parser_create( ).
  3. При помощистандартных функций зарегистрируйте своифункции в анализаторе XML.
  4. Откройтефайл XML, прочитайте содержащиеся в немданные и передайте их анализатору XML.Обработка данных выполняется простымвызовом xml_parse( )! В процессе своей работы этафункция обеспечивает косвенный вызов всехопределенных вами обработчиков.
  5. Уничтожьтеанализатор XML, чтобы освободитьзадействованные им ресурсы.

Задачарешается функцией xml_parser_free( ). Смысл всехперечисленных этапов разъясняется вследующем разделе.

Подключениепользовательских функций к обработке XML

В РНРсуществует восемь стандартных функций длярегистрации пользовательских функций,обрабатывающих различные компонентыдокументов XML.

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

xml_set_character_data_handler()

Функциярегистрирует пользовательскую функцию дляработы с символьными данными. Синтаксис:

int xml_set_characterdata_handler(int анализатор,string обработчик_символьных_данных)

Первыйпараметр определяет анализатор XML, а второй- имя пользовательской функции,используемой при обработке символьныхданных. Определение функции-обработчикадолжно выглядеть так:

function обработчик_символьных_данных(int анализатор, string данные) {

...

}

Первыйпараметр определяет анализатор XML, а второй- символьные данные, подлежащие обработке.

xml_set_default_handler()

Функциярегистрирует пользовательскую функцию длявсех незарегистрированных компонентовдокумента XML. В частности, к числу такихкомпонентов относятся пролог XML икомментарии. Синтаксис:

int xml_set_default_handler(intанализатор,string обработчик_по_умолчанию)

Первыйпараметр определяет анализатор XML, а второй- имя пользовательской функции,используемой по умолчанию. Определениефункции-обработчика должно выглядеть так:

function обработчик_по_умолчанию(int анализатор, string данные) {

...

}

Первыйпараметр определяет анализатор XML, а второй- символьные данные, подлежащие обработке.

xml_set_element_handler()

Функциярегистрирует пользовательские функции дляобработки открывающих и закрывающих теговэлементов. Синтаксис:

int xml_set_element_handler(intанализатор, stringобработчик_открывающих_тегов, stringобработчик_закрывающих_тегов)

Первыйпараметр определяет анализатор XML. Второй итретий параметры определяют имена функций,используемых для обработки, соответственно,открывающих и закрывающих тегов.Определение обработчика открывающих теговдолжно выглядеть так:

function обработчик_открывающих_тегов(int анализатор, string имя_тега, 

string атрибуты[]) {

...

}

Первыйпараметр определяет анализатор XML, второй -имя открывающего тега для анализируемогоэлемента, а третий содержит массиватрибутов соответствующего тега.

Обработчикзакрывающих тегов определяется следующимобразом:

function обработчик_закрывающих_тегов(int анализатор, string имя_тега){

...

}

Первыйпараметр определяет анализатор XML, второй -имя закрывающего тега для анализируемогоэлемента.

xml_set_external_entity_ref_handler()

Функциярегистрирует пользовательскую функцию дляобработки внешних ссылок на сущности.Синтаксис:

int xml_set_external_entity_ref_handler(intанализатор,string обработчик_внешних_ссылок)

Первыйпараметр определяет анализатор XML, а второй- имя пользовательской функции,используемой при обработке внешних ссылок.Определение функции-обработчика должновыглядеть так:

function обработчик_внешних_ссылок(int анализатор, string ссылка, string база. stringсистемный_идентификатор, string открытый_идентификатор){

...

}

Первыйпараметр определяет анализатор XML. Второйпараметр определяет имя ссылки, четвертый- системный идентификатор ссылки насущность, а пятый - открытый идентификаторссылки. Третий параметр, база, в настоящеевремя не используется, однако егообъявление все равно обязательно.

xml_set_notation_decl_handler( )

Функциярегистрирует пользовательскую функцию дляобработки синтаксических объявлений.Синтаксис:

int xml_set_notation_decl_handler(intанализатор,string обработчик_синтаксических_обьявлений)

Первыйпараметр определяет анализатор XML, а второй- имя пользовательской функции,используемой при обработке синтаксическихобъявлений. Определение функции-обработчикадолжно выглядеть так:

function обработчик_синтаксических_обьявлений(int анализатор, string ссылка, string база, stringсистемный_идентификатор, string открытый_идентификатор){

...

}

Первыйпараметр определяет анализатор XML. Второйпараметр определяет имя объявления,четвертый - системный идентификатор, апятый - открытый идентификатор объявления.Третий параметр, база, в настоящее время неиспользуется, однако его объявление всеравно обязательно.

xml_set_object( )

Функцияассоциирует анализатор XML с некоторымобъектом. Синтаксис:

void xml_set_object(int анализатор,object &о6ъект)

Первыйпараметр определяет анализатор XML, а второйсодержит ссылку на объект, методы которогобудут использоваться для обработкикомпонентов XML. Таким образом, функцияxml_set_object связывает анализатор с объектом.Как правило, она вызывается в конструктореобъекта перед определениями функций-обработчиков:

class xmlDB { 

VAR $xmlparser:

function xmlDB( ) { 

$this->xmlparser = xml_parser_create(); 

// Связатьанализатор с объектом 

xml_set_object($this->xmlparser.&$this); 

// Определить функции-обработчики

xml_set_element_handler($this->xmlparser,

"startTag","endTag");

xml_set_character_data($this->xmlparser,"characterData");

}

...Определения функций-обработчиков startTag. endTag.characterData и т.д. ...

} // class xmlDB

В порядкеэксперимента попробуйте закомментироватьвызов xml_set_object( ). Вы увидите, что привыполнении этого фрагмента выводятсясообщения об ошибках, в которых говорится оневозможности обращения к методам объекта.

xml_set_processing_instruction_handler()

Функциярегистрирует пользовательскую функцию дляработы с Pi-инструкциями.

Синтаксис:

int xml_set_processing_instruction_handler(intанализатор,string обработчик_инструкций)

Первыйпараметр определяет анализатор XML, а второй- имя пользовательской функции,используемой при обработке Pi-инструкций.Определение функции-обработчика должновыглядеть так:

functionобработчик_инструкций(int анализатор, string приложение, stringинструкция) {

...

}

Первыйпараметр определяет анализатор XML, второй -имя приложения, выполняющего инструкции, атретий - инструкцию, передаваемуюприложению.

xml_set_unparsed_entity_decl_handler()

Функциярегистрирует пользовательскую функцию длянеобработанных внешних ссылок на сущности.Синтаксис:

int xml_set_external_entity_ref_handler(intанализатор,string обработчик_внешних_ссылок)

Первыйпараметр определяет анализатор XML, а второй- имя пользовательской функции,используемой для обработки необработанныхвнешних ссылок. Определение функции-обработчикадолжно выглядеть так:

function обработчик_внешних_ссылок(int анализатор, string сущность, string база, stringсистемный_идентификатор. string открытый_идентификатор,string имя_объявления) {

...

}

Первыйпараметр определяет анализатор XML. Второйпараметр определяет имя ссылки, четвертый- системный идентификатор ссылки насущность, а пятый - открытый идентификаторссылки. Третий параметр, база, в настоящеевремя не используется, однако егообъявление все равно обязательно. Наконец,последний параметр определяет имясинтаксического объявления.

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

Функцииобработки кода XML

Хотяреализация всех функций-обработчиков необязательна (документы XML не обязанысодержать элементы всех типов), по крайнеймере три функции должны присутствовать вовсех сценариях, работающих с XML.

xml_parser_create( )

Передобработкой документа XML необходимопредварительно создать анализатор.Синтаксис:

int xml_parser_create([stnngкодировка])

Необязательныйпараметр определяет кодировку исходноготекста. В настоящее время поддерживаютсятри варианта кодировки:

  • UTF-8;
  • US-ASCII;
  • ISO-8859-1 (используетсяпо умолчанию).

По аналогиис тем, как функция fopen( ) возвращаетманипулятор открытого файла, функцияxml_parser_create( ) также возвращает манипулятор,используемый для вызова различных функцийв процессе обработки XML. При одновременнойобработке нескольких документов можносоздать сразу несколько анализаторов.

xml_parse()

Функцияxml_parse( ) выполняет обработку документа XML.Синтаксис:

int xml_parse(int анализатор,string данные [int завершение])

Первыйпараметр определяет анализатор XML (используетсязначение, возвращаемое при вызове xml_parser_create()). Если необязательный параметр завершениеравен TRUE, передаваемый фрагмент данныхявляется последним. Как правило, этопроисходит при достижении концаобрабатываемого файла.

xml_parser_free( )

Функцияосвобождает ресурсы, выделенные для работыанализатора. Синтаксис:

int xml_parser_free(int анализатор)

Параметрфункции определяет анализатор XML.

Другиеполезные функции

В РНР такжесуществуют другие функции, упрощающиепроцесс обработки кода XML.

utf8_decode( )

Функцияпреобразует данные в кодировку ISO-8859-1.Предполагается, что преобразуемые данныенаходятся в кодировке UTF-8. Синтаксис:

string utf8_decode(string данные)

Параметрданные содержит преобразуемые данные вкодировке UTF-8.

utf8_encode( )

Функцияпреобразует данные из кодировки ISO-8859-1 вкодировку UTF-8. Синтаксис:

string utf8_decode(string данные)

Параметрданные содержит преобразуемые данные вкодировке ISO-8859-1.

xml_get_error_code( )

Функцияxm1_get_error_code( ) получает код ошибки, возникшейв процессе обработки XML. Код ошибкипередается функции xml_error_string( ) (см. ниже) дляинтерпретации. Синтаксис:

int xml_error_code(int анализатор)

Параметрфункции определяет анализатор XML. Примериспользования приведен ниже, в описаниифункции xml_get_current_line_number( ).

xml_error_string( )

Ошибкам,возникающим в процессе анализа кода XML,присваиваются числовые коды. Функцияxml_error_string( ) возвращает текстовое описаниеошибки по ее коду. Синтаксис:

string xml_error_string(intкод)

В параметрефункции передается код ошибки (вероятно,полученный при вызове функции xml_get_error_code( )).Пример использования функции приведен ниже,в описании функции xml_get_current_line_number( ).

xml_get_current_line_number()

Функциявозвращает номер текущей строки,обрабатываемой анализатором XML. Синтаксис:

int xml_get_current_line_number(intанализатор)

Параметрфункции определяет анализатор XML. Примериспользования функции:

while ($line - fread($fh.4096)) :

if (! xml_parse($xml_parser.$line. feof($fh)));

$err_string -xml_error_string(xml_get_error_code($xml_parser)); 

$line_number -xml_get_current_line_number($xml_parser); 

print "Error! [Line Sline_number]:$err_string";

endif; 

endwhile;

Например,если ошибка была обнаружена в шестой строкефайла, определяемого манипулятором $fh,сообщение будет выглядеть примерно так:

Error! [Line 6]:misnatched tag

xml_get_current_column_number()

Функцияxml_get_current_colunin_number( ) может использоваться всочетании с xml_get_current_line_number( ) дляопределения точного местонахожденияошибки в документе XML. Синтаксис:

int xml_get_current_column_number(intанализатор)

Параметрфункции определяет анализатор XML. Давайтеусовершенствуем предыдущий пример:

while ($line = fread($fh.4096)) :

if (! xml_parse($xml_parser,$line, feof($fh))):

$err_string =xml_error_string(xml_get_error_code($xml_parser)); 

$line_number =xml_get_current_line_number($xml_parser); 

$column_number =xml_get_current_column_number($xml_parser) 

print "Error! [Line$line_nuimber, Column $column_number]: $err_string"; 

endif; 

endwhile;

Например,если ошибка была обнаружена в шестой строкефайла, определяемого манипулятором $fh,сообщение будет выглядеть примерно так:

Error! [Line 6 Column2]:mismatched tag

Параметрыанализатора XML

В настоящеевремя в РНР поддерживаются два параметра,влияющих на работу анализатора XML:

  • XML_OPTION_CASE_FOLDING- автоматическое преобразование иментегов к верхнему регистру;
  • XML_OPTION_TARGET_ENCODING- кодировка документа на выходеанализатора XML. В настоящеевремя поддерживаются кодировки UTF-8, ISO-8859-1 иUS-ASCII.

Дляполучения текущих значений и модификацииэтих параметров применяются,соответственно, функции xml_parser_get_option( ) иxml_parser_set_option( ).

xml_parser_get_option()

Функцияxml_parser_get_option( ) получает текущее значениепараметра анализатора XML. Синтаксис:

int xml_parser_get_option(intанализатор, int параметр)

Первыйпараметр функции определяет анализатор XML,а второй - имя интересующего вас параметра.Пример:

$setting =xml_parser_get_option($xml_parser, XML_OPTION_CASE_FOLDING); 

print "CaseFolding: $setting";

Еслипараметру XML_OPTION_CASE_FOLDING не присваивалосьдругое значение, функция вернет значение поумолчанию. В этом случае будет выведенследующий результат:

Case Folding: 1

xml_parser_set_option()

Функцияxml_parser_set_option() задает значение параметраанализатора XML. Синтаксис:

int xml_parser_set_option(intанализатор,int параметр, mixed значение)

Первыйпараметр функции определяет анализатор XML,второй - имя интересующего вас параметра, атретий - его новое значение. Пример:

$setting =xml_parser_set_option($xml_parser, XML_OPTION_TARGER_ENCODING."UTF-8"):

В результатевыполнения этой команды выходная кодировкадокумента изменяется с ISO-8859-1 на UTF-8.

ПреобразованиеXML в HTML

Предположим,у вас имеется документ XML bookmarks.xml,содержащий список ссылок. Он выглядитпримерно так:

<?xml version="1.0"?>

<website>

<title>Epicurious</title>

<url>http://www.epicurious.com</url>

<description>

Epicurious is a greatonline cooking resource, providing tutorials.

recipes, forums and more.

</description></website>

Допустим, выхотите преобразовать bookmarks.xml и вывести егосодержимое в формате, совместимом сформатом браузера вашего компьютера.Программа, приведенная в листинге 14.3,преобразует файл к нужному формату.

Листинг14.3. ПреобразованиеXML в HTML

Class XMLHTML {

VAR $xmlparser:VAR $tagcolor ="#800000";

VAR $datacolor ="#0000ff";

function XMLHTML( ) {

$this->xmlparser =xml_parser_create();

xml_set_object($this->xmlparser. &$this); 

xml_set_element_handler($this->xmlparser, "startTag", "endTag"); 

xml_set_character_data_handler($this->xmlparser. "characterData");

}

// Функцияотвечает за обработку всех открывающихтегов.

function startTag($parser,$tagname, $attributes) {

GLOBAL $tagcolor;

print "<fontsize=\"-2\" color=\"$this->tagcolor\" face=\"arial, 

verdana\ ">&1 t ; $tagname&gt ; </f ont> <br>";

// Функцияотвечает за обработку всех символьныхданных.

function characterData($parser.$characterData) { 

GLOBAL $datacplor;

print "<fontsize=\"-2\" color=\"$this->datacolor\" face=\"arial,

verdana\ ">&nbsp; &nbsp; &nbsp; $characterData</font><br>";

// Функцияотвечает за обработку всех закрывающихтегов.

function endTag(Sparser,$tagname) {

GLOBAL Stagcolor;

print "<fontsize=\"-2\" color=\"$this->tagcolor\" face=\"arial,verdana\">&lt;/ 

$tagname&gt;</font> <br>";

}

function.parse($fp) {

// xml_parse($this->xm1parser,$data);

// Обработатьфайл XML

while ( $line = fread($fp.4096) ) :

// Привозникновении ошибки прервать обработку //и вывести сообщение об ошибке.

if ( ! xml_parse($this->xmlparser,$line, feof($fp))) :

die(sprintf("XMLerror: %s at line %d", 

xml_error_sthng(xml_get_error_code($this->xmlparser)), 

xml_get_curren_line_number($this->xmlparser))); 

endif;

endwhile;

}

}

// Открытьфайл XML для обработки 

$xml_file = "bookmarks. xml"; 

$fp = f open ($xml_flie, "r");

// Создатьновый объект 

$xml_parser = new XMLHTML;

// Обработать$xml_file 

$xml_parser->parse($fp);

?>

В результатепреобразования файл bookmarks.xml выводится вбраузере в следующем виде:

<WEBSITE> 

<TITLE>

Epicurious 

</TITLE> 

<URL>

http : //www.epicurious.com 

</URL>

<DESCRIPTION>

Epicurious is a greatonline cooking resource,

providing tutorials,recipes, forums and more. 

</DESCRIPTION> 

</WEBSITE>

Конечно,результат не такой уж впечатляющий - мывсего лишь добились, чтобы файл XMLотображался в браузере. Внеся небольшиеизменения в листинг 14.3, можно преобразоватьURL в работающие гиперссылки, оформитьданные между парой тегов <TITLE>...</TITLE>жирным шрифтом и т. д. Как видно из листинга14.3, я использую шрифт двух разных цветов,чтобы продемонстрировать возможностьформатирования текста в браузере.

Несколькослов о РНР и XML

В этой главемы познакомились с XML и различнымифункциями РНР, предназначенными дляобработки документов в формате XML.Поскольку основной темой книги являетсяРНР, я описал лишь одну из трех спецификацийстандарта XML и не упомянул о том, какработают XSL и XLL. Конечно, полноценноеотделение содержания от представлениятребует использования всех трехкомпонентов или по меньшей мере XML и XSL.

Ксожалению, на момент написания книги РНРеще не обладал возможностями, которые быпозволяли работать с XMLисключительно средствами РНР. Конечно,

возможностиРНР продолжают расширяться, и в будущем этапроблема обязательно будет решена.

Особоговнимания в этой области заслуживает XSL-процессорSablotron, разработанный компанией Ginger Alliance Lts. (http://www.gingerall.com).12 октября 2000 года было объявлено о том, чтоРНР 4.03 отныне распространяется с модулемрасширения Sablotron для платформ Linux и Windows.Обязательно проследите за дальнейшимразвитием событий.

Итоги

В этой главебыл изложен довольно обширный материал,касающийся XML и возможностей обработки кодаXML в РНР. Глава начинается с краткой историиязыков разметки. Читатель знакомится с XML иего основными преимуществами, после чегоприводится сводка синтаксическихконструкций языка. Оставшаяся часть главыпосвящена стандартным функциям РНР дляработы с кодом XML. В завершение приводятсяпримеры использования РНР для обработки ивывода данных XML. В частности,рассматриваются следующие вопросы:

  • краткоеописание языков разметки текста;
  • SGML;
  • общиесведения о XML;
  • синтаксис XML;
  • описаниетипа документа (DTD);
  • РНР и XML.

В главе 15рассматриваются две перспективныетехнологии, JavaScript и СОМ (Component Object Model), ивозможности их использования в РНР.