к библиотеке   к оглавлению   Банки данных Интернет   визуальные среды - 4GL   технологии программирования

Отображение XML-документа на Web-странице

Понятие о связывании данных

Метод связывания данных сводится к установке связи XML-документа с HTML-страницей, а также сцеплению элементов HTML с XML-элементами. В результате HTML-элементы автоматически отображают содержимое XML-элементов, с которыми они сцеплены. В этом случае при открытии HTML-страницы встроенный в Internet Explorer XML-процессор синтаксически анализирует XML-документ. При этом Internet Explorer создаёт программный объект, который носит название "Объект исходных данных" (Data Source Object, DSO). Объект DSO хранит данные XML и обеспечивает доступ к ним. DSO позволяет осуществлять доступ и манипулирование XML-данными посредством ряда методов, свойств и событий.

Если вы открываете XML-документ описанным выше способом (через HTML-страницу), Internet Explorer проверяет, является ли документ корректно сформированным, а также, если документ включает объявление типа документа - является ли документ валидным. Если документ содержит ошибку (не является валидным), Internet Explorer просто не будет отображать данные XML, не выводя сообщение об ошибке. Если документ содержит DTD (объявление типа документа), вы должны исчерпывающе описать все возможные элементы (спецификацию содержимого "ANY" использовать нельзя).

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

Основные шаги при связывании данных:

  1. Установка связи XML-документа с HTML-страницей, на которой вы хотите отобразить данные XML. Этот шаг реализуется включением HTML-элемента с именем XML в HTML-страницу:

    <XML ID="dsoPRODUCTS" SRC="Products.xml"></XML>

  2. Сцепление HTML-элементов с XML-элементами, например:

    <SPAN DATASRC="#dsoPRODUCTS" DATAFLD="PRODUCT"></SPAN>

HTML-элемент с именем XML называется фрагментом данных. Весь текст XML-документа в принципе может быть помещён между начальным и конечным тэгами XML:

<XML ID="dsoPRODUCTS">
    <?xml version="1.0"?>
    <PRODUCTS>
        <PRODUCT>
            <TITLE> Prod#1 </TITLE>
            <PRICE> 10.00 </PRICE>
        </PRODUCT>
        <PRODUCT>
            <TITLE> Prod#2 </TITLE>
            <PRICE> 20.00 </PRICE>
        </PRODUCT>
    </PRODUCTS>
</XML>


Однако согласно идеологии XML собственно данные (XML-документ) должны храниться отдельно от информации по их форматированию и обработке. Поэтому как правило HTML-элемент с именем XML (фрагмент данных) остаётся пустым и содержит только идентификатор объекта DSO и URL XML-документа, который находится в отдельном файле. Идентификатор фрагмента данных (атрибут ID) используется для доступа к XML-документу с HTML-страницы и должен быть уникальным.

Сцепление HTML-элементов с XML-элементами осуществляется двумя основными способами:

Табличное сцепление данных

При табличном сцеплении Internet Explorer берёт на себя бóльшую часть работы. Вам не нужно писать сценарии. Только если вы выбрали режим пролистывания, вам потребуется включить несколько вызовов простых функций. Кроме того, вы можете использовать вложенные HTML-таблицы для отображения XML-документа, содержащего иерархический набор записей.

Если данные XML-документа организованы в виде простого набора записей, т.е. если корневой элемент содержит множество элементов ("записей"), каждый из которых содержит одинаковый набор элементов ("полей"), а каждое "поле" содержит уже только символьные данные, вы можете использовать один единственный HTML-элемент TABLE для отображения XML-документа. Пример такого XML-документа:

