Перетворення SQL в XML за допомогою PHP (исходники), HTML, XML, DHTML, Інтернет-технології, статті

Введення


Можливо, ви чули про PEAR – архіві додатків і розширень PHP (PHP Extension and Application Repository). Цей проект, підтримуваний співтовариством користувачів, націлений на створення великої бібліотеки високоякісного відкритого коду, який допоможе програмістам на PHP прискорити розробку додатків. Уже давно PEAR, схожий по ідеї з архівом CPAN для Perl, є першим місцем, де я шукаю цікаві і корисні віджети PHP + XML. Деякі з них використовують клас XML_Serializer, дуже зручний для перетворення структур даних PHP в послідовну форму об’єктів XML; клас XML_XUL, що надає інтерфейс API для розробки додатків Mozilla XUL, і клас XML_SVG, який реалізує методи програмного побудови векторної графіки в форматі SVG.


У цій статті я розповім вам про ще один елемент розділу XML архіву PEAR – класі XML_Query2XML. Цей клас реалізує програмний інтерфейс для швидкого та ефективного перетворення результуючого безлічі даних SQL в правильно оформлений XML-код. Використовуючи трохи фантазії, можна перетворити ці дані в інші формати за допомогою XSLT або інтегрувати їх з іншими додатками, які використовують XML.


Установка необхідного програмного забезпечення


Пакет XML_Query2XML активно розробляється і підтримується Лукасом Фейлером (Lukas Feiler) і випускається для спільноти PHP під ліцензією LGPL. Для нього потрібно PHP 5.0 (або пізнішої версії). Простіше всього встановити цей пакет за допомогою автоматичної настановної програми PEAR, яка повинна за замовчуванням присутній у вашій збірці PHP. Щоб встановити цей пакет, просто виконайте наступну команду в командному рядку shell:


shell>pear install XML_Query2XML


Програма установки PEAR з’єднується з сервером пакетів PEAR, завантажує пакет і встановлює його у відповідну папку у вашій системі.


Щоб встановити пакет вручну, зайдіть на Web-сайт PEAR, завантажте архів з пакетом і розархівуйте файли в потрібну директорію. Врахуйте, що для процесу ручної установки необхідне знання організаційної структури пакета PEAR.


На цьому етапі треба також пам’ятати про деякі залежності пакунка:



  1. Для зв’язку з необхідною СУБД пакет XML_Query2XML використовує один з рівнів абстракції бази даних DB, MDB2 або ADOdb, тому в системі повинен бути встановлений один з цих рівнів абстракції і драйвер відповідної бази даних. У прикладах, наведених у цій статті, використовується рівень абстракції MDB2, який разом з драйвером MySQL MDB2_Driver_mysql також можна знайти в архіві пакетів PEAR. Як було описано раніше, для установки обох пакетів ви можете скористатися програмою автоматичної установки PEAR або завантажити з с Web-сайту PEAR.
  2. У прикладах, наведених у цій статті, використовується демонстраційна база даних MySQL world, Вже заповнена і містить зв’язані таблиці даних про містах і країнах. Посилання на завантаження бази даних MySQL worldнаведена внизу сторінки.
  3. Для прикладів, наведених у цій статті, потрібно, щоб збірка PHP підтримувала функції PHP DOM, XSL і SimpleXML. Ці функції включені за замовчуванням в PHP 5.x.
  4. Передбачається, що ви знаєте функції PHP DOM і SimpleXML, а також технології XML, XPath і XSL.

Всі приклади, наведені в цій статті, були перевірені на XML_Query2XML версії 1.2.1.


Перетворення SQL в XML


Якщо встановлені всі необхідні компоненти, ви можете почати вивчення XML_Query2XML з наступного простого сценарію PHP:


Лістинг 1. Просте перетворення SQL в XML





