XRunner

2.2.2017 2:22

Библиотека XRunner

Библиотека XRunner (полное имя com/teacode/xrunner) содержит вспомогательные средства для работы с xml документами, представленными в формате стандартной библиотеки libretto/xml. Стандартная библиотека минимальна, и не содержит средств для управления xml документами.

Библиотека XRunner предлагает инструменты для поиска по xml документам, а также методы для "конвейерного" создания xml документов.

Поиск и выборки в xml документах

XRunner позволяет осуществлять поиск по xml документам, а также делать выборки элементов, удовлетворяющих условиям – в стиле, похожем на XPath.

Навигационные методы XRunner делятся на следующие типы:

  • e, ee: методы получения элементов – детей и потомков текущего элемента
  • a, keys – методы получения имен и значений атритутов текущего элемента
  • t, tt, i, r – методы получения и обработки текста, содержащегося в элементе и его потомках.

Пример. Определим

use com/teacode/xrunner as x

def catalog = 
<CATALOG>
  <PLANT>
    <COMMON lang="en">Bloodroot</COMMON>
    <COMMON lang="ru">Лапчатка</COMMON>
    <BOTANICAL>Sanguinaria canadensis</BOTANICAL>
    <ZONE>4</ZONE>
    <LIGHT>Mostly Shady</LIGHT>
    <PRICE>2.44</PRICE>
    <AVAILABILITY>031599</AVAILABILITY>
  </PLANT>
  <PLANT>
    <COMMON>Columbine</COMMON>
    <BOTANICAL>Aquilegia canadensis</BOTANICAL>
    <ZONE>3</ZONE>
    <LIGHT>Mostly Shady</LIGHT>
    <PRICE>9.37</PRICE>
    <AVAILABILITY>030699</AVAILABILITY>
  </PLANT>
  <PLANT>
    <COMMON lang="en">Marsh Marigold</COMMON>
    <COMMON lang="ru">Калужница болотная</COMMON>
    <BOTANICAL>Caltha palustris</BOTANICAL>
    <ZONE>4</ZONE>
    <LIGHT>Mostly Sunny</LIGHT>
    <PRICE>6.81</PRICE>
    <AVAILABILITY>051799</AVAILABILITY>
  </PLANT>
  <PLANT>
    <COMMON>Cowslip</COMMON>
    <BOTANICAL>Caltha palustris</BOTANICAL>
    <ZONE>4</ZONE>
    <LIGHT>Mostly Shady</LIGHT>
    <PRICE>9.90</PRICE>
    <AVAILABILITY>030699</AVAILABILITY>
  </PLANT>
</CATALOG>

Следующий запрос позволяет выбрать все названия на русском языке

