Эффективный конвейер XSLT в Java (или перенаправление результатов в источники)

У меня есть ряд таблиц стилей XSL 2.0, которые передаются друг другу, т. е. вывод таблицы стилей A передает B каналы C.

Каков наиболее эффективный способ сделать это? Перефразированный вопрос звучит так: как можно эффективно направить вывод одного преобразования в другое.

Вот моя первая попытка:

@Override
public void transform(Source data, Result out) throws TransformerException{
    for(Transformer autobot : autobots){
        if(autobots.indexOf(autobot) != (autobots.size()-1)){
            log.debug("Transforming prelim stylesheet...");
            data = transform(autobot,data);
        }else{
            log.debug("Transforming final stylesheet...");
            autobot.transform(data, out);
        }
    }
}

private Source transform(Transformer autobot, Source data) throws TransformerException{
    DOMResult result = new DOMResult();
    autobot.transform(data, result);
    Node node = result.getNode();
    return new DOMSource(node);
}

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

Есть ли простой способ маршрутизировать, чтобы сказать, маршрутизировать SAXResult к SAXSource? Решение StAX было бы еще одним вариантом.

Я знаю о таких проектах, как XProc, что очень здорово, если вы еще не ознакомились с ними, но я не хочу инвестировать в целую структуру.


person Chris Scott    schedule 21.08.2009    source источник
comment
for(Автоботы-трансформеры: автоботы){ Бесценно :-)   -  person Damien B    schedule 01.07.2010


Ответы (3)


Я нашел это: #3. Цепочка преобразований, которая показывает два способа использования TransformerFactory для цепочки преобразований, когда результаты одного преобразования передаются следующему преобразованию, а затем, наконец, выводятся в систему. Это позволяет избежать необходимости промежуточной сериализации в строку, файл и т. д. между преобразованиями.

Если для одного и того же XML-документа требуется несколько последовательных преобразований, обязательно избегайте ненужных операций синтаксического анализа. Я часто сталкиваюсь с кодом, который преобразует строку в другую строку, а затем преобразует эту строку в еще одну строку. Это не только медленно, но и может потреблять значительный объем памяти, особенно если промежуточные строки не разрешены к сборке мусора.

Большинство преобразований основаны на серии событий SAX. Парсер SAX обычно анализирует InputStream или другой InputSource в события SAX, которые затем могут быть переданы в Transformer. Вместо вывода Transformer в файл, строку или другой подобный результат вместо этого можно использовать SAXResult. SAXResult принимает ContentHandler, который может передавать эти события SAX непосредственно другому преобразователю и т. д.

Вот один из подходов, который я обычно предпочитаю, поскольку он обеспечивает большую гибкость для различных источников ввода и вывода. Это также упрощает динамическое создание цепочки преобразований с переменным числом преобразований.

SAXTransformerFactory stf = (SAXTransformerFactory)TransformerFactory.newInstance();

// These templates objects could be reused and obtained from elsewhere.
Templates templates1 = stf.newTemplates(new StreamSource(
  getClass().getResourceAsStream("MyStylesheet1.xslt")));
Templates templates2 = stf.newTemplates(new StreamSource(
  getClass().getResourceAsStream("MyStylesheet1.xslt")));

TransformerHandler th1 = stf.newTransformerHandler(templates1);
TransformerHandler th2 = stf.newTransformerHandler(templates2);

th1.setResult(new SAXResult(th2));
th2.setResult(new StreamResult(System.out));

Transformer t = stf.newTransformer();
t.transform(new StreamSource(System.in), new SAXResult(th1));

// th1 feeds th2, which in turn feeds System.out.
person Mads Hansen    schedule 23.08.2009
comment
Отлично, похоже, это именно то, что я ищу. Просто любопытно - что вы искали, чтобы найти это? Мой google-foo должен быть ржавым. - person Chris Scott; 24.08.2009
comment
На самом деле, ваш вопрос напомнил мне о каком-то коде, который я видел реализованным некоторое время назад. Я знал, что он использует saxtransformerfactory, поэтому я погуглил: цепные преобразования saxtransformerfactory. Его действительно трудно найти, учитывая, сколько кода/логики/проблем он экономит, когда вы хотите преобразовать конвейер. - person Mads Hansen; 25.08.2009
comment
Согласно onjava.com/pub/a/onjava/excerpt /java_xslt_ch5/?page=6 можно проверить, может ли transFact.getFeature(SAXTransformerFactory.FEATURE) безопасно выполнять приведение к SAXTransformerFactory. - person Chry Cheng; 22.04.2013
comment
Не следует ли закрывать потоки, которые вы получаете от getResourceAsStream? Для меня это выглядит как утечка ресурсов. - person stenix; 05.06.2019

Связанный вопрос Эффективный XSLT-конвейер с параметрами в Java уточнен правильно параметры, передаваемые в такую ​​цепочку трансформаторов.

И это также дало намек на немного более короткое решение без третьего трансформатора:

SAXTransformerFactory stf = (SAXTransformerFactory)TransformerFactory.newInstance();

Templates templates1 = stf.newTemplates(new StreamSource(
        getClass().getResourceAsStream("MyStylesheet1.xslt")));
Templates templates2 = stf.newTemplates(new StreamSource(
        getClass().getResourceAsStream("MyStylesheet2.xslt")));

TransformerHandler th1 = stf.newTransformerHandler(templates1);
TransformerHandler th2 = stf.newTransformerHandler(templates2);

th2.setResult(new StreamResult(System.out));

// Note that indent, etc should be applied to the last transformer in chain:
th2.getTransformer().setOutputProperty(OutputKeys.INDENT, "yes");

th1.getTransformer().transform(new StreamSource(System.in), new SAXResult(th2));
person Vadzim    schedule 01.03.2013

Лучше всего придерживаться DOM, как вы это делаете, потому что XSLT-процессору в любом случае придется строить дерево — потоковая передача — это вариант только для очень ограниченной категории преобразований, и лишь немногие процессоры, если они вообще есть, могут понять это автоматически и переключиться. к реализации только для потоковой передачи; в противном случае они просто читают ввод и строят дерево.

person Pavel Minaev    schedule 21.08.2009
comment
Это неправильно. Поведение зависит от реализации. Реализация Java W3C DOM очень неэффективна, и в большинстве реализаций используется более эффективное внутреннее представление этой модели DOM. Таким образом, принятый ответ действительно улучшает производительность по сравнению с DOM. - person rmuller; 09.09.2016