<?php / / Включаємо необхідні файли
include “XML/Query2XML.php”;
include “MDB2.php”;
try { / / Ініціалізували об’єкт Query2XML
$q2x = XML_Query2XML::factory(MDB2::factory(“mysql://root:pass@localhost/world”));
/ / Формуємо запит SQL / / Отримуємо результат в XML
$sql = “SELECT * FROM Country”;
$xml = $q2x->getFlatXML($sql);
/ / Відправляємо результат в браузер
header(“Content-Type: text/xml”);
$xml->formatOutput = true;
echo $xml->saveXML();
} catch (Exception $e) {
echo $e->getMessage();
}
?>

Цей сценарій демонструє приклад використання класу XML_Query2XML. Спочатку сценарій включає файли класів XML_Query2XML і MDB2, а потім ініціалізує екземпляр рівня абстракції MDB2 за допомогою методу factory(). На вхід цього методу передається рядок DSN, що містить інформацію про тип СУБД, імені користувача та пароль, а також назві бази даних. Одержаний примірник MDB2 використовується для ініціалізації примірника XML_Query2XML, представленого об’єктом $q2x.


Коли ви сформували рядок DSN і створили екземпляр об’єкта XML_Query2XML, приходить час виконати запит SQL до СУБД і перетворити результат в XML. Ця дія реалізується в методі getFlatXML() класу XML_Query2XML, який використовується в основному для простих запитів типу SELECT. На виході цей метод повертає правильно оформлений документ XML, що містить результуюче безліч SQL. Він буде виглядати приблизно так:


Лістинг 2. Документ XML, сформований в результаті роботи лістингу 1 (скорочений)





<?xml version=”1.0″ encoding=”UTF-8″?>
<root>
<row>
<code>AFG</code>
<name>Afghanistan</name>
<continent>Asia</continent>
<region>Southern and Central Asia</region>
<surfacearea>652090.00</surfacearea>
<indepyear>1919</indepyear>
<population>22720000</population>
<lifeexpectancy>45.9</lifeexpectancy>
<gnp>5976.00</gnp>
<gnpold></gnpold>
<localname>Afganistan/Afqanestan</localname>
<governmentform>Islamic Emirate</governmentform>
<headofstate>Mohammad Omar</headofstate>
<capital>1</capital>
<code2>AF</code2>
</row>
<row>
<code>NLD</code>
<name>Netherlands</name>
<continent>Europe</continent>
<region>Western Europe</region>
<surfacearea>41526.00</surfacearea>
<indepyear>1581</indepyear>
<population>15864000</population>
<lifeexpectancy>78.3</lifeexpectancy>
<gnp>371362.00</gnp>
<gnpold>360478.00</gnpold>
<localname>Nederland</localname>
<governmentform>Constitutional Monarchy</governmentform>
<headofstate>Beatrix</headofstate>
<capital>5</capital>
<code2>NL</code2>
</row>
<row>
<code>ANT</code>
<name>Netherlands Antilles</name>
<continent>North America</continent>
<region>Caribbean</region>
<surfacearea>800.00</surfacearea>
<indepyear></indepyear>
<population>217000</population>
<lifeexpectancy>74.7</lifeexpectancy>
<gnp>1941.00</gnp>
<gnpold></gnpold>
<localname>Nederlandse Antillen</localname>
<governmentform>Nonmetropolitan Territory of
The Netherlands</governmentform>
<headofstate>Beatrix</headofstate>
<capital>33</capital>
<code2>AN</code2>
</row>

</root>

Якщо уважно вивчити наведений вище документ XML, стає видно чітка структура. Кожен запис з результуючого безлічі SQL представлена ​​елементом <row>, А окремі поля кожного запису розташовані всередині відповідного . Назви вкладених елементів відповідають іменам полів таблиці, до якої виконується запит, а елемент документа – корінь дерева XML – називається, відповідно, <root>.


Перетворення вихідного XML за допомогою XSL


Звичайно ж, створення XML із запиту SQL – це, як правило, тільки половина роботи; після цього з ним треба щось зробити. З документом XML можна зробити безліч речей, проте найчастіше його перетворять за допомогою XSLT в будь-який інший формат, наприклад, HTML або RSS. Беручи це до уваги, складемо невелику таблицю стилів XSL для перетворення виведення XML з Лістингу 2 в просту сторінку HTML.


Лістинг 3. Таблиця стилів XSL





<?xml version=”1.0″ encoding=”UTF-8″?>
<xsl:stylesheet xmlns:xsl=”http://www.w3.org/1999/XSL/Transform” version=”1.0″>
<xsl:template match=”/root”>
<html>
<head>
<style type=”text/css”>
td { text-align: center; padding: 3px; }
.head { font-style: italic; }
</style>
</head>
<body>
<table class=borderall>
<thead>
<tr>
<xsl:for-each select=”row[1]/*”>
<td class=”head”>
<xsl:value-of select=”local-name(.)”/>
</td>
</xsl:for-each>
</tr>
</thead>
<tbody>
<xsl:apply-templates/>
</tbody>
</table>
</body>
</html>
</xsl:template>
<xsl:template match=”row”>
<tr>
<xsl:apply-templates/>
</tr>
</xsl:template>
<xsl:template match=”row/*”>
<td>
<xsl:value-of select=”.”/>
</td>
</xsl:template>
</xsl:stylesheet>

В Лістингу 4 наведено виправлений сценарій PHP, в якому тепер використовуються функції XSL PHP для перетворення виведення XML_Query2XML:


Лістинг 4. Перетворення виведення SQL в XML за допомогою XSL





<?php / / Включаємо необхідні файли
include “XML/Query2XML.php”;
include “MDB2.php”;
try { / / Ініціалізували об’єкт Query2XML
$q2x = XML_Query2XML::factory(MDB2::factory(“mysql://root:pass@localhost/world”));
/ / Формуємо запит SQL / / Отримуємо результат в XML
$sql = “SELECT * FROM Country”;
$xml = $q2x->getFlatXML($sql);
/ / Зчитуємо дані таблиці стилів XSL
$xsl = new DOMDocument;
$xsl->load(“country.xsl”);
/ / Ініціалізували механізм XSLT
$xslp = new XSLTProcessor;
/ / Підключаємо об’єкт таблиці стилів XSL
$xslp->importStyleSheet($xsl);
/ / Виконуємо перетворення
header(“Content-Type: text/html”);
echo $xslp->transformToXML($xml);
} catch (Exception $e) {
echo $e->getMessage();
}
?>

Перша частина цього сценарію така ж, як і в Лістингу 1; Вона формує документ XML, що містить результати виконання запиту SQL і записує його в змінну $xml як екземпляр DOMDocument. Потім ініціалізується екземпляр класу XSLTProcessor і за допомогою методу importStyleSheet() імпортується таблиця стилів XSL. Після цього викликається метод transformToXML(), Який отримує в якості аргументу вихідні дані XML, який перетворює документ XML в сторінку HTML за правилами, описаним в таблиці стилів XSL.


На малюнку 1 показано, як буде виглядати результат:


Рисунок 1. Документ HTML, сформований програмою з лістингу 4

Існує безліч варіантів використання можливостей організації вкладеності, крім того, XML_Query2XML пропонує безліч варіантів додаткового налаштування виводу документів XML.


Фільтрація записів SQL за допомогою XPath


Як можна припустити, обмежити кількість записів, що виводяться методом getXML(), Досить легко. Досить просто додати відповідне умова WHERE до запиту SQL. Іншим способом є використання конструкцій XPath для створення обмежених підмножин дерева XML і його повернення зухвалому клієнту.


В Лістингу 12 наведено простий приклад реалізації цього способу шляхом модифікації Лістингу 11 та обмеження виводяться в XML даних тільки країнами та містами, розташованими в Європі, за допомогою умов XPath:


Лістинг 12. Обмеження даних, що виводяться з SQL в XML за допомогою XPath





<?php / / Включаємо необхідні файли
include “XML/Query2XML.php”;
include “MDB2.php”;
try { / / Ініціалізували об’єкт Query2XML
$q2x = XML_Query2XML::factory(MDB2::factory(“mysql://root:pass@localhost/world”));
/ / Формуємо запит SQL / / Отримуємо результат в XML
$sql_1 = “SELECT * FROM Country”;
$sql_2 = “SELECT * FROM City WHERE CountryCode = ? ORDER BY Population DESC LIMIT 5”;
$xml = $q2x->getXML($sql_1, array(
“idColumn” => “code”,
“rootTag” => “countries”,
“rowTag” => “country”,
“attributes” => array(“code”, “name”, “continent”),
“elements” => array(“cities” => array(
“sql” => array(“data” => array(“code”), “query” => $sql_2),
“idColumn” => “id”,
“rootTag” => “cities”,
“rowTag” => “city”,
“attributes” => array(“name”,”district”,”population”))
)
)
);
/ / Тепер фільтруємо XML ще раз за допомогою XPath / / Повертаємо в DOMNodeList тільки ті вузли , / / У яких є атрибут “continent = Europe”
$xpath = new DOMXPath($xml);
$nodelist = $xpath->query(“/countries/country[@continent=”Europe”]”);
/ / Створюємо нове дерево DOM за допомогою безлічі XPath / / Створюємо кореневий елемент / / Імпортуємо всі вузли зі списку і вставляємо в нове дерево DOM
$dom = new DOMDocument;
$root = $dom->createElement(“countries”);
$dom->appendChild($root);
$x = 0;
while ($node = $nodelist->item($x)) {
$node = $dom->importNode($node, true);
$root->appendChild($node);
$x++;
}
/ / Виконуємо друк XML
header(“Content-Type: text/xml”);
$dom->formatOutput = true;
echo $dom->saveXML();
} catch (Exception $e) {
echo $e->getMessage();
}
?>

Перша частина сценарію залишилася незмінною – два вкладених запиту SQL, для формування списку країн і міст внутрішній запит використовує дані з зовнішнього. Проте цього разу замість того, щоб виводити XML безпосередньо на друк або передавати його обробникові XSLT, ініціалізується об’єкт DOMXPath і з вихідного дерева XML створюється новий список DOMNodeList. Щоб вивести в цей список тільки елементи , що містять атрибут continent зі значенням Europe, Використовується запит XPath. Після створення списку DOMNodeList ініціалізується новий об’єкт DOMDocument і в нього імпортується цей DOMNodeList, формуючи новий документ XML.


В Лістингу 13 показаний фрагмент результату:


Лістинг 13. Результат XML, сформований програмою в лістингу 12 (скорочений)





<?xml version=”1.0″?>
<countries>
<country code=”NLD” name=”Netherlands” continent=”Europe”>
<cities>
<city name=”Amsterdam” district=”Noord-Holland” population=”731200″/>
<city name=”Rotterdam” district=”Zuid-Holland” population=”593321″/>
<city name=”Haag” district=”Zuid-Holland” population=”440900″/>
<city name=”Utrecht” district=”Utrecht” population=”234323″/>
<city name=”Eindhoven” district=”Noord-Brabant” population=”201843″/>
</cities>
</country>
<country code=”ALB” name=”Albania” continent=”Europe”>
<cities>
<city name=”Tirana” district=”Tirana” population=”270000″/>
</cities>
</country>
<country code=”AND” name=”Andorra” continent=”Europe”>
<cities>
<city name=”Andorra la Vella” district=”Andorra la Vella” population=”21189″/>
</cities>
</country>
<country code=”BEL” name=”Belgium” continent=”Europe”>
<cities>
<city name=”Antwerpen” district=”Antwerpen” population=”446525″/>
<city name=”Gent” district=”East Flanderi” population=”224180″/>
<city name=”Charleroi” district=”Hainaut” population=”200827″/>
<city name=”Liège” district=”Liège” population=”185639″/>
<city name=”Bruxelles [Brussel]” district=”Bryssel” population=”133859″/>
</cities>
</country>

<countries>

Злиття даних з декількох джерел


При розробці реальних програм на базі XML малоймовірно, що документ XML буде містити інформацію тільки з одного джерела. На додаток до одного або кількох запитів SQL він може також включати в себе дані з дискових файлів, від зовнішніх Web-сервісів або з системної таблиці процесів. Для обліку цієї ситуації XML_Query2XML надає спосіб інтеграції в документ XML, що повертається методом getXML(), Даних із джерел, відмінних від SQL.


Пакет XML_Query2XML дозволяє розробникам визначати власні функції зовнішнього виклику, викликані певними елементами в формованому документі XML. Ці функції необхідні для отримання потрібних даних, перетворення їх у формат XML і повернення цього XML (у вигляді примірника DOMNode) викликає функції у форматі, відповідному для вставки у відповідну позицію в дереві документа XML. У виклику getXML() перед назвою функції виклику вказується символ решітки (#), На вхід буде автоматично подаватися поточна запис SQL.


У вас може виникнути запитання, наскільки дійсно корисна ця функція. Найкраще продемонструвати це на прикладі. По-перше, припустимо, що ви бажаєте сформувати документ XML, в якому будуть перераховані країни і найбільш населені міста. Ви вже бачили багато прикладів, що роблять точно те ж саме. Щоб зробити приклад більш цікавим, давайте доповнимо XML координатами широти і довготи кожного міста за даними Web-сервісу GeoNames.


Код представлений в Лістингу 14:


Лістинг 14. Інтеграція даних Web-сервісів з результатами перетворення SQL в XML





<?php
ini_set(“max_execution_time”, 120); / / Включаємо необхідні файли
include “XML/Query2XML.php”;
include “MDB2.php”;
try { / / Ініціалізували об’єкт Query2XML
$q2x = XML_Query2XML::factory(MDB2::factory(“mysql://root:pass@localhost/world”));
/ / Формуємо запит SQL / / Отримуємо результат в XML
$sql = “SELECT Country.Code2 AS code, Country.Name AS country, City.Name AS city,
City.Population AS population FROM Country, City
WHERE Country.Code = City.CountryCode GROUP BY City.CountryCode
HAVING City.Population = MAX(City.Population) ORDER BY City.Population
DESC LIMIT 15”;
$xml = $q2x->getXML($sql, array(
“idColumn” => “code”,
“rootTag” => “countries”,
“rowTag” => “country”,
“attributes” => array(“code”, “name” => “country”),
“elements” => array(“city” => array (
“elements” => array(
“name” => “city”,
“population”,
“location” => “#getLocation”),
)
),
)
);
/ / Виводимо XML
header(“Content-Type: text/html”);
$xml->formatOutput = true;
print $xml->saveXML();
} catch (Exception $e) {
echo $e->getMessage();
}
/ / Функція отримання даних Web-сервісу GeoNames / / Викликаємо GeoNames і передаємо назва країни та міста / / Створюємо фрагмент документа XML з повернутими значеннями
function getLocation($record) { / / Отримуємо дані і формат в об’єкт SimpleXML
$sxml = simplexml_load_string(file_get_contents(
“http://ws.geonames.org/search?maxRows=1&name=” .
urlencode(utf8_encode($record[“city”])) . “&country=” .
urlencode(utf8_encode($record[“code”]))));
/ / Витягуємо дані з об’єкта SimpleXML / / Перетворимо їх у фрагменти DOMNode
$dom = new DOMDocument(); / / Формуємо вузол
$lat = $dom->createElement(“lat”);
$lat->appendChild($dom->createTextNode($sxml->geoname{0}->lat)); / / Формуємо вузол
$long = $dom->createElement(“long”);
$long->appendChild($dom->createTextNode($sxml->geoname{0}->lng));
return array($lat, $long);
}
?>

Виклик getXML() в Лістингу 14 виконує запит SELECT, який групує міста по країнах і вибирає міста з найбільшим населенням. Після цього дані перетворюються в документ XML наступного виду (Лістинг 15):


Лістинг 15. Документ XML, сформований кодом з лістингу 14 на першому етапі (скорочений)





<?xml version=”1.0″ encoding=”UTF-8″?>
<countries>
<country code=”AW” name=”Aruba”>
<city>
<name>Oranjestad</name>
<population>29034</population>
</city>
</country>

</countries>

Тепер потрібно отримати координати широти і довготи кожного з міст і додати їх у сформоване раніше дерево документа (див. Лістинг 14). Ця інформація запитується на Web-сервісі GeoNames, доступному в стилі REST, у якого відкритий метод search(), Який повертає географічну інформацію зазначеного місця.


В Лістингу 16 показаний приклад пакета, який висилає GeoNames у відповідь на запит “Berlin, Germany”:


Лістинг 16. Приклад відповідного пакета GeoNames





<?xml version=”1.0″ encoding=”UTF-8″ standalone=”no”?>
<geonames>
<totalResultsCount>807</totalResultsCount>
<geoname>
<name>Berlin</name>
<lat>52.5166667</lat>
<lng>13.4</lng>
<geonameId>2950159</geonameId>
<countryCode>DE</countryCode>
<countryName>Germany</countryName>
<fcl>P</fcl>
<fcode>PPLC</fcode>
</geoname>
</geonames>

Як бачите, у відповідному пакеті міститься різна інформація про зазначеному місці, у тому числі й дані, які нас цікавлять – координати широти і довготи.


Давайте тепер уважно подивимося на виклик getXML() в Лістингу 13. Зверніть увагу, що ключ location масиву параметрів є пов’язаною, але не з полем з результату запиту, а з функцією зовнішнього виклику getLocation(). Це означає, що всякий раз, коли getXML() обробляє запис з результуючого безлічі SQL, він викликає getLocation() для цього запису як асоціативний масив пар поле-значення. Метод getLocation(), В свою чергу, за допомогою REST викликає метод search() Web-сервісу GeoNames, передає йому як параметр назва міста та країни із запису SQL і отримує відповідь як об’єкт SimpleXML. Після цього для отримання елементів <lat> і <lng> з відповідного пакета, їх перетворення в два окремих екземпляри DOMNode та їх передачі getXML() у вигляді масиву для вставки в дерево можна використовувати нотацію SimpleXML.


В кінці обробки вихідний документ буде виглядати так, як показано в лістингу 17:


Лістинг 17. Остаточний вихідний документ XML, що формується в Лістингу 14 (скорочений)





<?xml version=”1.0″ encoding=”UTF-8″?>
<countries>
<country code=”IN” name=”India”>
<city>
<name>Mumbai (Bombay)</name>
<population>10500000</population>
<location>
<lat>18.975</lat>
<long>72.8258333</long>
</location>
</city>
</country>
<country code=”KR” name=”South Korea”>
<city>
<name>Seoul</name>
<population>9981619</population>
<location>
<lat>37.5663889</lat>
<long>126.9997222</long>
</location>
</city>
</country>

</countries>

Як видно з цього прикладу, використання власних функцій зовнішнього виклику – це найпростіший шлях перетворення даних з різних джерел в документ XML, що формується методом getXML(). Сценарій з Лістингу 14 підключається до зовнішнього Web-сервісу; так само просто можна імпортувати в кінцеве дерево документа XML зовнішній файл або результат виконання виклику XML-RPC.


Створення резервної копії бази даних


Ще одним корисним додатком пакета XML_Query2XML є копіювання вмісту таблиць бази даних у формат XML для подальшого зберігання та резервування. Логіка сценарію резервного копіювання дуже проста: отримати перелік таблиць бази даних, послідовно пройти по цьому списку і виконати запити DESC ? і SELECT * FROM ? SQL для вилучення відповідно схеми і записів кожної з таблиць. Якщо ви уважно вивчали цю статтю, ви, напевно, вже уявляєте собі, як повинен виглядати виконує цю функцію метод getXML().


Вирішити це завдання здається на перший погляд не так просто, головним чином через обмеження рівня абстракції MDB2, а саме, через те, що він не може обробляти символи підстановки для назв таблиць і колонок у підготовлених запитах. Це ускладнює використання згаданих раніше запитів DESC ? і SELECT * FROM ?, Так як рівень MDB2 буде просто видавати помилку, якщо зустріне такі запити.


Що робити в цій ситуації? Проявити трохи фантазії, як в Лістингу 18:


Лістинг 18. Формування дампа структури та вмісту бази даних у форматі XML





<?php
ini_set(“max_execution_time”, 120);
/ / Включаємо необхідні файли
include “XML/Query2XML.php”;
include “MDB2.php”;
/ / Встановлюємо назву бази даних
$db = “world”;
try { / / Ініціалізували об’єкт Query2XML
$q2x = XML_Query2XML::factory(MDB2::factory(“mysql://root:pass@localhost/” . $db));
/ / Виконуємо запит SQL для отримання списку таблиць / / Примітки: цей запит буде різним для різних баз даних
$sql = “SHOW TABLES”;
$xml = $q2x->getXML($sql, array(
“idColumn” => false,
“rootTag” => “database”,
“rowTag” => “table”,
“attributes” => array(“name” => “tables_in_” . $db))
);
/ / Отримуємо список всіх вузлів

$nodelist = $xml->getElementsByTagName(“table”);
/ / Проходимо по кожному з вузлів
$x = 0;
while ($node = $nodelist->item($x)) { / / Витягаємо назва таблиці
$table = $node->attributes->getNamedItem(“name”)->nodeValue;
/ / Отримуємо опис таблиці / / У вигляді документа DOM / / Примітка: цей запит буде різним для різних баз даних
$sql_1 = “DESC ” . $table;
$schema = $q2x->getXML($sql_1, array (
“idColumn” => “field”,
“rowTag” => “define”,
“rootTag” => “schema”,
“elements” => array(“*”))
);
/ / Отримуємо вміст таблиці / / У вигляді іншого документа DOM
$sql_2 = “SELECT * FROM ” . $table;
$data = $q2x->getXML($sql_2, array (
“idColumn” => false,
“rowTag” => “record”,
“rootTag” => “data”,
“elements” => array(“*”))
);
/ / Проходимо по документу DOM $ schema / / Використовуємо XPath для отримання вузла і всіх дочірніх вузлів / / Імпортуємо його в основне дерево XML, у відповідний елемент

/ / Автор ідеї: Ігор Краус (Igor Kraus), http://www.php.net/simplexml
$xpath = new DOMXPath($schema);
$query = $xpath->query(“//schema”);
for ($i = 0; $i < $query->length; $i++) {
$xml->documentElement->childNodes->item($x)->appendChild(
$xml->importNode($query->item($i), true));
}
/ / Виконуємо ту ж операцію для документа DOM $ data
$xpath = new DOMXPath($data);
$query = $xpath->query(“//data”);
for ($i = 0; $i < $query->length; $i++) {
$xml->documentElement->childNodes->item($x)->appendChild(
$xml->importNode($query->item($i), true));
}
/ / Збільшуємо лічильник для наступного проходу
$x++;
}
/ / Записуємо результат на диск / / Виводимо повідомлення про успішне завершення або помилку
$xml->formatOutput = true;
if ($xml->save(“/tmp/dump.xml”)) {
echo “Data successfully saved!”;
} else {
echo “Data could not be saved!”;
}
} catch (Exception $e) {
echo $e->getMessage();
}
?>

Виглядає досить складно, але насправді все просто:



  1. По-перше, отримуємо назва всіх таблиць поточної бази даних. Вид запиту SQL для отримання цього списку буде різним для різних баз даних. У сценарії, наведеному в Лістингу 18, Використовується запит для MySQL SHOW TABLES, Але він не буде працювати в інших СУБД. Якщо ви використовуєте іншу систему баз даних, цей запит потрібно змінити. Результат виконання цієї команди у вигляді документа XML зберігається у змінній $xml і має вигляд, представлений в Лістингу 19:

    Лістинг 19. Результат XML, що формується програмної в лістингу 18 на першому етапі





    <?xml version=”1.0″ encoding=”UTF-8″?>
    <database>
    <table name=”City”/>
    <table name=”Country”/>
    <table name=”CountryLanguage”/>
    </database>


  2. Після цього отримуємо набір всіх елементів <table>, Створених на попередньому кроці, Викликаючи в циклі метод getElementsByTagName(). На кожному кроці циклу створюються два нових документа XML: $schema, В якому міститься інформація про структуру полів таблиці (дивись Лістинг 20), І $data, В якому зберігаються всі записи таблиці (дивись Лістинг 21):

    Лістинг 20. Документ XML, що містить схему таблиці





    <?xml version=”1.0″ encoding=”UTF-8″?>
    <schema>
    <define>
    <field>ID</field>
    <type>int(11)</type>
    <null>NO</null>
    <key>PRI</key>
    <default/>
    <extra>auto_increment</extra>
    </define>
    <define>
    <field>Name</field>
    <type>char(35)</type>
    <null>NO</null>
    <key/>
    <default/>
    <extra/>
    </define>
    <define>

    </define>
    </schema>

    Лістинг 21. Документ XML, що містить записи таблиці





    <?xml version=”1.0″ encoding=”UTF-8″?>
    <data>
    <record>
    <id>1</id>
    <name>Kabul</name>
    <countrycode>AFG</countrycode>
    <district>Kabol</district>
    <population>1780000</population>
    </record>
    <record>
    <id>2</id>
    <name>Qandahar</name>
    <countrycode>AFG</countrycode>
    <district>Qandahar</district>
    <population>237500</population>
    </record>
    <record>

    </record>
    </data>


  3. Продовжуючи ту ж ітерацію циклу, імпортуємо два незалежних документа XML, $schema і $data, В батьківський документ $xml. Як ви вже бачили з попередніх прикладів, XPath надає простий спосіб вилучення фрагментів вузла XML з $schema і $xml, Решта обробляє метод importNode() розширення DOM, вставляючи ці фрагменти у відповідну точку основного дерева XML.

    В Лістингу 22 наведено фрагмент кінцевого документа:


    Лістинг 22. Кінцевий документ XML, що формується програмою в лістингу 18





    <?xml version=”1.0″ encoding=”UTF-8″?>
    <database>
    <table name=”City”>
    <schema>
    <define>
    <field>ID</field>
    <type>int(11)</type>
    <null>NO</null>
    <key>PRI</key>
    <default/>
    <extra>auto_increment</extra>
    </define>
    <define>
    <field>Name</field>
    <type>char(35)</type>
    <null>NO</null>
    <key/>
    <default/>
    <extra/>
    </define>

    </schema>
    <data>
    <record>
    <id>1</id>
    <name>Kabul</name>
    <countrycode>AFG</countrycode>
    <district>Kabol</district>
    <population>1780000</population>
    </record>
    <record>
    <id>2</id>
    <name>Qandahar</name>
    <countrycode>AFG</countrycode>
    <district>Qandahar</district>
    <population>237500</population>
    </record>

    </data>
    </table>
    <table>

    </table>
    </database>


В Лістингу 23 представлено інше, більш елегантне рішення, запропоноване Лукасом Фейлером (Lukas Feiler), розробником класу XML_Query2XML:


Лістинг 23. Альтернативний спосіб формування дампа структури та вмісту бази даних в XML





<?php
ini_set(“max_execution_time”, 120);
/ / Автор: Lukas Feiler, http://www.lukasfeiler.com / / Включаємо файли
require_once “XML/Query2XML.php”;
require_once “MDB2.php”;
/ / Ініціалізували рівень абстракції MDB / / Завантажуємо диспетчер MDB
$mdb2 = MDB2::factory(“mysql://root:pass@localhost/world”);
$mdb2->loadModule(“Manager”);
/ / Ініціалізували об’єкт Query2XML
$q2x = XML_Query2XML::factory($mdb2);
/ / Отримуємо перелік таблиць
$tables = $mdb2->listTables();
/ / Динамічно створюємо масив $ options / / Для кожної таблиці
$elements = array();
for ($i=0; $i<count($tables); $i++) {
$elements[“table” . $i] = array(
“rowTag” => “table”,
“attributes” => array(
“name” => “:” . $tables[$i]
),
“elements” => array(
“record” => array(
“idColumn” => false,
“sql” => “SELECT * FROM ” . $tables[$i],
“elements” => array(
“*”
)
)
)
);
}
/ / Отримуємо дані з таблиць в XML
$xml = $q2x->getXML(
false,
array(
“idColumn” => false,
“rowTag” => “__tables”,
“rootTag” => “database”,
“elements” => $elements
)
);
/ / Записуємо результат на диск / / Виводимо повідомлення про успішне завершення або помилку
$xml->formatOutput = true;
if ($xml->save(“/tmp/dump.xml”)) {
echo “Data successfully saved!”;
} else {
echo “Data could not be saved!”;
}
?>

Це рішення спочатку завантажує модуль MDB2 Manager і за допомогою його методу listTables() отримує список всіх таблиць бази даних, незалежно від типу бази. Після цього воно проходить по списку таблиць і на кожній ітерації динамічно формує новий масив elements. Після обробки всіх таблиць виклик методу getXML() з динамічно створеним масивом elements, створює дамп всієї бази даних в форматі XML, який записується на диск. В Лістингу 24 показаний фрагмент вихідного файлу:


Лістинг 24. Документ XML, отриманий в результаті роботи програми з лістингу 23





<?xml version=”1.0″ encoding=”UTF-8″?>
<database>
<table name=”city”>
<record>
<id>1</id>
<name>Kabul</name>
<countrycode>AFG</countrycode>
<district>Kabol</district>
<population>1780000</population>
</record>
<record>
<id>2</id>
<name>Qandahar</name>
<countrycode>AFG</countrycode>
<district>Qandahar</district>
<population>237500</population>
</record>

</table>
<table name=”country”>
<record>
<code>AFG</code>
<name>Afghanistan</name>
<continent>Asia</continent>
<region>Southern and Central Asia</region>
<surfacearea>652090.00</surfacearea>
<indepyear>1919</indepyear>
<population>22720000</population>
<lifeexpectancy>45.9</lifeexpectancy>
<gnp>5976.00</gnp>
<gnpold/>
<localname>Afganistan/Afqanestan</localname>
<governmentform>Islamic Emirate</governmentform>
<headofstate>Mohammad Omar</headofstate>
<capital>1</capital>
<code2>AF</code2>
</record>

</table>
<table>

</table>
</database>

Висновок


Як видно з наведених раніше лістингів, можливості пакета XML_Query2XML значно ширше простого форматування безлічі даних SQL в XML. Він може служити основою для широкого спектру додатків, від простих конвертерів SQL в HTML до інструментів, які створюють складні документи XML з безлічі джерел даних, включаючи Web-сервіси, дискові файли і різні бази даних. Тому цей пакет буде цінним доповненням до інструментарію будь-якого розробника PHP. Спробуйте використовувати його в наступний раз, коли вам знадобиться інтерфейс між додатком PHP / XML і базою даних SQL, і переконайтеся в цьому самі!

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*