WEB-приложение Сведение отчетности  (23.11.2023)
Разработка xslt-преобразований
Для реализации загрузки отчетов из xml-документов произвольной структуры необходимо предпринять следующие шаги:
  1. Внимательно изучить структуру, с которой придется иметь дело. Если схемы валидации документов такой структуры не существует, ее придется разработать самостоятельно.
    Пример
    Например, нам нужно иметь дело с документами следующей структуры:
    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-преобразованиях.