<?xml version="1.0"?>
<PRODUCTS>
    <PRODUCT>
        <TITLE> Product #1 </TITLE>
        <PRICE> $10.00 </PRICE>
    </PRODUCT>
    <PRODUCT>
        <TITLE> Product #2 </TITLE>
        <PRICE> $20.00 </PRICE>
    </PRODUCT>
    <PRODUCT>
        <TITLE> Product #3 </TITLE>
        <PRICE> $30.00 </PRICE>
    </PRODUCT>
    <PRODUCT>
        <TITLE> Product #4 </TITLE>
        <PRICE> $40.00 </PRICE>
    </PRODUCT>
    <PRODUCT>
        <TITLE> Product #5 </TITLE>
        <PRICE> $50.00 </PRICE>
    </PRODUCT>
</PRODUCTS>

Когда вы связываете HTML-таблицу с таким XML-документом, данные каждой "записи" отображаются в отдельной строке таблицы, а данные каждого "поля" - в отдельном столбце. Чтобы произвести такое связывание, вам необходимо указать на HTML-странице фрагмент данных (тэг XML), в тэге TABLE указать значение атрибута DATASRC, а в каждую ячейку таблицы (тэг TD) поместить элемент SPAN, в котором указать атрибут DATAFLD. Вложенный элемент SPAN в данном случае необходим просто потому, что сам элемент TD не является связываемым HTML-элементом (задание в нём атрибута DATAFLD ничего не даст). При этом в HTML-таблице достаточно определить одну строку - браузер сам проделает остальную работу (повторит строковый элемент для каждой "записи" в XML-документе). Вот текст этого HTML-документа:

<html>
<head>
<script for="window" event="onload">
doc=dsoPRODUCTS.XMLDocument;
if(doc.readyState == 4) DisplayError();
else doc.onreadystatechange = DisplayError;
function DisplayError(){
    if(doc.readyState != 4) return;
    if(doc.parseError.errorCode){
        mess =
        "parseError.errorCode: " + doc.parseError.errorCode + "\n" +
        "parseError.filepos: " + doc.parseError.filepos + "\n" +
        "parseError.line: " + doc.parseError.line + "\n" +
        "parseError.linepos: " + doc.parseError.linepos + "\n" +
        "parseError.reason: " + doc.parseError.reason + "\n" +
        "parseError.srcText: " + doc.parseError.srcText + "\n" +
        "parseError.url: " + doc.parseError.url + "\n" +
        "";
        alert(mess);
    }
}
</script>
</head>
<body>
<XML ID="dsoPRODUCTS" SRC="Sample.xml"></XML>
<TABLE ID="ProductsTable" DATASRC="#dsoPRODUCTS" border="1" width="100%" cellspacing="0">
<TR><TD><SPAN DATAFLD="TITLE"></SPAN></TD><TD><SPAN DATAFLD="PRICE"></SPAN></TD></TR>
</TABLE>
</body>
</html>

Скрипт на этой HTML-странице запускает функцию DisplayError в тот момент, когда XML-документ оказывается полностью загруженным, и отображает подробное сообщение об ошибке в случае, если XML-документ не прошёл проверку на валидность (применение такого скрипта имеет смысл, если XML-документ содержит DTD).

Вы можете использовать постраничный вывод записей вместо отображения всех записей одновременно в огромной таблице. Для этого вам придётся внести некоторые изменения в приведённый выше HTML-документ:

Приведённые выше методы не имеют аргументов. Если в настоящий момент отображена первая страница, вызов метода previousPage игнорируется, а если отображена последняя страница, игнорируется вызов nextPage.

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

