|
1 | 1 | Обработка XML документов
|
2 | 2 | ========================
|
3 |
| -`Data Source`_ |
| 3 | +`Data Source`_ `Eng Data Source`_ |
4 | 4 |
|
5 |
| -... |
| 5 | +``XML`` - удобный формат описания данных, который строится по древовидной структуре. Каждый элемент может содержать |
| 6 | +значение и/или другие элементы. Текст внутри элемента может чередоваться с дочерними элементами, но он всё равно будет |
| 7 | +расценен как единое значение. Кроме того, у каждого элемента могут быть заданы атрибуты. Всё выше описанное отражено в |
| 8 | +ниже приведённом примере (пусть это будет файл ``sample.xml``): |
| 9 | + |
| 10 | +.. code:: xml |
| 11 | +
|
| 12 | + <?xml version="1.0" encoding="utf-8"?> |
| 13 | + <our_document> |
| 14 | + <some_tag> |
| 15 | + Some tag's content. |
| 16 | + </some_tag> |
| 17 | + <planet_earth> |
| 18 | + <continent id="1"> |
| 19 | + North America |
| 20 | + <country id="1"> |
| 21 | + Canada |
| 22 | + </country> |
| 23 | + <country id="2"> |
| 24 | + USA |
| 25 | + </country> |
| 26 | + </continent> |
| 27 | + <continent id="2"> |
| 28 | + Europe |
| 29 | + <country id="1"> |
| 30 | + Estonia |
| 31 | + </country> |
| 32 | + <country id="2"> |
| 33 | + Latvia |
| 34 | + </country> |
| 35 | + <country id="3"> |
| 36 | + Lithuania |
| 37 | + </country> |
| 38 | + </continent> |
| 39 | + </planet_earth> |
| 40 | + </our_document> |
| 41 | +
|
| 42 | +.. _блок_cdata: |
| 43 | + |
| 44 | +Блок CDATA |
| 45 | +---------- |
| 46 | + |
| 47 | +Если требуется указать в качестве содержания одного из элементов символы, которые могут помешать корректной разборке |
| 48 | +XML документа, то нужно содержание элемента заключать в блок CDATA. К ряду символов таких символов относятся символы |
| 49 | +``>``, ``<`` и ``&``. Синтаксис блока ``CDATA`` выглядит следующим образом: |
| 50 | + |
| 51 | +.. code:: xml |
| 52 | +
|
| 53 | + <![CDATA[Some symbolic data, that > breaks & xml]]> |
| 54 | +
|
| 55 | +Данные внутри блока ``CDATA`` не должны содержать последовательность ``]]>``, т.к. она будет воспринята как окончание |
| 56 | +данного блока. Если задание такой последовательности символов необходимо, следует воспользоваться следующим подходом: |
| 57 | + |
| 58 | +.. code:: xml |
| 59 | +
|
| 60 | + <![CDATA[]]]]><![CDATA[>]]> |
| 61 | +
|
| 62 | +В выше приведённом примере данные разбиты на два фрагмента и каждый из них заключён в свой блок ``CDATA``. Особенно |
| 63 | +удобно применение ``CDATA`` в случае, когда нужно написать ``XML``, который будет показан пользователю, но не обработан |
| 64 | +при разборке XML документа. |
| 65 | + |
| 66 | +Получение XML документа |
| 67 | +----------------------- |
| 68 | + |
| 69 | +Перед тем, как разбирать ``XML`` документ, содержащийся в файле, его нужно сначала прочитать. |
| 70 | + |
| 71 | +Получение локального файла |
| 72 | +^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 73 | + |
| 74 | +Для получения локального файла (т.е. находящегося на том-же компьютере, что и сам сайт) следует использовать |
| 75 | +стандартную функцию `file_get_contents <https://www.php.net/file_get_contents>`__. |
| 76 | +Данная функция возвращает содержание файла, путь к которому передан в качестве первого её аргумента. |
| 77 | + |
| 78 | +.. code:: php |
| 79 | +
|
| 80 | + $file_contents = file_get_contents(WRITEABLE . '/user_files/sample.xml'); |
| 81 | +
|
| 82 | +Получение удалённого файла |
| 83 | +^^^^^^^^^^^^^^^^^^^^^^^^^^ |
| 84 | + |
| 85 | +Функция `file_get_contents <https://www.php.net/file_get_contents>`__ также позволяет |
| 86 | +получать содержимое файлов, находящихся на удалённых ресурсах. Однако, в целях безопасности, на сервере может быть |
| 87 | +запрещена эта возможность. Поэтому настоятельно рекомендуется получать удалённый файл при помощи стандартного класса |
| 88 | +K4 - ``kCurlHelper``. |
| 89 | + |
| 90 | +.. code:: php |
| 91 | +
|
| 92 | + $curl_helper =& $this->Application->recallObject('CurlHelper'); |
| 93 | + /* @var $curl_helper kCurlHelper */ |
| 94 | +
|
| 95 | + $xml_data = $curl_helper->Send('http://sample-host.com/sample.xml'); |
| 96 | +
|
| 97 | +У метода ``Send`` также есть второй необязательный параметр, который указывает на то, что нужно закрывать соединение |
| 98 | +сразу после получения содержания документа. По умолчанию он равен ``true``, т.е. закрывать соединение. |
| 99 | + |
| 100 | +Разборка XML документа |
| 101 | +---------------------- |
| 102 | + |
| 103 | +В классе ``kXMLHelper`` реализован удобный механизм разбора XML документа. Сначала следует создать экземпляр класса. |
| 104 | + |
| 105 | +.. code:: php |
| 106 | +
|
| 107 | + $xml_helper =& $this->Application->recallObject('kXMLHelper'); |
| 108 | + /* @var $xml_helper kXMLHelper */ |
| 109 | +
|
| 110 | +Далее, начать обработку полученного ранее XML документа. |
| 111 | + |
| 112 | +.. code:: php |
| 113 | +
|
| 114 | + $root_node =& $xml_helper->Parse($file_contents); |
| 115 | +
|
| 116 | +В результате будет возвращена древовидная структура объектов, в которой все объекты связаны при помощи ссылок. |
| 117 | +Содержимое каждого объекта класса ``kXMLNode`` выглядит так: |
| 118 | + |
| 119 | +.. code:: php |
| 120 | +
|
| 121 | + kxmlnode Object ( |
| 122 | + [Name] => xml_element_name |
| 123 | + [Attributes] => Array |
| 124 | + ( |
| 125 | + [1st_attribute_name] => 1st_attribute_value |
| 126 | + [2nd_attribute_name] => 2nd_attribute_value |
| 127 | + ... |
| 128 | + ) |
| 129 | + [Children] => Array |
| 130 | + ( |
| 131 | + [0] => kxmlnode Object |
| 132 | + [1] => kxmlnode Object |
| 133 | + ... |
| 134 | + ) |
| 135 | + [Data] => text_value_that_this_XML_element_encapsulates |
| 136 | + [firstChild] => kxmlnode Object |
| 137 | + [lastChild] => kxmlnode Object |
| 138 | + [Parent] => kxmlnode Object |
| 139 | + [Position] => 1 |
| 140 | + ) |
| 141 | +
|
| 142 | +.. note:: |
| 143 | + |
| 144 | + Всё ниже приведённое описание содержания объекта класса kXMLNode будет основано на примере, приведённом в |
| 145 | + начале статьи. |
| 146 | + |
| 147 | +Переменной ``$root_node`` будет присвоен родительский (root) объект, т.е. это объект xml-элемента ``our_document``. |
| 148 | +Атрибут ``Children`` (private) содержит массив всех дочерних элементов текущего элемента. В данном примере ими |
| 149 | +являются два элемента - ``some_tag`` и ``planet_earth``. У последнего - два дочерних элемента ``continent``. Важно |
| 150 | +понимать, что элементы массива - точно такие же объекты, как и текущий. У них, в свою очередь, могут быть свои дочерние |
| 151 | +элементы, и так далее. |
| 152 | + |
| 153 | +У каждого элемента есть атрибут ``Position``. Это - порядковый номер элемента среди соседних элементов (элементов того |
| 154 | +же уровня, например - "country" Canada и "country" USA). Атрибуты ``firstChild`` и ``lastChild`` содержат первый и |
| 155 | +последний (с точки зрения его ``Position``) дочерний элемент соответственно. |
| 156 | + |
| 157 | +Для последующей обработки полученной информации используется методы и атрибуты именно класса ``kXMLNode``. |
| 158 | + |
| 159 | +Практическое использование kXMLHelper |
| 160 | +------------------------------------- |
| 161 | + |
| 162 | +Ниже приведён код, который распечатает все страны описанного выше XML-документа. |
| 163 | + |
| 164 | +.. code:: php |
| 165 | +
|
| 166 | + $root_node =& $xml_helper->Parse($xml_data); |
| 167 | + /* @var $root_node kXMLNode */ |
| 168 | +
|
| 169 | + // Getting first continent node |
| 170 | + $continent_node =& $root_node->FindChild('continent'); |
| 171 | +
|
| 172 | + // Cycling through it and all the rest continent nodes |
| 173 | + do { |
| 174 | + // Getting first country node |
| 175 | + $country_node =& $continent_node->firstChild; |
| 176 | +
|
| 177 | + // Cycling through it and all the rest continent nodes |
| 178 | + do { |
| 179 | + echo $continent_node->Attributes['ID'] . ' - ' . trim($continent_node->Data) . ': ' . $country_node->Attributes['ID'] . ' - ' . trim($country_node->Data) . '<br/>'; |
| 180 | + } while ($country_node =& $country_node->NextSibling()); |
| 181 | + } while ($continent_node =& $continent_node->NextSibling()); |
| 182 | +
|
| 183 | +В переменной ``$continent_node`` сохраняется первый найденный объект ``continent``, т.е. - ``North America``. В |
| 184 | +первом цикле перебираются континенты. Для перехода к элементу того же уровня используется метод ``NextSibling`` |
| 185 | +(есть противоположный ему метод ``PrevSibling``). Из континента выбирается первая страна. Внутренний цикл перебирает |
| 186 | +все страны данного континента и делает вывод в приведённом ниже формате. Как можно заметить, текстовое значение |
| 187 | +элементов доступно через атрибут ``Data``. |
| 188 | + |
| 189 | +- ``1 - North America: 1 - Canada`` |
| 190 | +- ``1 - North America: 2 - USA`` |
| 191 | +- ``2 - Europe: 1 - Estonia`` |
| 192 | +- ``2 - Europe: 2 - Latvia`` |
| 193 | +- ``2 - Europe: 3 - Lithuania`` |
| 194 | + |
| 195 | +Методы класса "kXMLNode" |
| 196 | +------------------------ |
| 197 | + |
| 198 | +Ниже приведены public методы класса ``kXMLNode``. Все методы рассчитаны на чтение данных, но не на их запись. |
| 199 | + |
| 200 | ++---------------------------------------+------------------------------------------------------------------------------+ |
| 201 | +| метод | описание | |
| 202 | ++=======================================+==============================================================================+ |
| 203 | +| ``&FindChild($name)`` | Возвращает первый встретившийся элемент-потомок с указанным именем. Работает | |
| 204 | +| | рекурсивно, до самого последнего уровня. | |
| 205 | ++---------------------------------------+------------------------------------------------------------------------------+ |
| 206 | +| ``FindChildValue($name, $attr=null)`` | Возвращает либо значение элемента-потомка (если задано только его имя), либо | |
| 207 | +| | один из атрибутов (если явно указан). | |
| 208 | ++---------------------------------------+------------------------------------------------------------------------------+ |
| 209 | +| ``&GetChildByPosition($position)`` | Возвращает дочерний элемент, который находится по указанной позиции. | |
| 210 | ++---------------------------------------+------------------------------------------------------------------------------+ |
| 211 | +| ``GetXML()`` | Генерирует и возвращает XML-документ, построенный от текущего элемента. | |
| 212 | +| | Актуально при предыдущем изменении структуры и не только. | |
| 213 | ++---------------------------------------+------------------------------------------------------------------------------+ |
6 | 214 |
|
7 | 215 | .. _Data Source: http://guide.in-portal.org/rus/index.php/K4:%D0%9E%D0%B1%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%BA%D0%B0_XML_%D0%B4%D0%BE%D0%BA%D1%83%D0%BC%D0%B5%D0%BD%D1%82%D0%BE%D0%B2
|
| 216 | +.. _Eng Data Source: http://guide.in-portal.org/eng/index.php/K4:KXMLHelper |
0 commit comments