Разработка xslt-преобразований

WEB-приложение Сведение отчетности (29.04.2026) | (одним файлом) (cсылка)
Разработка xslt-преобразований
1. Для реализации загрузки отчетов из xml-документов произвольной структуры необходимо предпринять следующие шаги: Внимательно изучить структуру, с которой придется иметь дело. Если схемы валидации документов такой структуры не существует, ее придется разработать самостоятельно.
   Пример | Например, нам нужно иметь дело с документами следующей структуры:
       1<data>
       2  <report agent="РосПищеСвет" form="Форма 160.285">
       3    <subreport ЗаСпички="100" ЗаМыло="200" Качество="Хорошее" />
       4    <subreport code="Разрез 1" ЗаСпички="10" ЗаМыло="20" Качество="Среднее" />
       5    <subreport code="Разрез 2" ЗаСпички="80" ЗаМыло="280" Качество="Отличное" />
       6  </report>
       7</data>
   Для валидации документов такой структуры создадим xsd-схему:
       01<xs:schema
       02  xmlns:xs="http://www.w3.org/2001/XMLSchema">
       03  <xs:element name="data">
       04  <!--  Корневой элемент документа имеет имя "data" -->
       05    <xs:complexType>
       06      <xs:sequence>
       07        <xs:element name="report" maxOccurs="unbounded">
       08        <!--  Корневой элемент включает в себя любое количество элементов "report" -->
       09          <xs:complexType>
       10            <xs:sequence>
       11              <xs:element maxOccurs="unbounded" name="subreport">
       12              <!--  Элемент "report" включает в себя любое количество элементов "subreport" -->
       13                <xs:complexType>
       14                  <xs:attribute name="code" type="xs:string" use="optional" />
       15                  <!--  Элемент "subreport" имеет необязательный атрибут "code" -->
       16                  <xs:anyAttribute processContents="skip" />
       17                  <!--  Элемент "subreport" имеет неизвестное заранее количество любых атрибутов
       18                    Это будут значения показателей.
       19                   -->
       20                </xs:complexType>
       21              </xs:element>
       22            </xs:sequence>
       23            <xs:attribute name="agent" type="xs:string" use="required" />
       24            <!--  Элемент "report" имеет обязательный строковый атрибут "agent" -->
       25            <xs:attribute name="form" type="xs:string" use="required" />
       26            <!--  Элемент "report" имеет обязательный строковый атрибут "form" -->
       27          </xs:complexType>
       28        </xs:element>
       29      </xs:sequence>
       30    </xs:complexType>
       31  </xs:element>
       32</xs:schema>