<?xml version="1.0"?>
<PRODUCTS>
    <PRODUCT>
        <TITLE> Product #1 </TITLE>
        <SORT>
            <COLOR> red </COLOR>
            <PRICE> $10.00 </PRICE>
        </SORT>
        <SORT>
            <COLOR> blue </COLOR>
            <PRICE> $11.00 </PRICE>
        </SORT>
        <SORT>
            <COLOR> gray </COLOR>
            <PRICE> $16.00 </PRICE>
        </SORT>
    </PRODUCT>
    <PRODUCT>
        <TITLE> Product #2 </TITLE>
        <SORT>
            <COLOR> red </COLOR>
            <PRICE> $20.00 </PRICE>
        </SORT>
        <SORT>
            <COLOR> blue </COLOR>
            <PRICE> $22.00 </PRICE>
        </SORT>
    </PRODUCT>
    <PRODUCT>
        <TITLE> Product #3 </TITLE>
        <SORT>
            <COLOR> red </COLOR>
            <PRICE> $30.00 </PRICE>
        </SORT>
        <SORT>
            <COLOR> blue </COLOR>
            <PRICE> $33.00 </PRICE>
        </SORT>
    </PRODUCT>
    <PRODUCT>
        <TITLE> Product #4 </TITLE>
        <SORT>
            <COLOR> red </COLOR>
            <PRICE> $40.00 </PRICE>
        </SORT>
        <SORT>
            <COLOR> blue </COLOR>
            <PRICE> $44.00 </PRICE>
        </SORT>
    </PRODUCT>
    <PRODUCT>
        <TITLE> Product #5 </TITLE>
        <SORT>
            <COLOR> red </COLOR>
            <PRICE> $50.00 </PRICE>
        </SORT>
        <SORT>
            <COLOR> blue </COLOR>
            <PRICE> $55.00 </PRICE>
        </SORT>
    </PRODUCT>
</PRODUCTS>

Две вложенные HTML-таблицы, которые отобразят вышеприведённый XML-документ, будут выглядеть следующим образом:

<XML ID="dsoPRODUCTS" SRC="Sample.xml"></XML>
<TABLE ID="ProductsTable" DATASRC="#dsoPRODUCTS" border="1" width="100%" cellspacing="0">
<TR>
<TD colspan="2"><SPAN DATAFLD="TITLE"></SPAN></TD>
</TR>

<TR>
<TD colspan="2">

<TABLE DATASRC="#dsoPRODUCTS" DATAFLD="SORT" border="0" width="100%" cellspacing="0">
<TR><TD>&nbsp;&nbsp;&nbsp;<SPAN DATAFLD="COLOR"></SPAN></TD><TD><SPAN DATAFLD="PRICE"></SPAN></TD></TR>
</TABLE>

</TD>
</TR>

</TABLE>

Внешняя таблица сцеплена с XML-документом с помощью атрибута DATASRC. Внешняя таблица имеет две строки: в первой отображается элемент TITLE, а вторая строка содержит вложенную таблицу для отображения содержимого элемента SORT. Вложенная таблица также сцеплена с XML-документом с помощью атрибута DATASRC, и сцеплена дополнительно с элементом SORT с помощью атрибута DATAFLD. Вложенная таблица имеет одну строку, в которой отображаются элементы COLOR и PRICE. Таким образом, внешняя таблица при отображении браузером будет иметь количество строк, соответствующее количеству элементов верхнего уровня (т.е. элементов PRODUCT), а именно - по две строки на каждый PRODUCT (поскольку в коде таблицы определено две строки). Вложенная таблица при отображении браузером будет иметь количество строк, равное количеству элементов SORT у текущего элемента PRODUCT.

Уровней вложенности в HTML-таблицах может быть больше, чем в вышеприведённом примере. Кроме того, никто не запрещает вам использовать методику постраничного отображения данных вместе с вложенными таблицами.

Связывание данных по одной записи

Связывание данных по одной записи используется для HTML-элементов, которые не являются таблицами и не включены в связанную таблицу. Например, следующий элемент SPAN сцеплён с полем TITLE XML-документа, доступ к которому осуществляется через фрагмент данных dsoPRODUCTS:

<SPAN DATASRC="#dsoPRODUCTS" DATAFLD="TITLE"></SPAN>

Поскольку такой HTML-элемент не имеет множественных частей, подобно таблице, он способен отобразить значение поля только для одной записи за раз. Отображаемая в данный момент запись называется текущей записью. Связывание данных по одной записи иногда называют связыванием по текущей записи. DSO (объект исходных данных), ассоциированный с XML-документом, предоставляет ряд свойств и методов, которыми вы можете воспользоваться при перемещении между записями. Эти методы и свойства принадлежат объекту recordset DSO, который соответствует стандарту технологии доступа к данным ADO (ActiveX Data Objects):

