Логин:   Пароль:






Новости
Рассылки
Форум
Поиск


Java
- Апплеты
- Вопрос-ответ
- Классы
- Примеры
- Руководства
- Статьи
- IDE
- Словарь терминов
- Скачать

Мобильная Java
- Игры
- Примеры
- Статьи
- WAP, WML и пр.

JavaScript
- Вопрос-ответ
- Примеры
- Статьи

Веб-мастеринг
- HTML
- CSS
- SSI

Разминка для ума
Проекты
Книги
Ссылки
Программы
Юмор :)




Rambler's Top100
Rambler's Top100

Java: СтатьиУсловная компиляция Java на основе XML и XSL

Условная компиляция Java на основе XML и XSL

Условная компиляция достаточно полезная вещь, с этим, наверное, никто спорить не будет. Иметь возможность собирать разные версии приложения без изменений исходных текстов очень удобно. Условная компиляция есть в С/С++, в VB и еще наверно не в одном языке программирования. Но ее нет почему-то в Java. Может этому есть разумное объяснение, а может и нет. В любом случае лучше иметь этот инструмент в языке, а уж разработчики сами решат, пользоваться им или нет.

Одним из способов отладки Java (да вообще-то любых) программ, как известно, является добавление в код функций трассировки:


void f(...) {

        try {

            System.out.println("job started");

            some_job();

            System.out.println("job OK");

        } catch(...) {

            System.out.println("job FAILED");

        }

    }

Когда определенный участок кода отлажен, и необходимость отслеживать его работу пропадает, приходиться избавляться от println-ов вручную. Это неудобно, особенно если учесть, что к отладке придется вернуться еще не один раз, что обычно и происходит. Можно конечно строки не удалять, а просто закрывать их комментариями. Но все равно ручной работы не избежать. Одним словом очень хочется написать на Java что-нибудь вроде такого:


void f(...) {

        try {

    #ifdef DEBUG

            System.out.println("job started");

    #endif

            some_job();

    #ifdef DEBUG

            System.out.println("job OK");

    #endif

        } catch(...) {

    #ifdef DEBUG

            System.out.println("job FAILED");

    #endif

        }

    } 

Но встроенного препроцессора в Java нет, так что это решение не подходит. Есть самодельные препроцессоры. Но ими обычно пользуются сами авторы и их знакомые, но применять их в коммерческих проектах никто, вероятно, не решится. Вот если бы препроцессор был построен на каком-нибудь индустриальном стандарте или написан Sun, тогда другое дело.

Предлагаемый препроцессор как некий исполняемый модуль или отдельный класс-файл не существует. Идея его состоит в том, чтобы представлять исходные java файлы в виде xml документов, а затем трансформировать их в компилируемые java файлы при помощи xsl-процессора и подходящих таблиц стилей.

Следующий пример иллюстрирует работу предложенного препроцессора.

Исходный java файл (Sample.java):


public class Sample {

    public static void main(String args[]) {

        System.out.println("start");

        for(int i = 0; i < 5; i++) {

            System.out.println("iteration=" + i);

        }

        System.out.println("done");

    }

}

Класс примитивный и в комментариях не нуждается. Псевдокод, приведенный ниже, показывает, какая отладочная информация должна быть удалена из release-версии класса:


public class Sample {

    public static void main(String args[]) {

        System.out.println("start");

        for(int i = 0; i < 5; i++) {

#ifdef DEBUG

            System.out.println("iteration=" + i);

#endif

        }

        System.out.println("done");

    }

}

Преобразуем псевдокод в xml документ (Sample.java.xml):


