Потоковая передача xml-to-json

У меня есть несколько очень больших XML-файлов, которые я хотел бы преобразовать в (одинаково большие) файлы JSON. Для этого я написал XSLT, который преобразует XML в промежуточное «представление XML в JSON», указанное в спецификации XSLT 3.0. Затем я могу вызвать функцию fn: xml-to-json.

Однако я хотел бы транслировать этот процесс, чтобы использование памяти оставалось стабильным. Это возможно?


person J. Nicholas    schedule 21.05.2019    source источник
comment
Этот первый шаг преобразования, этот XSLT, который вы написали, оценивается Saxon как потоковый? Можете ли вы написать код на Java или .NET (в зависимости от используемой вами версии Saxon), чтобы связать эти два преобразования? См. saxonica.com/html/documentation/using-xsl/embedding. / говорит, что Xslt30Transformer не реализует интерфейс назначения напрямую; но вы можете вызвать его метод asDestination (), чтобы получить объект назначения, позволяющий преобразованию действовать как место назначения для некоторого другого процесса в конвейере.   -  person Martin Honnen    schedule 22.05.2019
comment
Библиотека underscore-java может конвертировать XML-файл размером до 100 МБ в JSON.   -  person Valentyn Kolesnikov    schedule 22.06.2021


Ответы (1)


К сожалению, невозможно (ни в соответствии со спецификацией XSLT 3.0 от W3C, ни в реализации Saxon) написать многофазное преобразование потоковой передачи в одной таблице стилей. Обычно существует два способа записать многофазное преобразование (то есть преобразование, которое представляет собой композицию двух отдельных преобразований: либо первая фаза может быть вызвана как функция, либо первая фаза может предоставлять свои результаты в переменной. Ни один из этих механизмов не позволяет предоставлять промежуточные результаты (результаты первого этапа) в виде потокового документа.

(Мы знали об этом ограничении при разработке спецификации, но решили исключить его из требований, поскольку все уже становилось достаточно сложным.)

Но я считаю, что это можно сделать в Saxon, используя многофазное преобразование, реализованное с использованием двух отдельных таблиц стилей, связанных вместе. Самый простой способ сделать это, вероятно, - использовать интерфейс s9api. Напишите второе преобразование t2.xsl (которое просто вызывает xml-to-json) следующим образом:

<xsl:transform version="3.0" expand-text="yes"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:mode streamable="yes"/>
<xsl:output method="text"/>
<xsl:template match="/">{xml-to-json(.)}</xsl:template>
</xsl:transform>

а затем выполните:

Processor proc = new Processor(true);
Serializer out = proc.newSerializer(new File("out.xml");
XsltCompiler comp = proc.newXsltCompiler();
Xslt30Transformer t2 = comp.compile(new File("t2.xsl")).load30();
Destination phase2 = t2.asDocumentDestination(out);

Xslt30Transformer t1 = comp.compile(new File("t1.xsl").load30();
t1.applyTemplates(source, phase2);

Предостережение: хотя входной документ передается в потоковом режиме, а промежуточный XML передается в потоковом режиме, выходной JSON (я думаю) полностью создается в памяти перед записью в выходной файл. Это немного прискорбно, и мы должны попытаться исправить это.

person Michael Kay    schedule 22.05.2019