moveFirst()Переход к первой записи в документе.
moveLast()Переход к последней записи в документе.
movePrevious()Переход к предыдущей записи в документе. Если текущей является первая запись, вызов метода приведёт к зоне начала файла (BOF) и сцеплённый элемент будет пуст.
moveNext()Переход к следующей записи в документе. Если текущей является последняя запись, вызов метода приведёт к зоне конца файла (EOF) и сцеплённый элемент будет пуст.
move(i)Переход с шагом на указанное число записей в документе. Записи нумеруются, начиная с нуля.
BOFПринимает значение true (истина), если достигнуто начало файла.
EOFПринимает значение true (истина), если достигнут конец файла.

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

<XML ID="dsoPRODUCTS" SRC="Sample.xml"></XML>

<h1><SPAN DATASRC="#dsoPRODUCTS" DATAFLD="TITLE"></SPAN></h1>

<TABLE ID="ProductsTable" DATASRC="#dsoPRODUCTS" DATAFLD="SORT" border="1" width="100%" cellspacing="0">
<TR>
<TD><SPAN DATAFLD="COLOR"></SPAN></TD>
<TD><SPAN DATAFLD="PRICE"></SPAN></TD>
</TR>
</TABLE>
<br>
<button onclick="dsoPRODUCTS.recordset.moveFirst()">К началу</button>
<button onclick="dsoPRODUCTS.recordset.movePrevious();
    if(dsoPRODUCTS.recordset.BOF)dsoPRODUCTS.recordset.moveNext()">Назад</button>
<button onclick="dsoPRODUCTS.recordset.moveNext();
    if(dsoPRODUCTS.recordset.EOF)dsoPRODUCTS.recordset.movePrevious()">Вперёд</button>
<button onclick="dsoPRODUCTS.recordset.moveLast()">В конец</button>

Связывание данных с различными HTML-элементами, передача HTML-разметки, обновление данных XML

Вот перечень HTML-элементов, которые вы можете использовать для связывания данных по одной записи - т.е., все сцепляемые HTML-элементы, за исключением элемента TABLE:

HTML-элементСцепляемые свойстваПередача разметки HTMLОбновление XML
AhrefНетНет
APPLETparamНетДа
BUTTONinnerHTML
innerText
ДаНет
DIVinnerHTML
innerText
ДаНет
FRAMEsrcНетНет
IFRAMEsrcНетНет
IMGsrcНетНет
INPUT
type=checkbox
checkedНетДа
INPUT
type=hidden
valueНетДа
INPUT
type=password
valueНетДа
INPUT
type=radio
checkedНетДа
INPUT
type=text
valueНетДа
LABELinnerHTML
innerText
ДаНет
MARQUEEinnerHTML
innerText
ДаНет
SELECTtextНетДа
SPANinnerHTML
innerText
ДаНет
TEXTAREAvalueНетДа

Например, для элемента SPAN свойство innerText получает текстовое содержимое XML-элемента, не включая в него HTML-разметку. Свойство innerHTML получает полное содержимое, включая HTML-разметку. Для других сцепляемых HTML-элементов с полем XML могут сцепляться другие свойства. Например, для сцеплённого элемента A (анкер) из поля XML извлекается URL гиперссылки, а для флажка INPUT - булево значение свойства checked. В случае с флажком, если XML-поле пусто, содержит текст "0" или "false", поле флажка очищается. Если XML-поле содержит любой другой текст, флажок устанавливается.

По умолчанию, если символьные данные XML-поля включают HTML-разметку, HTML-элемент, сцеплённый с этим полем, отображает символы разметки как литерал. Для некоторых сцепляемых HTML-элементов вы можете установить для атрибута DATAFORMATAS значение "HTML", что заставит браузер обрабатывать любую HTML-разметку, включённую в текст поля. Присвоение атрибуту DATAFORMATAS значения по умолчанию - "TEXT" - даёт тот же эффект, что и пропуск этого атрибута. Возможность установки атрибута DATAFORMATAS для тех или иных HTML-элементов отражена в приведённой выше таблице в колонке "Передача разметки HTML". Вставка и передача HTML-разметки в XML-поля бывает удобна для изменения формата части текста и для включения в текст гиперссылок и изображений.