def main = 
  catalog.x/e('PLANT).x/e('COMMON)?[x/a('lang)=='ru].x/t

Результат:
  (Лапчатка, Калужница болотная)

Более сложный запрос – для каждого растения с русским названием нужно указать его латинский эквивалент:

def main = 
  catalog.x/e('PLANT) as p.
    x/e('COMMON)?[x/a('lang)=='ru].
      <<%{x/t} имеет латинское название "%{p.x/e('BOTANICAL).x/t}">>!

Результат:
  (Лапчатка имеет латинское название "Sanguinaria canadensis",
  Калужница болотная имеет латинское название "Caltha palustris")

Еще запрос – просуммируем цены всех растений:

def sum(rrr:Real*) {
  var s = 0.0
  rrr as r. {s = s + r} 
  s
}

def main = catalog.x/ee('PRICE).x/r.*sum
Результат:
  28.52

Подробнее опишем навигационные методы.

a/1

def xml/Elem a(key: String!): String?

Получение значения атрибута у элемента. Пример использования:

use com/teacode/xrunner as x

def main = 
  <a href="http://hello.com">Hello, world</a>. x/a('href)
Результат:
  http://hello.com

e

def xml/Elem e:xml/Elem*

Получение всех элементов – детей текущего элемента. Пример:

use com/teacode/xrunner as x

def palindrom = 
  <a>А роза <b>упала </b><c><d>на</d> лапы </c>Азора</a>

def main = palindrom.x/e.name
Здесь name – поле структуры xml/Elem. Результат:
  (b, c)

e/1

def xml/Elem e(name:String!):xml/Elem*

Выборка всех элементов – детей текущего элемента с именем name.

use com/teacode/xrunner as x


def palindrom = 
  <a>А роза <b>упала </b><c><d>на</d> лапы </c>Азора</a>

def main = palindrom.x/e('b).x/t
Здесь name – поле структуры xml/Elem. Результат:
  упала 

ee

def xml/Elem ee: xml/Elem*

Получение всех элементов – потомков элемента из контекста (на любом уровне). Пример:

use com/teacode/xrunner as x

def palindrom = 
  <a>А роза <b>упала </b><c><d>на</d> лапы </c>Азора</a>

def main = palindrom.x/eе.name

Результат:

  (b,c,d)

ee/1

def xml/Elem ee(key:String!)*

use com/teacode/xrunner as x

def palindrom = 
  <a>А роза <b>упала </b><c><d>на</d> лапы </c>Азора</a>

def main = palindrom.x/ee('d).string

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

  <d>на</d>

keys

def xml/Elem keys:String*

Получение имен всех атрибутов элемента.

use com/teacode/xrunner as x

def main = 
  <a href="http://h.com" style="color:red">Hello, world</a>.x/keys

Результат:

  (href, style)

t

def xml/Elem t:String*

Получение текста, содержащегося непосредственно в элементе

use com/teacode/xrunner as x

def palindrom = 
  <a>А роза <b>упала </b><c><d>на</d> лапы </c>Азора</a>

def main = palindrom.x/t

Результат:

 (А роза , Азора)

tt

def xml/Elem tt:String*

use com/teacode/xrunner as x

def palindrom = 
  <a>А роза <b>упала </b><c><d>на</d> лапы </c>Азора</a>

def main = palindrom.x/tt

Получение текста, содержащегося в элементе и во всех его потомках.

Результат:

  (А роза ,упала ,на, лапы ,Азора)

i

def xml/Elem i:Int*

Нахождение в контенте элемента текстовых компонент, представляющих целые числа.

use com/teacode/xrunner as x

def main = <a>aaa<b/>111<c/>bbb<d/>222<e/>333</a>.x/i

Результат:

  (111,222,333)

r

def xml/Elem r:Real*

Нахождение в контенте элемента текстовых компонент, представляющих вещественные числа.

use com/teacode/xrunner as x

def main = <a>aaa<b/>11.1<c/>bbb<d/>222<e/>3.33</a>.x/r

Результат:

  (11.1,222,3.33)

Построение xml документов

Поскольку структуры библиотеки libretto/xml являются неизменяемыми, ими неудобно пользоваться при постепенном создании xml документов.

Структура Elem представляет xml элементы, Comment – комментарии. Текстовые элементы представляются обычными строками String. Объединяющая структура Content определяет тип контента для элементов:

struct Content = Elem | String | Comment

Пример использования:

use com/teacode/xrunner


def main = {
  fix hlink = 
    x/elem('a).
      addAttr('href, "http://hehe.com").
        add("Go to hehe")

  fix divelem = 
    x/elem('div).
      addAttr('style, "color:red").
        add("Hyper & link: ").
          add( hlink ).
            addComm(" Hlink to hehe ")
  
  println( divelem.string )

  divelem.x/toXML
}

Результат:

<div style="color:red">Hyper & link: <a href="http://hehe.com">Go to hehe</a><!-- Hlink to hehe --></div>

libretto/xml/Elem@348036810

Ниже описаны основные методы xml конструктора.

elem/1

def elem(name:String!):Elem!

Создание нового элемента с именем name.

name

def Elem name: String!

Получение имени элемента.

name/1

def Elem name(nm:String!):Elem!

Задание нового имени элементу.

contents

def Elem contents: Content*

Получение контента у элемента.

contents/1

def Elem contents(c: Content*):Elem!

Задание элементу нового контента.

add/1

def Elem add(x: Content*):Elem!

Добавление новых компонент в контент элемента.

addAttr/2

def Elem addAttr(key:String!, value:String?):Elem!

Добавление/удаление атрибута элемента. Атрибут удаляется, если value==().

addComm/1

def Elem addComm(text:String!):Elem!

Добавление комментария в контент элемента.

toXML

def Elem toXML: xml/Elem!

Перевод xml документа с корнем в текущем элементе в стандартный формат библиотеки libretto/xml.

string

def Elem string: String!

Перевод элемента в строковое представление.