Как реализовать аналог saxon:result-document() для XQuery

При разработке первой версии интерент-магазина постельного белья kunmeng.ru, мне нужно было быстро сгенерировать много страниц по шаблону. Изначально текстовые данные о товаре я перевел в XML. Соответственно, для генерации карточек товаров и групп логично было бы использовать XSLT, который я не люблю. Выяснилось, что появился новый язык для работы с XML данными — XQuery, который оказался гораздо проще XSLT по синтаксису и вообще как-то понятнее.

Оставались только две небольшие проблемы:

  1. Найти нормальную реализацию;
  2. Научиться сохранять много файлов с разными именами из одного XQ преобразования.

Практически единственной доступной и нормальной реализацией оказался Saxon. Но вторая проблема в нем решалась только в коммерческой версии с помощью функции saxon:result-document(). Зато, можно было писать свои расширения на Java, и поэтому я быстренько набросал простейший убогий аналог saxon:result-document():


import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;

/**
 * Created: 16.11.2007
 *
 * @author Artem Kuroptev
 */
public class XQSaver
{
    public static String save(String path, 
                      String content, 
                  String enc) 
    throws IOException
    {
            FileOutputStream fos 
                = new FileOutputStream(new File(path));
            try
            {
                fos.write(content.getBytes(enc));
            }
            finally
            {
                fos.close();
            }
        return "";
    }
}

Как использовать эту функцию в XQ? Очень просто. Нужно скомпилировать класс и добавить его в classpath при вызове Saxon:
java -cp Lib\saxonb9-0-0-1j\saxon9.jar;java\classes net.sf.saxon.Query ...

Затем в XQ в заголовке пишем:
declare namespace my="java:XQSaver";

А теперь сам вызов:

for $item in doc("catalog.xml")/items/item
let $file := concat(concat("item-", $item/id/text()), ".html")
let $a:= <html>test</html>
return
    <done>{my:save($file, 
    saxon:serialize($a, 
                    <xsl:output 
            method="html" 
            encoding="cp1251" 
            indent="yes" 
            saxon:indent-spaces="2"/>), 
                    "cp1251")}</done> 

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

Избранное
Из недавнего

© Artem Kuroptev, 2005-2011.