Объект DSO XML даёт возможность модифицировать данные XML. Однако, при этом модифицируется только копия данных XML, которую DSO временно хранит в памяти, а не оригинальный XML-документ на сервере. Если вы не используете какие-либо способы обновления оригинального XML-документа на сервере (в данной статье эти способы не рассматриваются), такая модификация несёт мало пользы. Вы можете разрешить пользователю модифицировать определённое XML-поле, сцепив его с HTML-элементом, допускающим обновление. Возможность обновления данных XML для тех или иных HTML-элементов отражена в приведённой выше таблице в колонке "Обновление XML". Кроме того, объект DSO предоставляет некоторые методы для модификации данных, которые можно использовать в скриптах на HTML-странице:

addNew()Добавляет новую запись.
delete()Удаляет текущую запись.
cancelUpdate()Возвращает любые изменения, сделанные для полей текущей записи, или удаляет только что введённую запись.

Связывание HTML-элементов с XML-атрибутами

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

Чтобы иметь возможность отобразить как символьные данные, так и атрибут элемента, DSO использует специальное имя $TEXT для обращения ко всем символьным данным элемента, исключая атрибуты элемента. При связывании данных "$TEXT" можно использовать как обычное имя поля. Например, XML-элемент

<PRODUCT Price="10.00">Product #1</PRODUCT>

будет при разборе эквивалентен элементу

<PRODUCT>
    <Price>10.00</Price>
    <$TEXT>Product #1</$TEXT>
</PRODUCT>

Использование сценариев для DSO

Объект recordset DSO может быть использован для написания довольно функциональных скриптов, обращающихся к XML-данным. Напишем HTML-страницу, которая будет осуществлять поиск данных в связанном XML-документе по вхождению указанной пользователем строки и отображать результаты поиска. Поиск будем производить в XML-документе, приведённом выше в этой статье, а именно - в XML-документе, который мы отображали с помощью вложенных HTML-таблиц. Будем разыскивать товары, у которых есть сорт того цвета, который указал пользователь. Вот текст HTML-документа:

<XML ID="dsoPRODUCTS" SRC="Sample.xml"></XML>
Color: <input type="text" id="SearchText"> <button onclick="FindProducts()">Search</button>
<hr>
Results:<p>
<div id="ResultDiv" style="color:navy"></div>

<script>
function FindProducts(){
    //получаем текст, введённый пользователем,
    //и преобразуем его в прописные буквы, чтобы искать без учёта регистра
    SearchString = SearchText.value.toUpperCase();
    //если пользователь не ввёл текст, отображаем сообщение о том,
    //что ничего не найдено, и завершаем работу
    if(SearchString == ""){
        ResultDiv.innerHTML = "<h3> &lt; No products found &gt; </h3>";
        return;
    }
    //переходим в начало набора записей
    dsoPRODUCTS.recordset.moveFirst();
    //переменная, содержащая результаты поиска
    ResultHTML = "";
    //цикл по записям (товарам)
    while(!dsoPRODUCTS.recordset.EOF){
        //получаем заголовок товара
        TitleString = dsoPRODUCTS.recordset.fields("TITLE").value;
        //получаем набор записей сортов товара
        Sorts = dsoPRODUCTS.recordset.fields("SORT").value;
        //переходим в начало набора записей сортов товара
        Sorts.moveFirst();
        //цикл по сортам товара
        while(!Sorts.EOF){
            //получаем цвет товара
            ColorString = Sorts.fields("COLOR").value
            //собственно поиск
            if(ColorString.toUpperCase().indexOf(SearchString) >= 0){
                //если нашли, пополняем строку результатов
                ResultHTML += "<h3>" + TitleString + "<h3><br>"
                //переходим в конец набора записей сортов товара, т.к. дальнейший перебор не нужен
                Sorts.moveLast();
            }
            //переходим к следующему сорту товара
            Sorts.moveNext();
        }//конец цикла по сортам товара
        //переходим к следующему товару
        dsoPRODUCTS.recordset.moveNext();
    }//конец цикла по записям (товарам)
    //если ничего не найдено, отображаем сообщение об этом
    if(ResultHTML == "") ResultDiv.innerHTML = "<h3> &lt; No products found &gt; </h3>";
    //выводим строку результатов
    else ResultDiv.innerHTML = ResultHTML;
}
</script>

