Pull to refresh

Игры с XPath

Reading time 4 min
Views 29K


XML

XML — текстовый формат, предназначенный для хранения структурированных данных (взамен существующих файлов баз данных), для обмена информацией между программами, а также для создания на его основе более специализированных языков разметки (например, XHTML), иногда называемых словарями. XML является упрощённым подмножеством языка SGML.

XML это удобная штука хранить файлы в читаемом виде.

Например простой XML файл может быть таким

<?xml version="1.0" encoding="UTF-8"?>
<root>

 <data>

    <row>
         <id>1</id>
         <name company="ibm" status="banned" >Vasilii</name>
         <age>18</age>

    </row>

    <row>
          <id>2</id>
          <name company="ibm">Anton</name>
          <age>20</age>
    </row>
    <row>
          <id>3</id>
          <name company="apple">Petro</name>
          <age>35</age>
     </row>
 </data>

</root>

На данном файле будет показана работа с XPath.

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

Любой элемент имеет свой путь, например путь root-data-row[0] будет указывать на ветку Василия.

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

Что делать?

Решением данной проблемы является XPath.

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

Итак, есть документ.

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

Есть код:
$xml = simplexml_load_file("db.xml");
var_dump($xml);

Результат будет следующий:
object(SimpleXMLElement)[1]
  public 'data' =>
    object(SimpleXMLElement)[2]
      public 'row' =>
        array
          0 =>
            object(SimpleXMLElement)[3]
              public 'id' => string '1' (length=1)
              public 'name' => string 'Vasilii' (length=7)
              public 'age' => string '18' (length=2)
          1 =>
            object(SimpleXMLElement)[4]
              public 'id' => string '2' (length=1)
              public 'name' => string 'Anton' (length=5)
              public 'age' => string '20' (length=2)
          2 =>
            object(SimpleXMLElement)[5]
              public 'id' => string '3' (length=1)
              public 'name' => string 'Petro' (length=5)
              public 'age' => string '35' (length=2)

Как видно из результата доступ можно делать как: $xml->data->row[0]->name == Valilii.

Теперь собственно XPath.

XPath позволяет использовать условия и свои встроенные функции для выборки веток.

Например / (слеш) — указывает на иерархию веток, например /data,

Основные моменты при использовании:

/ — корневой узел

// — множество узлов удовлетворяющих след условие (детальнее на вики)

* — любые символы

@ — аттрибут

[] — аналог () в sql, задает условия

and, or — И, ИЛИ.

Более подробно написано ru.wikipedia.org/wiki/XPath

Сделаем выборку всех элементов с помощью XPath.

foreach( $xml->xpath("//row") as $res) var_dump($res);

object(SimpleXMLElement)[6]
  public 'id' => string '1' (length=1)
  public 'name' => string 'Vasilii' (length=7)
  public 'age' => string '18' (length=2)

object(SimpleXMLElement)[7]
  public 'id' => string '2' (length=1)
  public 'name' => string 'Anton' (length=5)
  public 'age' => string '20' (length=2)

object(SimpleXMLElement)[8]
  public 'id' => string '3' (length=1)
  public 'name' => string 'Petro' (length=5)
  public 'age' => string '35' (length=2)


Давайте сделаем выборку, где age>18
foreach( $xml->xpath("//row[age>18]") as $res) var_dump($res);

Результат:
object(SimpleXMLElement)[6]
  public 'id' => string '2' (length=1)
  public 'name' => string 'Anton' (length=5)
  public 'age' => string '20' (length=2)

object(SimpleXMLElement)[7]
  public 'id' => string '3' (length=1)
  public 'name' => string 'Petro' (length=5)
  public 'age' => string '35' (length=2)


Сделаем выборку у всех у которых аттрибут company='ibm'
foreach( $xml->xpath("//row[name[@company='ibm']]") as $res) var_dump($res);

Результат:
object(SimpleXMLElement)[6]
  public 'id' => string '1' (length=1)
  public 'name' => string 'Vasilii' (length=7)
  public 'age' => string '18' (length=2)

object(SimpleXMLElement)[7]
  public 'id' => string '2' (length=1)
  public 'name' => string 'Anton' (length=5)
  public 'age' => string '20' (length=2)

Следует обратить внимание, что атрибут @company является частью name, по этому просто написать row[ @company=..] — нельзя.

Сделаем выборку людей, у которых возраст больше 18 и работает в IBM
foreach($xml->xpath("//row[name[@company='ibm'] and age>18]") as $res) var_dump($res);

Результат:
object(SimpleXMLElement)[6]
  public 'id' => string '2' (length=1)
  public 'name' => string 'Anton' (length=5)
  public 'age' => string '20' (length=2)


Можно увидеть что комбинировать очень просто.
Следующий пример покажет как можно использовать встроенные функции, например
last() — получим последнего человека списка.
foreach($xml->xpath("//row[last()]") as $res) var_dump($res);

Результат:
object(SimpleXMLElement)[6]
  public 'id' => string '3' (length=1)
  public 'name' => string 'Petro' (length=5)
  public 'age' => string '35' (length=2)


А теперь найдем людей которые НЕ работают в IBM:
foreach( $xml->xpath("//row[name[not(@company='ibm')]]") as $res) var_dump($res);

Результат:
object(SimpleXMLElement)[6]
  public 'id' => string '3' (length=1)
  public 'name' => string 'Petro' (length=5)
  public 'age' => string '35' (length=2)


Все очень просто и удобно!

Результаты


Xpath — хороший инструмент для работы с документом XML. Базовые функции выполняет.
Для более сложных есть XQuery, но речь сейчас не об этом.

XML+XPath достойная замена в тех местах, где неудобно использовать БД по каким либо причинам.

Спасибо.
Продолжение следует.


Первоисточник
Tags:
Hubs:
+4
Comments 23
Comments Comments 23

Articles