Подтвердить что ты не робот

Эффективный конвейер 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, что очень круто, если вы еще не посмотрели, но я не хотел инвестировать в целую структуру.

4b9b3361

Ответ 1

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

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

Большинство преобразований основаны на серия событий SAX. Анализатор SAX обычно будет анализировать InputStream или другой InputSource в событиях SAX, которые затем могут 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.

Ответ 2

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

Ответ 3

Связанный с этим вопрос Эффективный конвейер 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));