Приведённая выше HTML-страница содержит поле ввода текста для пользователя (с идентификатором "SearchText"), и кнопку запуска поиска. При нажатии на кнопку запускается скрипт, использующий свойства и методы объекта recordset DSO, который осуществляет поиск и выводит результаты в элемент HTML-страницы DIV (с идентификатором "ResultDiv"), расположенный внизу страницы. Скрипт подробно прокомментирован и в дополнительных пояснениях не нуждается.

Людоговский Александр

к библиотеке   к оглавлению   Банки данных Интернет   визуальные среды - 4GL   технологии программирования

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

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

В отличие от лукавого понятия "физический вакуум", как бы совместимого с релятивизмом, понятие "эфир" подразумевает наличие базового уровня всей физической материи, имеющего как собственную систему отсчета (обнаруживаемую экспериментально, например, через фоновое космичекое излучение, - тепловое излучение самого эфира), так и являющимся носителем 100% энергии вселенной, а не "нуль-точкой" или "остаточными", "нулевыми колебаниями пространства". Подробнее читайте в FAQ по эфирной физике.

НОВОСТИ ФОРУМА

Форум Рыцари теории эфира


Рыцари теории эфира
 10.11.2021 - 12:37: ПЕРСОНАЛИИ - Personalias -> WHO IS WHO - КТО ЕСТЬ КТО - Карим_Хайдаров.
10.11.2021 - 12:36: СОВЕСТЬ - Conscience -> РАСЧЕЛОВЕЧИВАНИЕ ЧЕЛОВЕКА. КОМУ ЭТО НАДО? - Карим_Хайдаров.
10.11.2021 - 12:36: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от д.м.н. Александра Алексеевича Редько - Карим_Хайдаров.
10.11.2021 - 12:35: ЭКОЛОГИЯ - Ecology -> Биологическая безопасность населения - Карим_Хайдаров.
10.11.2021 - 12:34: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> Проблема государственного терроризма - Карим_Хайдаров.
10.11.2021 - 12:34: ВОЙНА, ПОЛИТИКА И НАУКА - War, Politics and Science -> ПРАВОСУДИЯ.НЕТ - Карим_Хайдаров.
10.11.2021 - 12:34: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Вадима Глогера, США - Карим_Хайдаров.
10.11.2021 - 09:18: НОВЫЕ ТЕХНОЛОГИИ - New Technologies -> Волновая генетика Петра Гаряева, 5G-контроль и управление - Карим_Хайдаров.
10.11.2021 - 09:18: ЭКОЛОГИЯ - Ecology -> ЭКОЛОГИЯ ДЛЯ ВСЕХ - Карим_Хайдаров.
10.11.2021 - 09:16: ЭКОЛОГИЯ - Ecology -> ПРОБЛЕМЫ МЕДИЦИНЫ - Карим_Хайдаров.
10.11.2021 - 09:15: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Екатерины Коваленко - Карим_Хайдаров.
10.11.2021 - 09:13: ВОСПИТАНИЕ, ПРОСВЕЩЕНИЕ, ОБРАЗОВАНИЕ - Upbringing, Inlightening, Education -> Просвещение от Вильгельма Варкентина - Карим_Хайдаров.
Bourabai Research - Технологии XXI века Bourabai Research Institution