Загрузка из XML

Материал из GB wiki
Перейти к: навигация, поиск

Понимание процесса преобразования XML в датасет

Датасет в ГБ представляет собой, в общем случае, таблицу, некоторые поля которой могут содержать вложенные таблицы (субсеты).

XML-файл представляет собой данные иерархической структуры.

Процесс преобразования XML-данных в датасет происходит так:

  • создается датасет заданной структуры
  • определяется узел, потомки которого будут отображены в записи датасета
  • определяются значения ключевых полей. Если в датасете еще нет записи с такими значениями ключевых полей, она добавляется, иначе такая запись становится текущей. После этого производится заполнение полей из атрибутов или потомков текущего тэга, при этом возможна аггрегация данных (можно прибавить значение из атрибута к текущему значению поля).
  • субсеты обрабатываются рекурсивно таким же образом

Заголовок шаблона

Заголовок шаблона определяет только кодировку данных, другие параметры игнорируются

<?xml version="1.0" encoding="utf-8"?> 

Имя схемы

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

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

Например, если имеется файл данных

<root>
 <товары>
...
 </товары>
 <адреса>
...
 </адреса>
</root>

имя схемы должно быть либо товары, либо адреса. Имя корневого тэга по умолчанию можно изменить, вызвав SETROOTTAG перед XML2DS.

Данные в шаблоне могут располагаться двумя способами:

  • Корневой тэг имеет имя, совпадающее с именем схемы
<?xml version="1.0" encoding="Windows-1251"?> 
<Товар>
 <xml2ds>
  • Корневой тэг имеет имя root, его непосредственные потомки имеют имя, совпадающее с именем схемы
<?xml version="1.0" encoding="Windows-1251"?> 
<root>
 <Товар>
  <xml2ds>

При такой структуре можно иметь в одном шаблоне сразу несколько схем с разными именами. Если задано несколько схем с одним именем, они будут обработаны все.

Тэгов xml2ds также может быть несколько - например, они могут описывать разные схемы для разных фильтров. При преобразовании они также будут обработаны все.

Имя целевого тэга

Имя целевого тэга определяет местонахождение тэга, из которого будут браться данные, и задается тэгом object, который должен находиться непосредственно внутри описания схемы:

<object name="имя"/>

Имя тэга может иметь вид:

  • Товар - данные берутся непосредственно из тэга <Товар>, который является потомком корневого тэга
  • %child.Товар - данные берутся из тэга, который расположен где-то внутри тэга <Товар>, на любой глубине

Структура датасета

Описание структуры датасета задается тэгом structure, который должен находиться непосредственно внутри описания схемы. Каждого поле датасета описывается тэгом field, каждый субсет тэгом subset Для каждого поля необходимо задать имя (атрибут name) и тип (атрибут type). Возможные значения типа поля:

  • I4 - длинное целое
  • I2 - короткое целое
  • F8 - число с плавающей точкой
  • D8 - дата и время
  • SXX - строка длиной XX (не длиннее 250 символов)
  • B - блоб (строка любой длины)

Кроме того, для поля можно задать подпись (атрибут label) и сущность (атрибут nature) Для субсетов задается только имя (name).

Пример шаблона для датасета товаров с субсетом штрихкодов:

<structure>
 <field name="Id" type="I4" label="Код" nature="fmId+otArticuls" />
 <field name="Name" type="S40" label="Название" nature="fmName" />
 <subset name="BarCodes">
  <field name="BarCode" type="S20" label="Штрих-код" />
 </subset>
</structure>

Поиск данных

Для того, чтобы указать в шаблоне, где находятся данные, необходимо описать структуру при помощи набора тэгов subset. Предположим, что у нас есть XML вида

<root>
 <Справочники>
  <Товары>
   <Товар Name="..."> <-- Интересующие нас данные

Для того, чтобы получить эти данные, нужно внутри тэга xml2ds повторить данную структуру:

<Справочники> 
 <object name="%child.Справочники">  
 <xml2ds>
  <subset line="Товары">
   <subset name="Товар">
   </subset>
  </subset>
 </xml2ds>


Получение значений атрибутов и вложенных тэгов

Данные в XML могут быть представлены двумя способами:

  • Атрибутами
<Товар name="Название товара" />
  • Текстом
<Товар>
 <Имя>Название товара</Имя>
</Товар>

Получить значение атрибута текущего тэга или одного из его предков можно при помощи функции GETATTRVALUE. Для получения значения атрибута текущего тэга можно пользоваться как GetAttrValue(0,`имя`), так и сокращенной записью !имя

Получить значение текста текущего или вложенного тэга можно при помощи функции GETTEXTVALUE

Заполнение полей

Заполнение поля делается при помощи тэга attr, имя заполняемого поля задается атрибутом fieldname. Значение поля задается либо атрибутом value, либо содержимым тэга attr. Например, если мы хотим прописать в поле name значение атрибута name, это можно сделать одним из способов:

<attr fieldname="name" value="!name" />
<attr fieldname="name">!name</attr>
<attr fieldname="name">
 GetAttrValue(0,`name`)
</attr>

Для задания ключевых полей можно использовать атрибут key="true"

Заполнение субсетов

Заполнение субсета производится при помощи тэга subset с указанным атрибутом fieldname, при этом возможны варианты:

  • Субсет формируется на основе тэга, лежащего непосредственно внутри текущего тэга
<subset fieldname="BarCodes" line="BarCodes">
  • Субсет формируется на основе тэга, лежащего глубоко внутри текущего тэга
<subset fieldname="BarCodes" line="%child.BarCodes">

При заполнении субсета может потребоваться заполнить и поля родительского датасета, обращение к этим полям происходит через fieldname="%master.ИмяПоля", fieldname="%master.%master.ИмяПоля" и т.д.

Ключевые поля

Для того, чтобы создать для каждого тэга в XML одну запись в датасете, не выполняя аггрегации, можно просто добавить первым атрибутом такой

<attr fieldname="*" />

Если нужно аггрегировать данные в датасете, то первыми нужно указывать ключевые поля, а в неключевых полях выполнять действия по аггрегации:

<attr fieldname="Articul" value="!articul" key="true" />
<attr fieldname="Certificate" value="!certificate" key="true" />
<attr fieldname="Quantity" value="ifempty(Quantity,0)+strtofloat(!quantity)" />

Фильтрация

Для тэгов xml2ds, а также тэгов subset с заданным fieldname, можно задать фильтрацию.

Фильтр задается при помощи атрибута filter="выражение" или вложенного тэга filter. При помощи нескольких тэгов xml2ds с разными фильтрами можно делать сложные схемы, воспринимающие разные виды данных

Пример шаблона загрузки из XML

Исходный файл XML имеет содержание:

 <?xml version="1.0" ?>
 <Order xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="Order.xsd" OrderNo="4500000236" 
 CreditorNo="100360" OrderDate="2010-04-14" PriceCurrency="RUB">
 <OrderItem ItemNo="00010" MatCode="1186078" EANs="4605885331483" MatName="Кукла 1018 Defa с одеждой и аксес в кор" 
 RefMatCode="400085525" Unit="ШТ" Quantity="36.000" Shop="R001" Price="351" DeliveryDate="2010-04-15"/>
 </Order>

По данному файлу необходимо прочитать данные из корневого тэга Order и из тэга OrderItem, которых может быть множество в файле. Сам шаблон будет следующим:

 <?xml version="1.0" encoding="windows-1251"?>
 <OrderItem>
  <structure>
     <field name="PrevDate"        label="Дата поставки"          type="S40" nature="fmName"/>
     <field name="OpDate"          label="Дата операции"          type="S40" nature="fmName"/>
     <field name="Articul"         label="Товар"                  type="I4" nature="fmId+otArticuls"/>
     <field name="Price"           label="Цена"                   type="F8" nature="fmPrice"/>
     <field name="Quantity"        label="Кол-во"                 type="F8" nature="fmQuantity"/>
     <field name="NoPos"           label="Поз. Уютерра"           type="F8" nature="fmName"/>	
     <field name="OrderNo"         label="Комментарий"            type="S40" nature="fmName"/>	  
     <field name="MatCode"         label="Поз.Уютерра"            type="S40" nature="fmName"/>
  </structure>
  <object name="OrderItem"/>
  	<xml2ds>
        <attr value=":opdate:=GETATTRVALUE(1,`OrderDate`)"/>
        <attr value=":orderno:=GETATTRVALUE(1,`OrderNo`)"/>
        <attr fieldname="Articul" value="!RefMatCode" key="true" />
        <attr fieldname="Quantity" value="StrToFloat(!Quantity)"  key="true" />
        <attr fieldname="Price" value="StrToFloat(!Price)" key="true" />
        <attr fieldname="NoPos" value="!ItemNo"  />
        <attr fieldname="MatCode" value="!MatCode" />
        <attr fieldname="PrevDate" value="!DeliveryDate" />
        <attr fieldname="OrderNo" value="ifempty(:orderno,``)" />
        <attr fieldname="OpDate" value="ifempty(:opdate,``)" />
       </xml2ds>
 </OrderItem>

Где в <structure></structure> описана структура, которую получит DataSet. Поиск данных ведется по тэгу <OrderItem>. Получаем значения корневого тэга с помощью GETATTRVALUE: <attr value=":opdate:=GETATTRVALUE(1,`OrderDate`)"/> и <attr value=":orderno:=GETATTRVALUE(1,`OrderNo`)"/>. И делаем заполнение полей DataSet'a, например: <attr fieldname="NoPos" value="!ItemNo" />