<?xml version="1.0" encoding="utf-8" ?>
<prep:root xmlns:prep="http://java.preprocessor.ru"> <![CDATA[

public class Sample {

    public static void main(String args[]) {

        System.out.println("start");

        for(int i = 0; i < 5; i++) {

// <-- ]]> <prep:debug> <![CDATA[

            System.out.println("iteration=" + i);

// --> ]]> </prep:debug> <![CDATA[

        }

        System.out.println("done");

    }

}

// ]]> </prep:root>

На приведенном выше листинге представлен xml документ с корневым элементом root. У него есть три дочерних элемента: блок текста, элемент debug и блок текста. В свою очередь элемент debug имеет один дочерний элемент - блок текста. Все элементы принадлежат пространству имен prep (сокращение от preprocessor). Блоки текста ограничиваются парой "" для того чтобы xml процессор не интерпретировал их содержание как xml разметку. Имена элементов root и debug выбраны произвольно, так же как и пространство имен.

Далее необходимо получить из xml документа Sample.java.xml компилируемый java файл. Для этого создадим две таблицы стилей xsl. Одна будет преобразовывать документ Sample.java.xml так чтобы строка System.out.println("iteration=" + i); оставалась в получаемом java файле, а другая так чтобы эта строка удалялась. Первую таблицу стилей назовем debug.xsl, т.к. после ее применения в выходном java файле останется вся отладочная информация, а вторую release.xsl.


(debug.xsl):

<?xml version="1.0" ?<

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

    xmlns:prep="http://java.preprocessor.ru">

<xsl:output method="text"/>

<xsl:output omit-xml-declaration="yes"/>

<xsl:output encoding="utf-8"/>

<xsl:template match="/">

    <xsl:apply-templates />

</xsl:template>

<xsl:template match="*|@*|text()">

    <xsl:copy>

        <xsl:apply-templates select="*|@*|text()"/>

    </xsl:copy>

</xsl:template>

</xsl:stylesheet>

Есть несколько моментов, на которые следует обратить внимание при составлении любой таблицы стилей предназначенной для использования в нашем препроцессоре:

  • означает, что в результате применения данной таблицы стилей в выходном документа будут удалены элементы разметки xml;
  • означает, что в выходном документе будет отсутствовать строка ;
  • значение кодировки выходного документа (строка ) должно совпадать со значением кодировки xml документа к которому будет применена таблица стилей (Sample.java.xml(1):);
  • кодировка UTF-8 выбрана из-за того, что все xml парсеры и xsl процессоры корректно ее обрабатывают;

Воспользовавшись каким-либо xsl процессором (в данном случае XT):
java com.jclark.xsl.sax.Driver Sample.java.xml debug.xsl Sample.java

получим следующий java файл (Sample.java):


public class Sample {

    public static void main(String args[]) {

        System.out.println("start");

        for(int i = 0; i < 5; i++) {

// <--   

            System.out.println("iteration=" + i);

// -->   

        }

        System.out.println("done");

    }

}

//

Как видно из листинга, получился вполне корректный java файл без xml разметки. Следует отметить, что, число строк в оригинальном Sample.java.xml и трансформированном Sample.java файлах одинаковое. Это удобно, т.к. сообщения об ошибках компиляции, выдаваемые javac-ом можно интерпретировать в контексте оригинального Sample.java.xml.

Таблица стилей release.xsl выглядит несколько сложнее:


<?xml version="1.0" ?>

<xsl:stylesheet version="1.0"

    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"

    xmlns:prep="http://java.preprocessor.ru" >

<xsl:output method="text"/>

<xsl:output omit-xml-declaration="yes"/>

<xsl:output encoding="utf-8"/>

<xsl:template match="/">

    <xsl:apply-templates />

</xsl:template>

<xsl:template match="text()">

    <xsl:choose>

        <xsl:when test="name(following-sibling::*[1])='prep:debug'">

            <xsl:copy-of select="substring(., 0, string-length(.)-7)"/>/***</xsl:when>

        <xsl:when test="name(..)='prep:debug'">

            <xsl:copy-of select="substring(., 0, string-length(.)-7)"/>***/</xsl:when>

        <xsl:otherwise>

            <xsl:copy-of select="."/>

        </xsl:otherwise>

    </xsl:choose>

</xsl:template>

</xsl:stylesheet>

Применение release.xsl к Sample.java.xml дает следующий результат (Sample.java):


public class Sample {

    public static void main(String args[]) {

        System.out.println("start");

        for(int i = 0; i < 5; i++) {

/*** 

            System.out.println("iteration=" + i);

***/ 

        }

        System.out.println("done");

    }

}

//

Как видно из листинга Sample.java, отладочная информация оказалась закомментированной, и соответственно не будет компилироваться. Число строк в оригинальном Sample.java.xml и трансформированном Sample.java файлах одинаковое, как и в случае применения debug.xsl.

Т.о. используя различные таблицы стилей xsl можно добиться генерации нескольких java файлов на основе одного xml документа без его изменения.

Приведенные xsl файлы являются простейшими и всего лишь демонстрируют возможности предложенного подхода к построению Java-препроцессора.

В заключение следует сказать несколько слов о xsl процессорах. При разработке (если написание xsl-файлов можно назвать разработкой) препроцессора были испробованы три таких программы:
XT 20020426a http://blnz.com/xt/;
SAXON 6.2.2 http://users.iclway.co.uk/mhkay/saxon/;
XALAN 2.3.1 http://xml.apache.org/xalan-j/index.html.

Все это Java приложения, работают одинаково, но вот с кодировкой "windows-1251" справился только xalan, два других сказали, что не знают такой и отказались работать.

Файлы примеров

Автор: Alexey Semenjuk

Warning: mysql_connect() [function.mysql-connect]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/books/show2b.php on line 11

Warning: mysql_db_query() [function.mysql-db-query]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/books/show2b.php on line 19

Warning: mysql_db_query() [function.mysql-db-query]: A link to the server could not be established in /pub/home/javaport/javaportal/books/show2b.php on line 19

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /pub/home/javaport/javaportal/books/show2b.php on line 30
Узнай о чем ты на самом деле сейчас думаешь тут.


[an error occurred while processing this directive]



Warning: mysql_connect() [function.mysql-connect]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/news/worldnews.php on line 91

Warning: mysql_db_query() [function.mysql-db-query]: Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2) in /pub/home/javaport/javaportal/news/worldnews.php on line 93

Warning: mysql_db_query() [function.mysql-db-query]: A link to the server could not be established in /pub/home/javaport/javaportal/news/worldnews.php on line 93

Warning: mysql_fetch_array(): supplied argument is not a valid MySQL result resource in /pub/home/javaport/javaportal/news/worldnews.php on line 95