1С & XML

  1. 8 г. назад

    Итак...
    Коллеги, встал вопрос разбора XML собственными средствами платформы.
    На объемах до гига вполне работает, но ОЧЕНЬ медленно.
    Свыше гига иногда валится.
    Ессно, надо было решать что таки использовать, первое, что пришло в голову, старый DOM.Document от Microsoft.
    Опять таки, медленно, но. Возникла идея парсить средствами Microsoft SQL Server...

    И тут, это нас выручило.
    Используя бяку FOR XML можно получить очень быстро данные объема до 2 гигов за один проход.
    Парсинг 3 гигов занимает примерно минуту против 2 часов DOM.Document и 3 часов платформой 1С.
    Тестировалось на SQL от 2008 R2 и выше.

    ЗЫ: в SQL Server 2016 появился тип json :)
    В Postgres он был давно, только вот производительность хромала.

    Встает вопрос, как передать XML или универсальную коллекцию в явном виде серверу СУБД преобразова к типу xml.
    А очень просто. используя sp_executesql с параметром типа xml скормить ему текст
    в виде параметра.
    Но, важно учесть, что все namespace-ы вне известных SQL server будут игнорироваться.
    Т.е., если передать xml-представление таблицы значений не вырезав из оного 1С-ное пространство имен, xml парситься, конечно, будет, но, не так, как надо.

    Ответы: (6)
  2. -- небольшой пример передачи на сервер таблицы значений через сериализацию XML
    declare xml xml = REPLACE(N'
    <ValueTable xmlns="http://v8.1c.ru/8.1/data/core" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <column>
    <Name xsi:type="xs:string">КодТипаДляЗП</Name>
    <ValueType/>
    </column>
    <column>
    <Name xsi:type="xs:string">Ставка</Name>
    <ValueType/>
    </column>
    <row>
    <Value xsi:type="xs:string">01</Value>
    <Value xsi:type="xs:decimal">1</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">02</Value>
    <Value xsi:type="xs:decimal">5</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">03</Value>
    <Value xsi:type="xs:decimal">10</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">04</Value>
    <Value xsi:type="xs:decimal">22</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">05</Value>
    <Value xsi:type="xs:decimal">38</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">06</Value>
    <Value xsi:type="xs:decimal">55</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">07</Value>
    <Value xsi:type="xs:decimal">85</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">08</Value>
    <Value xsi:type="xs:decimal">115</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">09</Value>
    <Value xsi:type="xs:decimal">170</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">10</Value>
    <Value xsi:type="xs:decimal">235</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">11</Value>
    <Value xsi:type="xs:decimal">415</Value>
    </row>
    <row>
    <Value xsi:type="xs:string">12</Value>
    <Value xsi:type="xs:decimal">620</Value>
    </row>
    </ValueTable>','xmlns="http://v8.1c.ru/8.1/data/core"','')

    SELECT
    ТипыДляЗП.Ставка.value(N'Value[1]',N'nchar(2)') as КодТипаДляЗП
    ,ТипыДляЗП.Ставка.value(N'Value[2]',N'numeric(15,4)') as Ставка
    FROM xml.nodes('//ValueTable/row') as ТипыДляЗП(Ставка)

  3. В коде съедена болдом собака @

  4. Если убрать REPLACE, то запрос не отработает

  5. При этом, ошибки не возникнет

  6. Функция СериализацияXML(Знач ПереданноеЗначение,НазначатьТипXMLЯвно=Истина) Экспорт
                    ЗаписьXML=Новый ЗаписьXML();
                    ЗаписьXML.УстановитьСтроку();
                    Сериализатор=Новый СериализаторXDTO(ФабрикаXDTO);
                    Сериализатор.ЗаписатьXML(ЗаписьXML,ПереданноеЗначение,?(НазначатьТипXMLЯвно,НазначениеТипаXML.Явное ,НазначениеТипаXML.Неявное));
                    СтрокаXML=ЗаписьXML.Закрыть();
                    Возврат СтрокаXML;
    КонецФункции
     
     
    Функция ЗначениеИзСериализацииXML(СтрокаXML) Экспорт
                    ЧтениеXML=Новый ЧтениеXML;
                    ЧтениеXML.УстановитьСтроку(СтрокаXML);
                    Сериализатор=Новый СериализаторXDTO(ФабрикаXDTO);
                    ПолученноеЗначение=Сериализатор.ПрочитатьXML(ЧтениеXML);
                    Возврат ПолученноеЗначение;
    КонецФункции
    
  7. (0) у меня вопрос - зачем передавать 1 гиг инфы через XML. Нельзя ли эту инфу заархивировать и передавать как CDATA

    Ответы: (7)
  8. (6) Нельзя. Так устроена система - приемник (SAP XI)

    Ответы: (8)
  9. (7) чё то ржу. вы думаете, сап не может распознать CDATA?

    Ответы: (9) (10)
  10. (8) то же ржу, не может :)

    Ответы: (11)
  11. (8) мало того он просто виснет непонятно на каком элементе

  12. (9) это как минимум неправда - но оставим её на совести ваших консультантов. А почему нельзя этот документ разбить на мелкие кусочки и передавать их частями?

    Ответы: (12) (13)
  13. (11) там не совсем документы. Речь о начальном наполнении

    Ответы: (17)
  14. (11) В предыдущий раз мы тупо писали напрямую в таблицы Oracle

    Ответы: (14)
  15. (13) у вас даже не HANA...

    Ответы: (16)
  16. Правда, это было 11 лет назад :)

  17. (14) и не только у нас :)

  18. (12) я бы выгрузил данные в csv файл(ы) и заставил XI его запроцессить. это существенно уменьшит дальнейшие расходы на поддержку данного решения

    Ответы: (19) (21)
  19. или не XI, а целевую систему

  20. (17) делали, не вышло

  21. суммируя мои ответы - мне кажется, что задача поставлена неверно. Вместо решения задачи "как передать 2гига структурированных данных через XML" следует решить задачу "как передать 2 гига данных"

  22. (17) а где падает? 2 гига - это не те объемы, на которых сап должен падать

  23. а вот в случае XML я уже не был бы столь категоричен. По идее, при преобразовании 2гигового XML сап должен выделить около 20 гигов памяти под одну сессию. Это будет довольно затруднительно

  24. Закрепите в книге знаний
    И чтобы форматирование символы не ело, можно попробовать код постить в теге /code

    @test 
  25. Спасибо огромное ТС за публикацию! Просьба кинуть в ветку весь код по теме.

  26. Еще одно относительно полезное решение:

    Если надо вернуть из sql server ТЗ через ADODB, можно вернуть набор строк.
    Для этого можно преобразовать результат запроса к типу XML:
    Предположим, запрос {A} возвращает кортеж столбцов { a, b, c}, тогда запрос ниже
    SELECT
    1 as Tag, NULL As parent,
    A.a As [row!1!Value!ELEMENT]
    ,A.b As [row!1!Value!ELEMENT]
    ,A.c As [row!1!Value!ELEMENT]
    From {A} As A
    FOR XML EXPLICIT

    вернет XML набор строк таблицы значений.
    Но, XML из ADODB.Recordset тянуть неудобно.
    Проще обернуть эту конструкцию
    SELECT CONVERT(nvarchar(max),(
    SELECT
    1 as Tag, NULL As parent,
    A.a As [row!1!Value!ELEMENT]
    ,A.b As [row!1!Value!ELEMENT]
    ,A.c As [row!1!Value!ELEMENT]
    From {A} As A
    FOR XML EXPLICIT
    )) As Строки

    Такой запрос вернет одну строку с одним столбцом "Строки".
    Значение столбца будет содержать нужный нам текст.
    Далее, в XML значение пустой типизированной таблицы значений добавляем текст строк и восстанавливаем значение ТЗ.

    Если необходимо типизированной значение колонки, т.е колонка составного типа,
    Тогда просто добавляем атрибут полю
    SELECT CONVERT(nvarchar(max),(
    SELECT
    1 as Tag, NULL As parent,
    A.a As [row!1!Value!ELEMENT]
    ,{URI пространства имен} As [row!1!Value!{Идентификатор пространства имен}]
    ,A.b As [row!1!Value!ELEMENT]
    ,A.c As [row!1!Value!ELEMENT]
    From {A} As A
    FOR XML EXPLICIT
    )) As Строки

или зарегистрируйтесь чтобы ответить!