2. Теперь нам нужно научиться превращать документы в документы стандартной структуры Парус 8:
       01<REPORTS>
       02  <!-- отчет -->
       03  <REPORT>
       04    <!-- обязательные элементы -->
       05    <AGENT>Мнемокод контрагента</AGENT>
       06    <FORM>Мнемокод формы</FORM>
       07    <BDATE>Дата отчета</BDATE>
       08    <KIND>0-первичный отчет, 1-сводный отчет</KIND>
       09
       10    <!-- необязательные элементы -->
       11    <CATALOG>Наименование каталога</CATALOG>
       12    <CHECKED>0-непроверен;1-проверен</CHECKED>
       13    <STATE>Состояние отчета</STATE>
       14    <SENT>Отправлен</SENT>
       15
       16    <!-- подотчеты -->
       17    <SUBREPORTS>
       18
       19      <!-- главный подотчет -->
       20      <SUBREPORT>
       21        <!-- значения одиночных показателей -->
       22        <VALUES>
       23          <VALUE>
       24            <CODE>Мнемокод показателя</CODE>
       25            <!-- один из трех вариантов -->
       26            <NVAL>Число</NVAL>
       27            <SVAL>Строка</SVAL>
       28            <DVAL>Дата</DVAL>
       29          </VALUE>
       30          <VALUE>
       31            ...
       32          </VALUE>
       33        </VALUES>
       34
       35        <!-- таблицы показателей -->
       36        <TABLES>
       37          <TABLE>
       38            <NAME>Наименование таблицы</NAME>
       39            <!-- строки таблицы -->
       40            <ROWS>
       41              <ROW>
       42                <VALUE>
       43                  <CODE>Мнемокод показателя в составе таблицы</CODE>
       44                  <!-- один из трех вариантов -->
       45                  <NVAL>Число</NVAL>
       46                  <SVAL>Строка</SVAL>
       47                  <DVAL>Дата</DVAL>
       48                </VALUE>
       49                <VALUE>
       50                  ...
       51                </VALUE>
       52              </ROW>
       53              <ROW>
       54                ...
       55              </ROW>
       56            </ROWS>
       57          </TABLE>
       58          <TABLE>
       59            ...
       60          </TABLE>
       61        </TABLES>
       62      </SUBREPORT>
       63      <SUBREPORT>
       64        <CODE>Мнемокод разреза</CODE>
       65          ...
       66      </SUBREPORT>
       67    </SUBREPORTS>
       68  </REPORT>
       69  <REPORT>
       70    ...
       71  </REPORT>
       72</REPORTS>
   Пример | Преобразование нашего исходного документа к стандартной структуре:
       01<xsl:stylesheet version="1.0"
       02                xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
       03                xmlns:msxsl="urn:schemas-microsoft-com:xslt"
       04                xmlns:parus="parus.xslt"
       05                xmlns:vbs="parus.vbscript"
       06                exclude-result-prefixes="xsl msxsl parus vbs">
       07<!-- Пространства имен:
       08  xsl - стандартное пространство имен элементов xslt
       09  msxsl - расширение Microsoft пространства имен xslt
       10  parus - "наше" пространство имен. Принадлежащие ему идентификаторы описаны ниже.
       11  vbs - "локальное" пространство имен, через которое мы будем получать доступ к скриптовым функциям. -->
       12
       13<!-- нам понадобятся возможнсти, которые не предоставляются стандартными средствами xslt-транслятора.
       14Напрмер, нам будет нужна текущая дата. Определелим в локальном пространстве имен скриптовую функцию,
       15возвращающую отформатированную дату -->
       16  <msxsl:script language="VBScript" implements-prefix="vbs">
       17  <![CDATA[
       18    function today()
       19      today = Year(Date) & "-" & Month(Date) & "-" & Day(Date)
       20    end function
       21  ]]>
       22  </msxsl:script>
       23
       24  <xsl:output encoding="UTF-8"
       25              method="xml"/>
       26
       27  <!-- шаблон корневого узла. Он будет применен один и только один раз. -->
       28  <xsl:template match="/">
       29    <!-- Элемент целевой структуры -->
       30    <REPORTS>
       31
       32      <!-- Для каждого элемента "report" исходной структуры ... -->
       33      <xsl:for-each select="data/report">
       34        <REPORT>
       35          <!-- выводим сообщение пользователю. Он увидит его протоколе загрузки -->
       36          <xsl:value-of select="parus:Message(concat('Сообщение пользователю при загрузке файла ', parus:FileName(), '.'))"/>
       37
       38          <!-- выводим сообщение в отладочный монитор. -->
       39          <xsl:value-of select="parus:DebugString('Сообщение в монитор.')"/>
       40
       41          <!-- эти элементы бререм из атрибутов узла "report" -->
       42          <AGENT><xsl:value-of select="@agent"/></AGENT>
       43          <FORM><xsl:value-of select="@form"/></FORM>
       44
       45          <!-- Формируем дату как результат вызова скриптовой функции -->
       46          <BDATE><xsl:value-of select="vbs:today()" /></BDATE>
       47
       48          <!-- константа -->
       49          <KIND>0</KIND>
       50
       51          <SUBREPORTS>
       52            <!-- цикл по элементам "subreport" -->
       53            <xsl:for-each select="subreport">
       54              <SUBREPORT>
       55
       56                <!-- если "subreport" имеет атрибут "code", то использовать его -->
       57                <xsl:if test="@code">
       58                  <CODE><xsl:value-of select="@code"/></CODE>
       59                </xsl:if>
       60
       61                <VALUES>
       62                  <!-- цикл по всем атрибутам элемента "subreport" -->
       63                  <xsl:for-each select="@*">
       64                    <!-- если атрибут имеет имя, отличное от "code", то это показатель -->
       65                    <xsl:if test="not(name(.)='code')">
       66                      <VALUE>
       67                        <CODE><xsl:value-of select="name(.)"/></CODE>
       68                        <SVAL><xsl:value-of select="." /></SVAL>
       69                      </VALUE>
       70                    </xsl:if>
       71                  </xsl:for-each>
       72                </VALUES>
       73              </SUBREPORT>
       74            </xsl:for-each>
       75          </SUBREPORTS>
       76        </REPORT>
       77      </xsl:for-each>
       78    </REPORTS>
       79  </xsl:template>
       80</xsl:stylesheet>
   В результате применения этого преобразования к нашему документу мы получим следующий документ:
       01<REPORTS>
       02  <REPORT>
       03    <AGENT>РосПищеСвет</AGENT>
       04    <FORM>Форма 160.285</FORM>
       05    <BDATE>2015-10-15</BDATE>
       06    <KIND>0</KIND>
       07    <SUBREPORTS>
       08      <SUBREPORT>
       09        <VALUES>
       10          <VALUE>
       11            <CODE>ЗаСпички</CODE>
       12            <SVAL>100</SVAL>
       13          </VALUE>
       14          <VALUE>
       15            <CODE>ЗаМыло</CODE>
       16            <SVAL>200</SVAL>
       17          </VALUE>
       18          <VALUE>
       19            <CODE>Качество</CODE>
       20            <SVAL>Хорошее</SVAL>
       21          </VALUE>
       22        </VALUES>
       23      </SUBREPORT>
       24      <SUBREPORT>
       25        <CODE>Разрез 1</CODE>
       26        <VALUES>
       27          <VALUE>
       28            <CODE>ЗаСпички</CODE>
       29            <SVAL>10</SVAL>
       30          </VALUE>
       31          <VALUE>
       32            <CODE>ЗаМыло</CODE>
       33            <SVAL>20</SVAL>
       34          </VALUE>
       35          <VALUE>
       36            <CODE>Качество</CODE>
       37            <SVAL>Среднее</SVAL>
       38          </VALUE>
       39        </VALUES>
       40      </SUBREPORT>
       41      <SUBREPORT>
       42        <CODE>Разрез 2</CODE>
       43        <VALUES>
       44          <VALUE>
       45            <CODE>ЗаСпички</CODE>
       46            <SVAL>80</SVAL>
       47          </VALUE>
       48          <VALUE>
       49            <CODE>ЗаМыло</CODE>
       50            <SVAL>280</SVAL>
       51          </VALUE>
       52          <VALUE>
       53            <CODE>Качество</CODE>
       54            <SVAL>Отличное</SVAL>
       55          </VALUE>
       56        </VALUES>
       57      </SUBREPORT>
       58    </SUBREPORTS>
       59  </REPORT>
       60</REPORTS>
   Этот документ вполне соответствует стандартной структуре, и, если в БД существуют соответствующая форма, контрагент, показатели и разрезы, то он загрузится.
Важно! | Элементы пространства имен с uri "parus.xslt": Функция FileName () возвращает имя загруженного пользователем файла. Функция Message (Text: string) передает строковый аргумент пользователю в протокол загрузки отчета. Возвращает пустую строку. Если вы хотите передать этой функции что-то, отличное от строки, то преобразуйте аргумент в строку функцией string. Например, <xsl:value-of select="parus:Message(string(@code))" /> Функция DebugString (Text: string) передает строковый аргумент в отладочный монитор. Возвращает пустую строку. Если вы хотите передать этой функции что-то, отличное от строки, то преобразуйте аргумент в строку функцией string. Например, <xsl:value-of select="parus:DebugString(string(@code))" /> Функция SessionValue (Name: string) возвращает сохраненное в сессии значение с именем, определяемым параметром Name. Например, <xsl:value-of select="parus:SessionValue("agent")" /> Этими функциями вы можете пользоваться в своих xslt-преобразованиях.