Mercurial > hg > tema
changeset 0:1d2fe61a3a62 release_0_1
Tema 0.1 (imported from CVS).
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/build.xml Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,33 @@ +<?xml version="1.0"?> +<project name="tema" default="dist" basedir="."> + + <property name="src" value="src"/> + <property name="build" value="build"/> + <property name="dist" value="dist"/> + <property name="res" value="res"/> + <property name="jar_file" value="tema.jar"/> + + <target name="init"> + <tstamp/> + <mkdir dir="${build}"/> + </target> + + <target name="compile" depends="init"> + <javac srcdir="${src}" destdir="${build}" + deprecation="on" optimize="on" debug="on"/> + </target> + + <target name="dist" depends="compile"> + <jar jarfile="${dist}/${jar_file}" manifest="${src}/Manifest.mf"> + <fileset dir="${build}" includes="**/*.class"/> + </jar> + </target> + + <target name="clean"> + <delete> + <fileset dir="${build}" includes="**/*.class"/> + </delete> + <delete file="${dist}/${jar_file}"/> + </target> + +</project>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/biotope-top.sql Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,20 @@ +SELECT t1.*, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 1) = Left(t1.rangcode, 1) AND +Right(t2.rangcode, 8) = '00000000') AS class0, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 3) = Left(t1.rangcode, 3) AND +Right(t2.rangcode, 6) = '000000') AS class1, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 5) = Left(t1.rangcode, 5) AND +Right(t2.rangcode, 4) = '0000') AS class2, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 7) = Left(t1.rangcode, 7) AND +Right(t2.rangcode, 2) = '00') AS class3 + +FROM biotopelist AS t1 +WHERE Right(t1.rangcode, 2) <> '00' AND rusname
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/biotope.sql Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,24 @@ +SELECT t1.*, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 1) = Left(t1.rangcode, 1) +AND Right(t2.rangcode, 8) = '00000000' +AND Right(t1.rangcode, 8) <> '00000000') AS class0, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 3) = Left(t1.rangcode, 3) +AND Right(t2.rangcode, 6) = '000000' +AND Right(t1.rangcode, 6) <> '000000') AS class1, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 5) = Left(t1.rangcode, 5) +AND Right(t2.rangcode, 4) = '0000' +AND Right(t1.rangcode, 4) <> '0000') AS class2, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 7) = Left(t1.rangcode, 7) +AND Right(t2.rangcode, 2) = '00' +AND Right(t1.rangcode, 2) <> '00') AS class3 + +FROM biotopelist AS t1 +WHERE rusname
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/biotope.template Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="ISO-8859-5"?> +<!DOCTYPE _ SYSTEM "brief.dtd"> +<!-- rangcode: <%xml_escape get\rangcode%> --> +<_ show="0"> + < display="0"> + <%optional:<_ ="1" file="<%xml_escape image:maps/<%get\rangcode%>.gif maps/<%get\code%>.png png%>"/>%> +<%query:photo_sql [%\<%include\photo.template%>%] <%get\code%>%> + </> + <><%xml_escape get\rusname%></> + <><%xml_escape get\class0%></> + <1><%xml_escape get\class1%></1> + <2><%xml_escape get\class2%></2> + <3><%xml_escape get\class3%></3> + <_ rows="3"><%xml_cdata get\descript%></_> + <_ rows="3"><%xml_cdata get\geobotdescr%></_> + <_><%xml_escape get\contributors%></_> +</_>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/brief.dtd Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,27 @@ +<?xml encoding="ISO-8859-5"?> +<!ELEMENT _ (?, , , 1, 2, 3, _, _, _)> +<!ELEMENT (|_)*> +<!ELEMENT EMPTY> +<!ELEMENT _ EMPTY> +<!ELEMENT (#PCDATA)> +<!ELEMENT (#PCDATA)> +<!ELEMENT 1 (#PCDATA)> +<!ELEMENT 2 (#PCDATA)> +<!ELEMENT 3 (#PCDATA)> +<!ELEMENT _ (#PCDATA)> +<!ELEMENT _ (#PCDATA)> +<!ELEMENT _ (#PCDATA)> +<!ATTLIST _ show (0|1) "1"> +<!ATTLIST + display CDATA #FIXED "0"> +<!ATTLIST + num ID #REQUIRED + file CDATA #REQUIRED + big CDATA #REQUIRED + text CDATA #IMPLIED + CDATA #IMPLIED> +<!ATTLIST _ + num ID #REQUIRED + file CDATA #REQUIRED> +<!ATTLIST _ rows CDATA #FIXED "3"> +<!ATTLIST _ rows CDATA #FIXED "3">
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/class.sql Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,7 @@ +SELECT t1.* +FROM biotopelist AS t1 +WHERE rusname AND Right(t1.rangcode, 8) = '00000000' + AND EXISTS + (SELECT NULL FROM biotopelist AS t2 + WHERE Left(t2.rangcode, 1) = Left(t1.rangcode, 1) + AND Right(t2.rangcode, 8) <> '00000000')
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/classes.template Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="ISO-8859-5"?> +<><%query:class_sql [%\ + <!-- rangcode: <%xml_escape get\rangcode%> --> + < id="<%get\NUMBER%>"><%xml_escape get\rusname%></>%]%> +</>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/main.template Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,11 @@ +<%!: + <%prepare:biotope_sql <%read\biotope.sql%>%> + <%prepare:photo_sql <%read\photo.sql%>%> + <%prepare:class_sql <%read\class.sql%>%> + <%prepare:plant_sql <%read\plant.sql%>%> + + <%query:biotope_sql [%\<%write:<%get\code%>.xml <%include\biotope.template%>%> %]%> + + <%write:classes.xml <%include\classes.template%>%> + <%write:plants.xml <%include\plants.template%>%> +%>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/photo.sql Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,1 @@ +SELECT * from photos WHERE biotope = ?
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/photo.template Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,3 @@ + < num="<%xml_escape get\NUMBER%>" <%optional:="<%xml_escape get\authphoto%>" %>text="" + file="<%xml_escape image:biotopephotos/<%get\photo%> images/<%get\SUPER.code%>_<%get\NUMBER%>.jpg jpg 300 300%>" + big="<%xml_escape copy:biotopephotos/<%get\photo%> images/big/<%get\SUPER.code%>_<%get\NUMBER%>.jpg%>"/>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/plant.sql Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,3 @@ +SELECT t1.* +FROM biotopelist AS t1 +WHERE rusname AND Right(t1.rangcode, 2) <> '00'
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/plants.template Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="ISO-8859-5"?> +<><%query:plant_sql [%\ + <!-- rangcode: <%xml_escape get\rangcode%> --> + <><%xml_escape get\rusname%></>%]%> +</>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/biotopes/tema.properties Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,22 @@ +# Data source configuration +resource : jdbc:odbc:biotopes-data +driver : sun.jdbc.odbc.JdbcOdbcDriver + +# Base directory for images and files +resource_base : C:\\biotopes\\db + +# Template to start processing with +main_template : main.template + +# File encodings +input_encoding : ISO-8859-5 +output_encoding : ISO-8859-5 + +# Cache templates +cache_read : true + +# Output main_template parsing result to stderr +#output : stderr + +# File to output error messages (redirect stderr) +#log : tema.log
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/readme.html Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,86 @@ +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" + "DTD/xhtml1-transitional.dtd"> + +<html> + +<head> + <title>DbReader</title> + <meta http-equiv="Content-Type" content="text/html; charset=koi8-r" /> +</head> + +<body> +<h1>DbReader</h1> + +<h2> </h2> +<ol> +<li> .</li> + +<li> :<br /> + Windows 2000: // (ODBC), biotopes-data.mdb.</li> + +<li> :<br /> + dbreader.properties , :<br /> + <code>resource: jdbc:odbc:<em></em></code><br /> + , ( biotopephotos maps):<br /> + <code>resource_base: C:\\biotopes</code><br /> +( '\' )</li> + +<li> :<br /> +<code>dbreader.bat</code> <br /> +<code>java -jar dbreader.jar</code>.<br /> + Java Runtime Environment (JRE) 5.0, <a href="http://java.sun.com/j2se/1.5.0/download.jsp">http://java.sun.com/j2se/1.5.0/download.jsp</a>. , JRE - . + + :<br /> + <code>java -Dru.karrc.dbreader.<em></em>=<em></em> -jar dbreader.jar</code><br /> +(: <code>java -Dru.karrc.dbreader.log=dbreader.log -jar dbreader.jar</code>)</li> +</ol> + +<h2> </h2> + +<p> biotope.sql ( , dbreader.properties), biotope.template, .</p> +<p> : <code><%<em>_</em>[:|\]<em></em>%></code>, <em> </em> - , . , .</p> + +<h3> </h3> + +<ul> + <li><code>:</code> - .</li> + <li><code>\</code> - . <code><%</code> <code>%></code> (<code><%\<%%></code> <code><%\%%>></code>).</li> +</ul> + +<h3></h3> + +<ul> + <li><code><%get:<em></em>%></code><br /> + .</li> + + <li><code><%optional:<em></em>%></code><br /> + <em></em>, , , .</li> + + <li><code><%escape:<em></em>%></code><br /> + "" ( ).</li> + + <li><code><%invoke:<em></em>; <em>1</em> <em>2</em> ... <em>N</em>%></code><br /> + <em></em>.sql <em></em>.template. '?'.</li> + + <li><code><%image:<em>_</em> <em>_</em> <em></em> [<em>_</em>] [<em>_</em>]%></code><br /> + <em>_</em> ( "resource_base") , <em>_</em>. , . + , <code><%image:...%></code> <em>_</em>, - .</li> + + <li><code><%copy:<em>_</em> <em>_</em>%></code><br /> + <em>_</em> ( "resource_base") <em>_</em>. , <code><%copy:...%></code> <em>_</em>, - .</li> +</ul> + +<h3> </h3> + +<p><code>NUMBER</code> - . + , invoke, <code>SUPER.</code> (: <code>SUPER.NUMBER</code>).</p> + +<h3></h3> + +<p> name :</p> +<p><code><%escape get:name%></code></p> + +<p align="right"><i><a href="mailto:kryshen@cs.karelia.ru"> </a></i></p> + +</body> +</html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/readme.txt Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,63 @@ +text/plain; charset=UTF-8 + +Установка программы +------------------- + +1. Распаковать архив. + +2. Установить источник данных: +в Windows 2000: Панель управления/Администрирование/Источники данных (ODBC), добавить biotopes.mdb. + +3. Настроить программу: +В файле dbreader.properties указать имя, присвоенное источнику данных: + "resource: jdbc:odbc:<имя>" +и путь к каталогу, относительно которого программа будет искать изображения (содержащий biotopephotos и maps): + "resource_base: C:\\biotopes" +(символ '\' необходимо дублировать) + +4. Запуск программы: dbreader.bat или "java -jar dbreader.jar" +Для запуска необходима Java Runtime Environment (JRE) 5.0, можно скачать с http://java.sun.com/j2se/1.5.0/download.jsp. Возможно, будет работать и со старыми версиями JRE - не проверял. + +Все значения файла конфигурации можно переопределять при запуске программы: + команда "java -Dru.karrc.dbreader.<ключ>=<значение> -jar dbreader.jar" +(например: "java -Dru.karrc.dbreader.log=dbreader.log -jar dbreader.jar") + + +Работа программы +---------------- + +Программа выполняет запрос biotope.sql (или другой, указанный в dbreader.properties), после чего обрабатывает файл biotope.template, заменяя найденные в нем инструкции на результаты их выполнения. + +Формат инструкций: "<%список_функций[:|\]данные%>", список функций - имена функций разделенные пробелом, список может быть пустым. Если указано несколько функций, они выполняются начиная с последней. + +Разделители между списком функций и данными: +':' - данные будут обрабатываться рекурсивно. +'\' - данные будут переданы функции без обработки. Можно использовать для экранирования комбинаций символов "<%" и "%>" ("<%\<%%>" и "<%\%%>>"). + +Функции: +<%get:<имя>%> - заменяется на значение встроенной переменной или колонки запроса. + +<%optional:<текст>%> +Заменяется на <текст>, если в нем найдены инструкции, заменившиеся на непустые строки, иначе заменяется на пустую строку. + +<%escape:<текст>%> +Заменяет в тексте "опасные" символы (таблица замен задается в файле конфигурации). + +<%invoke:<имя> <парам1> <парам2> ... <парамN>%> +Выполняет запрос с параметрами <имя>.sql и заменяется на результаты обработки шаблона <имя>.template. Значения параметров подставляются в запрос вместо символа '?'. + +<%image:<исх_файл> <кон_файл> <формат> [<макс_ширина>] [<макс_высота>]%> +Загружает изображение из файла <исх_файл> (путь определяется относительно конфигурационного параметра "resource_base") и преобразует его в указанный формат, сохраняя результат в <кон_файл>. Если заданы максимальная высота и ширина, большие изображения будут уменьшены. +При успешном выполнении, инструкция "<%!image ...%>" будет заменена на значение <кон_файл>, иначе - на пустую строку. + +<%copy:<исх_файл> <кон_файл>%> +Копирует файл <исх_файл> (путь определяется относительно конфигурационного параметра "resource_base"). +При успешном выполнении, инструкция "<%!copy ...%>" будет заменена на значение <кон_файл>, иначе - на пустую строку. + +Встроенные переменные: +NUMBER - порядковый номер строки результата выполнения запроса. +Чтобы обратиться к переменной запроса, из которого обрабатываемый шаблон был вызван с помощью функции invoke, перед именем переменной нужно добавить "SUPER." (например: "SUPER.NUMBER"). + +Пример: +Следующая инструкция получит значение из столбца name и заменит в нем специальные символы: +<%escape get:name%>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/tema Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,3 @@ +#!/bin/sh + +java -jar tema.jar
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/tema.bat Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,1 @@ +java -jar tema.jar
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dist/tema.properties Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,22 @@ +# Data source configuration +# resource : jdbc:odbc:biotopes-data +# driver : sun.jdbc.odbc.JdbcOdbcDriver + +# Base directory for images and files +# resource_base : C:\\biotopes\\db + +# Template to start processing with +main_template : main.template + +# File encodings +# input_encoding : ISO-8859-5 +# output_encoding : ISO-8859-5 + +# Cache templates +cache_read : true + +# Output main_template parsing result to stderr +#output : stderr + +# File to output error messages (redirect stderr) +#log : tema.log
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/doc/article.txt Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,391 @@ +* XML- . + + " +" Microsoft Access XML- + DbReader. + + DbReader + . + + . + SQL-, +. + + +* : + + <%<_>{:|\}<>%> + + +<_> - , . + . +<> - , . + + +* : + + [<_>][<>] + + +<_> - , . + . +<> - , . + . , + , . + + , + : +: - , +\ - . + + , , + , + . + + - . + - . , + - +. + + '<', '>' '[', ']'. + + +* : + +: set +: <> +: <> +: <> +: <> + : 1 + +: get +: <> +: <>. + : 1, , 0 - . + +: prepare +: <> +: <> +: SQL- <> , + <>. +: <> + : 1 + +: query +: <_> <> <1> ... <N> +: , + prepare. + '?'. + , <>. + <> NUMBER, + . , + , + <> SUPER.<_>. + +: <> + . + : . + +: optional +: <> +: <>, + 0, - . + : 1, - , 0 - . + +: image +: <_> <_> <> [<_> [<_>]] +: <_> ( + "resource_base") + , + <_>. , + . +: <_> , - . + : 1 , 0 - . + +: copy +: <_> <_> +: <_> <_> + ( <_> + "resource_base"). +: <_> , - . + : 1 , 0 - . + +: write +: <_> +: <> +: <> <_>. +: <_> , - . + : 1 , 0 - . + +: read +: <_> +: <_>. +: , + - . + : 1 , 0 - . + +: include +: <_> +: <_>. +: . + : , . + +: ! +: <> +: . +: . + : , . + +: replace +: <1> <2> +: <> +: , <1> + <2>. + : , . + +: xml_escape +: <> +: <>, + '&', '<', '>', '`', '\' + XML. + : , . + +: xml_cdata +: <> +: XML CDATA. + : , . + + DbReader : +, Java. + + +* DbReader + " " Microsoft Access + XML- + + " + " ( ): + +biotopelist (code, rangcode, rusname, engname, descript, geobotdescr, + contributors, descrdate) + + code - , ; + rangcode - ABBCCDDEE, , BB, CC, DD, - + , ; + rusname, engname, descript, geobotdescr - ; + descrdate - . + +photos (biotope, photo, authphoto) + + biotope - , code biotopelist; + photo - ; + authphoto - . + + xml- biotopelist, + , , + . + + xml- + DbReader ( biotope.template): + +---------------------------------------------------------------------- +<?xml version="1.0" encoding="ISO-8859-5"?> +<!DOCTYPE _ SYSTEM "brief.dtd"> +<!-- rangcode: <%xml_escape get\rangcode%> --> +<_ show="0"> + < display="0"> + <%optional:<_ ="1" + file="<%xml_escape image:maps/<%get\rangcode%>.gif maps/<%get\code%>.png png%>"/>%> +<%query:photo_sql [%\<%include\photo.template%>%] <%get\code%>%> + </> + <><%xml_escape get\rusname%></> + <><%xml_escape get\class0%></> + <1><%xml_escape get\class1%></1> + <2><%xml_escape get\class2%></2> + <3><%xml_escape get\class3%></3> + <_ rows="3"><%xml_cdata get\descript%></_> + <_ rows="3"><%xml_cdata get\geobotdescr%></_> + <_><%xml_escape get\contributors%></_> +</_> +---------------------------------------------------------------------- + + SQL-, + rangcode, rusname, class0, class1, class2, +class3, descript, geobotdescr contributors ( biotope.sql): + +---------------------------------------------------------------------- +SELECT t1.*, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 1) = Left(t1.rangcode, 1) +AND Right(t2.rangcode, 8) = '00000000' +AND Right(t1.rangcode, 8) <> '00000000') AS class0, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 3) = Left(t1.rangcode, 3) +AND Right(t2.rangcode, 6) = '000000' +AND Right(t1.rangcode, 6) <> '000000') AS class1, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 5) = Left(t1.rangcode, 5) +AND Right(t2.rangcode, 4) = '0000' +AND Right(t1.rangcode, 4) <> '0000') AS class2, + +(SELECT t2.rusname FROM biotopelist AS t2 +WHERE Left(t2.rangcode, 7) = Left(t1.rangcode, 7) +AND Right(t2.rangcode, 2) = '00' +AND Right(t1.rangcode, 2) <> '00') AS class3 + +FROM biotopelist AS t1 +WHERE rusname +---------------------------------------------------------------------- + + biotope.template <%include\photo.template%>, + ( photo.template): + +---------------------------------------------------------------------- + < num="<%xml_escape get\NUMBER%>" + <%optional:="<%xml_escape get\authphoto%>" %>text="" + file="<%xml_escape image:biotopephotos/<%get\photo%> images/<%get\SUPER.code%>_<%get\NUMBER%>.jpg jpg 300 300%>" + big="<%xml_escape copy:biotopephotos/<%get\photo%> images/big/<%get\SUPER.code%>_<%get\NUMBER%>.jpg%>"/> +---------------------------------------------------------------------- + + SQL- +(photo.sql): + +---------------------------------------------------------------------- +SELECT * from photos WHERE biotope = ? +---------------------------------------------------------------------- + +, ( classes.template): + +---------------------------------------------------------------------- +<?xml version="1.0" encoding="ISO-8859-5"?> +<><%query:class_sql [%\ + <!-- rangcode: <%xml_escape get\rangcode%> --> + < id="<%get\NUMBER%>"><%xml_escape get\rusname%></>%]%> +</> +---------------------------------------------------------------------- + + SQL- (class.sql): + +---------------------------------------------------------------------- +SELECT t1.* +FROM biotopelist AS t1 +WHERE rusname AND Right(t1.rangcode, 8) = '00000000' + AND EXISTS + (SELECT NULL FROM biotopelist AS t2 + WHERE Left(t2.rangcode, 1) = Left(t1.rangcode, 1) + AND Right(t2.rangcode, 8) <> '00000000') +---------------------------------------------------------------------- + +, ( plants.template): + +---------------------------------------------------------------------- +<?xml version="1.0" encoding="ISO-8859-5"?> +<><%query:plant_sql [%\ + <!-- rangcode: <%xml_escape get\rangcode%> --> + <><%xml_escape get\rusname%></>%]%> +</> +---------------------------------------------------------------------- + + SQL- (plant.sql): + +---------------------------------------------------------------------- +SELECT t1.* +FROM biotopelist AS t1 +WHERE rusname AND Right(t1.rangcode, 2) <> '00' +---------------------------------------------------------------------- + + DbReader index.template, + SQL- +: + +---------------------------------------------------------------------- +<%!: + <%prepare:biotope_sql <%read\biotope.sql%>%> + <%prepare:photo_sql <%read\photo.sql%>%> + <%prepare:class_sql <%read\class.sql%>%> + <%prepare:plant_sql <%read\plant.sql%>%> + + <%query:biotope_sql [%\<%write:<%get\code%>.xml <%include\biotope.template%>%> %]%> + + <%write:classes.xml <%include\classes.template%>%> + <%write:plants.xml <%include\plants.template%>%> +%> +---------------------------------------------------------------------- + + XML-: + +---------------------------------------------------------------------- +<?xml version="1.0" encoding="ISO-8859-5"?> +<!DOCTYPE _ SYSTEM "brief.dtd"> +<!-- rangcode: E04020302 --> +<_ show="0"> + < display="0"> + < num="1" =" .." text="" + file="images/3_1.jpg" + big="images/big/3_1.jpg"/> + < num="2" =" .." text="" + file="images/3_2.jpg" + big="images/big/3_2.jpg"/> + </> + <>Betula sp. - Avenella flexuosa - Polytrichum commune</> + <>E. </> + <1> </1> + <2></2> + <3></3> + <_ rows="3"><![CDATA[ . 5 - 7 , , , .]]></_> + <_ rows="3"></_> + <_></_> +</_> +---------------------------------------------------------------------- + + +* DbReader + + DbReader Java + : + +ru.karrc.dbreader.DbReader: c . +, + JDBC, . + +ru.karrc.dbreader.TemplateParser: , + . + +ru.karrc.dbreader.Function: . +DbReader . + +ru.karrc.dbreader.FunctionDataParser: +. , +. + TemplateParser. + +ru.karrc.dbreader.Functions: + , Function. + +ru.karrc.dbreader.TemplateParser: , + . + + , , + . + + +* . + + : 8, + Java- ( ): 27, + : 1311, + ( ): 812, + : 180. + + +* + + DbReader, + + . +DbReader " " + XML- .
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sample/class.xml Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="ISO-8859-5"?> +<> + < id="1"> </> + < id="2"> </> + < id="3"> </> + < id="4">, </> + < id="5"> </> + < id="6"> </> +</>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sample/plants.xml Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="ISO-8859-5"?> +<> + <>Betula sp.</> + <>Calamagrostis arundinacea</> + <>Geranium sylvaticum</> +</>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/Manifest.mf Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,2 @@ +Manifest-Version: 1.0 +Main-Class: kryshen.tema.Tema
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/kryshen/tema/Function.java Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2005, 2006 Mikhail A. Kryshen + * + * $Id: Function.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $ + */ + +package kryshen.tema; + +import java.io.*; +import java.util.*; +import java.sql.ResultSet; + +public abstract class Function { + public final String name; + + protected Function(String name) { + this.name = name; + } + + public abstract int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/kryshen/tema/FunctionDataParser.java Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2006 Mikhail A. Kryshen + * + * $Id: FunctionDataParser.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $ + */ + +package kryshen.tema; + +import java.io.*; +import java.util.*; + +import static kryshen.tema.TemplateParser.Result; +import static kryshen.tema.TemplateParser.FunctionData; +import static kryshen.tema.TemplateParser.Terminator; + +/** + * Parser for a function data. + * + * @author Mikhail A. Kryshen + */ +public class FunctionDataParser { + static final char[] ARG_SEPARATORS = TemplateParser.LIST_SEPARATORS; + + private TemplateParser tp; + private FunctionData fd; + private Reader in; + + private boolean available = true; + private boolean first = true; + + FunctionDataParser(TemplateParser tp, FunctionData fd, + Reader in) { + this.tp = tp; + this.fd = fd; + this.in = in; + } + + private TemplateParser.Result parseData(Writer out, boolean argument) + throws IOException, TemplateException { + + if (!available) + throw new TemplateException + ("Unexpected end of instruction data."); + + TemplateParser.Result r; + + if (fd == FunctionData.RECURSIVE) { + r = tp.parse(in, out, true, + argument ? ARG_SEPARATORS : null, + (argument || !first) ? ARG_SEPARATORS : null); + } else if (fd == FunctionData.NONRECURSIVE) { + r = tp.parse(in, out, false, + argument ? ARG_SEPARATORS : null, + (argument || !first) ? ARG_SEPARATORS : null); + } else if (fd == FunctionData.SUBFUNCTION && argument) { + /* Subfunction can pass a list of arguments */ + StringWriter sw = new StringWriter(); + tp.parseFunction(in, sw); + sw.close(); + in = new StringReader(sw.toString()); + fd = FunctionData.NONRECURSIVE; + r = parseData(out, true); + } else if (fd == FunctionData.SUBFUNCTION) { + r = new Result(null, tp.parseFunction(in, out), false); + } else { + throw new IllegalArgumentException("Invalid FunctiodData: " + fd); + } + + if (r.terminator != TemplateParser.Terminator.SEPARATOR) + available = false; // No more function data available. + + first = false; + return r; + } + + public int parseData(Writer out) throws IOException, TemplateException { + return parseData(out, false).substitutions; + } + + public String getData() throws IOException, TemplateException { + StringWriter sw = new StringWriter(); + parseData(sw); + sw.close(); + return sw.toString(); + } + + public int parseNextArg(Writer out) throws IOException, TemplateException { + TemplateParser.Result r = parseData(out, true); + + // Ignore empty arguments. + while (r.empty && available) { + r = parseData(out, true); + } + + return r.substitutions; + } + + public String getNextArg() throws IOException, TemplateException { + StringWriter sw = new StringWriter(); + parseNextArg(sw); + sw.close(); + return sw.toString(); + } + + public List<String> getArgs() throws IOException, TemplateException { + List<String> l = new ArrayList<String>(); + + while (available) { + l.add(getNextArg()); + } + + return l; + } + + public boolean hasMoreData() { + return available; + } + + public TemplateParser getTemplateParser() { + return tp; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/kryshen/tema/Functions.java Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,336 @@ +/* + * Copyright (C) 2005, 2006 Mikhail A. Kryshen + * + * $Id: Functions.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $ + */ + +package kryshen.tema; + +import java.io.*; +import java.util.*; + +import java.sql.SQLException; +import java.sql.PreparedStatement; + +import kryshen.tema.functions.*; + +public class Functions { + public static final Function GET = + new Function("get") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + String name = fdp.getData(); + return fdp.getTemplateParser().parseVariable(name, out); + } + }; + + public static final Function SET = + new Function("set") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + String arg0 = fdp.getNextArg(); + String arg1 = fdp.getData(); + + fdp.getTemplateParser().setValue(arg0, arg1); + + out.write(arg0); + return 1; + } + }; + + /* prepare:qury_name sql_statement */ + public static final Function PREPARE = + new Function("prepare") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + String arg0 = fdp.getNextArg(); + String data = fdp.getData(); + + PreparedStatement statement; + + try { + statement = Tema.connection.prepareStatement(data); + } catch (SQLException e) { + throw new TemplateException(e.getMessage(), e); + } + + fdp.getTemplateParser().setValue(arg0, statement); + + out.write(arg0); + return 1; + } + }; + + public static final Function OPTIONAL = + new Function("optional") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + StringWriter sw = new StringWriter(); + int s = fdp.parseData(sw); + sw.close(); + String data = sw.toString(); + + if (s > 0) { + out.write(data); + return 1; + } else { + return 0; + } + } + }; + + public static final Function IMAGE = + new Function("image") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + String arg0 = fdp.getNextArg(); + String arg1 = fdp.getNextArg(); + String arg2 = fdp.getNextArg(); + int arg3 = fdp.hasMoreData() ? + Integer.parseInt(fdp.getNextArg()) : -1; + int arg4 = fdp.hasMoreData() ? + Integer.parseInt(fdp.getNextArg()) : -1; + + File source = new File + (Tema.getProperty("resource_base"), arg0); + + try { + ImageConverter.convert + (source, /* source file */ + new File(arg1), /* dest file */ + arg2, /* format */ + arg3, /* max width */ + arg4); /* max height */ + } catch (Exception e) { + System.err.println(e); + return 0; + } + + out.write(arg1); + return 1; + } + }; + + public static final Function COPY = + new Function("copy") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + String arg0 = fdp.getNextArg(); + String arg1 = fdp.getNextArg(); + + File source = new File + (Tema.getProperty("resource_base"), arg0); + File dest = new File(arg1); + + try { + copyFile(source, dest); + } catch (IOException e) { + System.err.println(e); + return 0; + } + out.write(arg1); + return 1; + } + }; + + /* query:sql_query template arg1 arg2 ... argN */ + public static final Function QUERY = + new Function("query") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + String arg0 = fdp.getNextArg(); + String arg1 = fdp.getNextArg(); + List<String> args = fdp.getArgs(); + + TemplateParser tp = fdp.getTemplateParser(); + + try { + return Tema.query + (arg1, (PreparedStatement)tp.getValue(arg0), + args, tp, out); + } catch (SQLException e) { + throw new TemplateException(e.getMessage(), e); + } + } + }; + + public static final Function WRITE = + new Function("write") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + String arg0 = fdp.getNextArg(); + + System.err.println("Writing " + arg0 + "..."); + + Writer fw; + + try { + fw = Tema.createFileWriter(arg0); + } catch (IOException e) { + System.err.println(e); + return 0; + } + + try { + fdp.parseData(fw); + } finally { + fw.close(); + } + + out.write(arg0); + + System.err.println("Saved " + arg0 + "."); + return 1; + } + }; + + public static final Function READ = + new Function("read") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + String filename = fdp.getData(); + String file; + + try { + file = Tema.readFile(new File(filename)); + } catch (IOException e) { + System.err.println(e); + return 0; + } + + out.write(file); + return 1; + } + }; + + public static final Function INCLUDE = + new Function("include") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + String filename = fdp.getData(); + + Reader fin = new BufferedReader + (Tema.createCachedFileReader(new File(filename))); + + int r = fdp.getTemplateParser().parse(fin, out); + + fin.close(); + return r; + } + }; + + public static final Function NULL_OUTPUT = + new Function("!") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + /* Write nothing. */ + return fdp.parseData(new Writer() { + public void close() {} + public void flush() {} + public void write(char[] cbuf, int off, int len) {} + }); + } + }; + + public static final Function REPLACE = + new Function("replace") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + String arg0 = fdp.getNextArg(); + String arg1 = fdp.getNextArg(); + + ReplaceWriter rw = new ReplaceWriter(out, arg0, arg1); + + int ret = fdp.parseData(rw); + rw.finish(); + return ret; + } + }; + + public static final Function XML_ESCAPE = + new Function("xml_escape") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + final String[] chars = {"&", "<", ">", "`", "\""}; + final String[] escape = {"&", "<", ">", "'", """}; + + ReplaceWriter rw = new ReplaceWriter(out, chars, escape); + + int ret = fdp.parseData(rw); + rw.finish(); + return ret; + } + }; + + public static final Function XML_CDATA = + new Function("xml_cdata") { + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + ReplaceWriter rw = new ReplaceWriter + (out, "]]>", "]]]><![CDATA[]>", "<![CDATA[", "]]>"); + + int ret = fdp.parseData(rw); + rw.finish(); + return ret; + } + }; + + public static final Function DEFINE = new Define(); + + private static void copyFile(File src, File dest) throws IOException { + System.err.print("Copying " + src + "... "); + + if (src.lastModified() < dest.lastModified()) { + System.err.println(dest + " is up to date."); + return; + } + + File parent = dest.getParentFile(); + if (parent != null) parent.mkdirs(); + + InputStream in = new FileInputStream(src); + OutputStream out = new FileOutputStream(dest); + + byte[] buffer = new byte[1024]; + int len; + while ((len = in.read(buffer)) > 0) { + out.write(buffer, 0, len); + } + in.close(); + out.close(); + + System.err.println("saved " + dest + "."); + } + + static void registerAllFunctions(TemplateParser p) { + p.registerFunction(GET); + p.registerFunction(SET); + p.registerFunction(OPTIONAL); + p.registerFunction(IMAGE); + p.registerFunction(COPY); + p.registerFunction(QUERY); + p.registerFunction(PREPARE); + p.registerFunction(WRITE); + p.registerFunction(READ); + p.registerFunction(INCLUDE); + p.registerFunction(NULL_OUTPUT); + p.registerFunction(REPLACE); + p.registerFunction(XML_ESCAPE); + p.registerFunction(XML_CDATA); + p.registerFunction(DEFINE); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/kryshen/tema/ImageConverter.java Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,184 @@ +/* + * Copyright (C) 2005, 2006 Mikhail A. Kryshen + * + * $Id: ImageConverter.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $ + */ + +package kryshen.tema; + +import java.util.*; +import java.io.*; +import java.awt.*; +import java.awt.image.*; +import java.awt.geom.AffineTransform; +import javax.imageio.*; +import javax.imageio.stream.*; + +/** + * Class defines static method to convert images to specified format. + * + * @author Mikhail A. Kryshen + */ +class ImageConverter { + + static void convert(File source, File dest, String format, + int maxWidth, int maxHeight) + throws IOException, InterruptedException { + + System.err.print("Converting image " + source + "... "); + + if (source.lastModified() < dest.lastModified()) { + System.err.println(dest + " is up to date."); + return; + } + + BufferedImage image = ImageIO.read(source); + + //int type = image.getType(); + //final int type = BufferedImage.TYPE_INT_RGB; + //ColorModel cm = image.getColorModel(); + + int w = image.getWidth(null); + int h = image.getHeight(null); + + //boolean scale = false; + + float scale = 1f; + + if (maxWidth > 0 && w > maxWidth) + scale = (float)maxWidth / w; + + if (maxHeight > 0 && h * scale > maxHeight) + scale = (float)maxHeight / h; + + if (scale != 1f) { + w *= scale; h *= scale; + +// ColorModel cm = image.getColorModel(); +// boolean alphaPremultiplied = cm.isAlphaPremultiplied(); +// WritableRaster raster = cm.createCompatibleWritableRaster(w, h); +// BufferedImage scaled = new BufferedImage +// (cm, raster, alphaPremultiplied, null); + +// BufferedImage scaled = new BufferedImage(w, h, image.getType()); + + + Image scaled = image.getScaledInstance(w, h, Image.SCALE_SMOOTH); + + ColorModel cm = image.getColorModel(); + boolean alphaPremultiplied = image.isAlphaPremultiplied(); + WritableRaster raster = cm.createCompatibleWritableRaster(w, h); + image = new BufferedImage(cm, raster, alphaPremultiplied, null); + + Graphics g = image.getGraphics(); + g.drawImage(scaled, 0, 0, null); + g.dispose(); + +// image = scale(image, scaled, scale); +// Graphics2D g = scaled.createGraphics(); +// g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, +// RenderingHints.VALUE_INTERPOLATION_BILINEAR); +// System.err.print(" " + g.drawImage(image, 0, 0, w, h, null) + " "); +// g.dispose(); +// image = scaled; + } + + File parent = dest.getParentFile(); + if (parent != null) parent.mkdirs(); + + ImageIO.write(image, format, dest); + System.err.println("saved " + dest + "."); + } + +// public static ColorModel getColorModel(Image image) +// throws InterruptedException { + +// PixelGrabber grabby = new PixelGrabber(image, 0, 0, 1, 1, false); +// if (!grabby.grabPixels()) +// throw new RuntimeException("pixel grab fails"); +// return grabby.getColorModel(); +// } + +// private static BufferedImage scale(BufferedImage image, +// BufferedImage dest, +// float scale) { + +// AffineTransform tx = new AffineTransform(); +// tx.scale(scale, scale); + +// AffineTransformOp op = new AffineTransformOp +// (tx, AffineTransformOp.TYPE_BILINEAR); + +// return op.filter(image, dest); +// } + + // TEST + + public static void main(String[] args) + throws IOException, InterruptedException { + + convert(new File(args[0]), new File(args[1]), "png", 300, 300); + } + + +// public static BufferedImage toBufferedImage(Image image, ColorModel cm) { +// if (image instanceof BufferedImage) +// return (BufferedImage)image; + +// int w = image.getWidth(null); +// int h = image.getHeight(null); + +// boolean alphaPremultiplied = cm.isAlphaPremultiplied(); +// WritableRaster raster = cm.createCompatibleWritableRaster(w, h); +// BufferedImage result = new BufferedImage(cm, raster, alphaPremultiplied, null); +// Graphics2D g = result.createGraphics(); + +// g.drawImage(image, 0, 0, null); +// g.dispose(); + +// return result; +// } +} + + +// This is how I'd recommend it in JDK1.4 using javax.imageio.ImageIO to +// do the reading/writing and Java2D to do the scaling. + +// // read in the original image +// BufferedImage in = ImageIO.read(new File("in.jpg")); + +// // create a new image of the smaller size +// BufferedImage out = new BufferedImage(newWidth, newHeight); + +// // get the graphics associated with the new image +// Graphics g = out.getGraphics(); + +// // draw the original image into the new image, scaling +// // on the fly +// g.drawImage(in, newWidth, newHeight, null); + +// // dispose the graphics object +// g.dispose(); + +// // write out the new image +// ImagIO.write("out.jpg", "jpeg", new File("out.jpg")); + +// ------------------------------------------ + +// For nicer scaling, you could add a rendering hint to the graphics +// object before painting. + +// ie. + +// Graphics2D g2d = (Graphics2D)g; +// g2d.setRenderingHint(RenderingHints.KEY_INTEPOLATION, +// RenderingHints.VALUE_INTERPOLATION_BILINEAR); + +// or use VALUE_INTERPOLATION_BICUBIC for the best. + +// But as you can guess, nicer == slower. + +// Shannon Hickey +// shann...@swingteam.com +// Swing Team http://TheSwingConnection.com http://TheJavaTutorial.com +// Java Software, a division of Sun Microsystems, Inc.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/kryshen/tema/ReplaceWriter.java Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2006 Mikhail A. Kryshen + * + * $Id: ReplaceWriter.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $ + */ + +package kryshen.tema; + +import java.io.Writer; +import java.io.FilterWriter; +import java.io.IOException; + +import java.util.LinkedList; +import java.util.Iterator; + +/** + * FilterWriter which replaces characters with escape strings. + * + * @author Mikhail A. Kryshen + */ +class ReplaceWriter extends FilterWriter { + private String[] patterns; + private String[] replaces; + + private String prefix; + private String postfix; + + private int maxPatternLength = 0; + + /** Had this Writer processed any data? */ + private boolean processedData = false; + + private StringBuffer buffer = new StringBuffer(); + + public ReplaceWriter(Writer w, String pattern, String replace) { + this(w, new String[]{pattern}, new String[]{replace}); + } + + public ReplaceWriter(Writer w, String pattern, String replace, + String prefix, String postfix) { + + this(w, new String[]{pattern}, new String[]{replace}, + prefix, postfix); + } + + public ReplaceWriter(Writer w, String[] patterns, String[] replaces) { + this(w, patterns, replaces, null, null); + } + + public ReplaceWriter(Writer w, String[] patterns, String[] replaces, + String prefix, String postfix) { + super(w); + + this.patterns = patterns; + this.replaces = replaces; + + this.prefix = prefix; + this.postfix = postfix; + + for (int i = 0; i < patterns.length; i++) { + int length = patterns[i].length(); + if (length > maxPatternLength) + maxPatternLength = length; + } + } + + private boolean processBuffer(int minLength) throws IOException { + if (buffer.length() == 0) return false; + + if (!processedData) { + if (prefix != null) + super.write(prefix, 0, prefix.length()); + processedData = true; + } + + int k; + for (k = 0; minLength + k < buffer.length(); k++) { + for (int i = 0; i < patterns.length; i++) { + String pattern = patterns[i]; + int length = pattern.length(); + + if (length + k > buffer.length()) + continue; + + boolean match = true; + + for (int j = 0; j < length; j++) { + if (pattern.charAt(j) != buffer.charAt(j + k)) { + match = false; + break; + } + } + + if (match) { + super.write(buffer.substring(0, k), 0, k); + buffer.delete(0, k + length); + super.write(replaces[i], 0, replaces[i].length()); + return true; + } + } + } + + super.write(buffer.substring(0, k), 0, k); + buffer.delete(0, k); + + return false; + } + + public void write(int c) throws IOException { + buffer.append((char)c); + processBuffer(maxPatternLength); + } + + public void write(char[] cbuf, int off, int len) throws IOException { + for (int i = off; i < off + len; i++) { + buffer.append(cbuf[i]); + } + processBuffer(maxPatternLength); + } + + public void write(String str, int off, int len) throws IOException { + buffer.append(str.substring(off, off + len)); + processBuffer(maxPatternLength); + } + + public void finish() throws IOException { + while (processBuffer(0)); + +// super.write(buffer.toString(), 0, buffer.length()); +// buffer.delete(0, buffer.length()); + + if (processedData && postfix != null) + super.write(postfix, 0, postfix.length()); + } + + public void close() throws IOException { + finish(); + super.close(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/kryshen/tema/Tema.java Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,237 @@ +/* + * Copyright (C) 2005, 2006 Mikhail A. Kryshen + * + * $Id: Tema.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $ + */ + +package kryshen.tema; + +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.Connection; +import java.sql.Statement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; + +import java.util.Map; +import java.util.HashMap; +import java.util.Properties; +import java.util.List; +import java.util.Collections; + +import java.io.*; + +/** + * Tema main class. + * + * @author Mikhail A. Kryshen + */ +public class Tema { + private static final String CONFIG_FILE = "tema.properties"; + private static final String ENV_PREFIX = "kryshen.tema."; + + private static Properties config = new Properties(); + static Connection connection = null; + + private static String inputEncoding; + private static String outputEncoding; + + static Map<File, String> fileCache = null; + + public static void main(String[] args) + throws IOException, TemplateException, SQLException, + ClassNotFoundException, InstantiationException, + IllegalAccessException { + + InputStream configIn = new FileInputStream(CONFIG_FILE); + config.load(configIn); + configIn.close(); + + String logFile = getProperty("log"); + if (logFile != null && logFile.length() > 0) + System.setErr(new PrintStream(new FileOutputStream(logFile))); + + if (Boolean.parseBoolean(getProperty("cache_read")) == true) + fileCache = new HashMap<File, String>(); + + inputEncoding = getProperty("input_encoding", "iso-8859-1"); + outputEncoding = getProperty("output_encoding", "iso-8859-1"); + + String resourceProperty = getProperty("resource"); + + if (resourceProperty != null) { + String driverProperty = getProperty("driver"); + if (driverProperty != null) { + // Register driver. + Driver d = (Driver)Class.forName(driverProperty).newInstance(); + } + + // Open connection. + connection = DriverManager.getConnection(resourceProperty); + } + +// String maxFilesString = getProperty("max_output_files"); +// int maxFiles = -1; +// if (maxFilesString != null) +// maxFiles = Integer.parseInt(maxFilesString); + + String main = getProperty("main_template"); + String output = getProperty("output"); + + Writer out; + + if ("stderr".equals(output)) + out = new OutputStreamWriter(System.err); + else + out = new OutputStreamWriter(System.out); + + InputStream is = new FileInputStream(main); + Reader in = new BufferedReader(new InputStreamReader(is, inputEncoding)); + + TemplateParser p = new TemplateParser(); + try { + p.parse(in, out); + } finally { + in.close(); + out.flush(); + } + + System.err.println("Done"); + } + +// private static void readEscapes() { +// for (int i = 1;; i++) { +// String pattern = getProperty("escape_char_" + i); + +// if (pattern == null) break; + +// escapes.put(pattern.charAt(0), +// getProperty("escape_string_" + i)); +// } +// } + + /** + * Get configuration property. + */ + static String getProperty(String name) { + String value = System.getProperty(ENV_PREFIX + name); + if (value != null) return value; + return config.getProperty(name); + } + + /** + * Get configuration property. + */ + static String getProperty(String name, String fallback) { + String value = getProperty(name); + if (value != null) return value; + return fallback; + } + + /** + * Process subquery and template. + * + * @param template template to fill with data. + * @param ps query statement to execute. + * @param args list of query parameters. + * @param superParser invoking object. + * @param out Writer to output processed data. + * + * @return number of processed rows in query result. + */ + static int query(String template, PreparedStatement ps, + List<String> args, + TemplateParser superParser, + Writer out) + throws IOException, SQLException, TemplateException { + + StringReader templateReader = new StringReader(template); + + int i = 1; + + for (String arg : args) { + ps.setString(i++, arg); + } + + ResultSet r = ps.executeQuery(); + ResultSetMetaData rm = r.getMetaData(); + int columnCount = rm.getColumnCount(); + + String[] names = new String[columnCount]; + + for (int j = 0; j < columnCount; j++) { + names[j] = rm.getColumnName(j + 1); + } + + TemplateParser p = new TemplateParser(superParser); + + for (i = 1; r.next(); i++) { + p.clearValues(); + + for (int j = 0; j < columnCount; j++) { + Object value = r.getObject(j + 1); + if (r.wasNull()) value = null; + + p.setValue(names[j], value); + } + + p.setValue("NUMBER", i); + p.parse(templateReader, out); + templateReader.reset(); + } + + r.close(); + ps.clearParameters(); + return i - 1; + } + + static Writer createFileWriter(String filename) throws IOException { + OutputStream os = new FileOutputStream(filename); + return new OutputStreamWriter(os, Tema.outputEncoding); + } + + static Reader createFileReader(File file) throws IOException { + InputStream is = new FileInputStream(file); + return new InputStreamReader(is, Tema.inputEncoding); + } + + static Reader createCachedFileReader(File file) throws IOException { + if (fileCache != null) return new StringReader(readFile(file)); + else return createFileReader(file); + } + + /** + * Read text file. + */ + static String readFile(File file) throws IOException { + String data; + + if (fileCache != null) { + data = fileCache.get(file); + if (data != null) return data; + } + + Reader r = new BufferedReader(createFileReader(file)); + + // FIXME: possible overflow (long -> int). + StringBuffer sb = new StringBuffer((int)file.length()); + + try { + for (int c = r.read(); c >= 0; c = r.read()) { + sb.append((char)c); + } + } finally { + r.close(); + } + + data = sb.toString(); + + if (fileCache != null) { + fileCache.put(file, data); + } + + return data; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/kryshen/tema/TemplateException.java Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2006 Mikhail A. Kryshen + * + * $Id: TemplateException.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $ + */ + +package kryshen.tema; + +/** + * Signals that template parsing fails. + * + * @author Mikhail A. Kryshen + */ +public class TemplateException extends Exception { + // TODO: store the number of template line with error. + + public TemplateException(String message) { + super(message); + } + + public TemplateException(String message, Throwable cause) { + super(message, cause); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/kryshen/tema/TemplateParser.java Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,287 @@ +/* + * Copyright (C) 2005, 2006 Mikhail A. Kryshen + * + * $Id: TemplateParser.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $ + */ + +package kryshen.tema; + +import java.io.*; +import java.util.*; + +/** + * Parser for DbReader templates. + * + * @author Mikhail A. Kryshen + */ +public class TemplateParser { + static final String SUPER = "SUPER."; + + /* Brackets. */ + static final char[] BR_LEFT = {'<', '['}; + static final char[] BR_RIGHT = {'>', ']'}; + + static final char BR_IN = '%'; + + /* Separators. */ + static final char[] REC_DATA_SEPARATORS = {':'}; + static final char[] NONREC_DATA_SEPARATORS = {'\\', '`'}; + static final char[] LIST_SEPARATORS = {' ', '\t', '\r', '\n'}; + + static enum FunctionData { + SUBFUNCTION, RECURSIVE, NONRECURSIVE; + }; + + static enum Terminator { + EOF, BRACKET, SEPARATOR; + }; + + static class Result { + Terminator terminator; + int substitutions; + + /** No text had been parsed. */ + boolean empty; + + Result(Terminator terminator, int substitutions, boolean empty) { + this.terminator = terminator; + this.substitutions = substitutions; + this.empty = empty; + } + + Result() { + this(null, 0, true); + } + }; + + private Map<String, Function> functions = new HashMap<String, Function>(); + + private Map<String, Object> variables = new HashMap<String, Object>(); + private TemplateParser superParser; + + private int termBracket = -1; + + public TemplateParser() { + this(null); + } + + public TemplateParser(TemplateParser superParser) { + this.superParser = superParser; + + Functions.registerAllFunctions(this); + } + + public void registerFunction(Function f) { + functions.put(f.name, f); + } + + public int parse(Reader in, Writer out) + throws IOException, TemplateException { + + return parse(in, out, true, null, null).substitutions; + } + + /** + * Parse template. + * + * @param in Reader to read template data. + * @param out Writer to write processed data. + * @param recursive enables recursive processing. + * @param separators characters which terminate parsing block. + * @param leading characters to ignore at the beginning of the block. + */ + Result parse(Reader in, Writer out, boolean recursive, + char[] separators, char[] leading) + throws IOException, TemplateException { + + Result result = new Result(); + int lc = -1; + + while (true) { + int c = in.read(); + + if (leading != null && isSeparator(c, leading)) + continue; + else + leading = null; + + boolean leftBracket = false; + int index; + + for (index = 0; index < BR_LEFT.length; index++) { + if (lc == BR_LEFT[index]) { + leftBracket = true; + break; + } + } + + if (recursive && leftBracket && c == BR_IN) { + + lc = -1; + int tb = termBracket; + termBracket = BR_RIGHT[index]; + result.substitutions += parseFunction(in, out); + termBracket = tb; + + } else if (lc == BR_IN && c == termBracket) { + + lc = -1; + result.terminator = Terminator.BRACKET; + break; + + } else { + + if (lc >= 0) + out.write(lc); + + lc = c; + } + + if (c < 0) { + result.terminator = Terminator.EOF; + break; + } else if (separators != null && isSeparator(c, separators)) { + result.terminator = Terminator.SEPARATOR; + break; + } + + result.empty = false; + } + + return result; + } + + int parseVariable(String name, Writer out) + throws IOException, TemplateException { + + Object ovalue = getValue(name); + if (ovalue == null) + return 0; + + String svalue = ovalue.toString(); + + if (svalue == null || svalue.length() == 0) + return 0; + + out.write(svalue); + return 1; + } + + boolean isSeparator(int c, char[] separators) { + for (char p : separators) { + if (c == p) return true; + } + + return false; + } + + int parseFunction(Reader in, Writer out) + throws IOException, TemplateException { + + StringBuffer sb = new StringBuffer(); + + while (true) { + int c = in.read(); + + if (isSeparator(c, LIST_SEPARATORS)) { + return invokeFunction(sb.toString(), + FunctionData.SUBFUNCTION, + in, out); + } else if (isSeparator(c, REC_DATA_SEPARATORS)) { + return invokeFunction(sb.toString(), + FunctionData.RECURSIVE, + in, out); + } else if (isSeparator(c, NONREC_DATA_SEPARATORS)) { + return invokeFunction(sb.toString(), + FunctionData.NONRECURSIVE, + in, out); + } else if (c < 0) { + System.err.println("Error: unexpected end of file."); + return 0; + } else { + sb.append((char)c); + } + } + } + + private int invokeFunction(String name, FunctionData fd, + Reader in, Writer out) + throws IOException, TemplateException { + + FunctionDataParser fdp = new FunctionDataParser(this, fd, in); + + if ("".equals(name)) { + return fdp.parseData(out); + } + + Function f = getFunction(name); + + if (f == null) { + throw new TemplateException("Unknown function: " + name); + } + + int r = f.invoke(fdp, out); + + if (fdp.hasMoreData()) { + /* Skip remaining function data. */ + fdp.parseData(new Writer() { + public void close() {} + public void flush() {} + public void write(char[] cbuf, int off, int len) {} + }); + } + + return r; + } + + Function getFunction(String name) throws TemplateException { + Function function = functions.get(name); + if (function != null) return function; + + if (superParser != null) { + if (name.startsWith(SUPER)) + return superParser.getFunction(name.substring(SUPER.length())); + else + return superParser.getFunction(name); + } + + return null; + } + + Object getValue(String name) throws TemplateException { + Object value = variables.get(name); + if (value != null) return value; + + if (superParser != null) { + if (name.startsWith(SUPER)) + return superParser.getValue(name.substring(SUPER.length())); + else + return superParser.getValue(name); + } + + return null; + } + + void setValue(String name, Object value) { + variables.put(name, value); + } + + void clearValues() { + variables.clear(); + } + + // TEST + public static void main(String[] args) + throws IOException, TemplateException { + + TemplateParser p = new TemplateParser(); + + FileReader in = new FileReader("parser.in"); + FileWriter out = new FileWriter("parser.out"); + + p.parse(in, out); + + in.close(); + out.close(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/kryshen/tema/functions/Define.java Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2006 Mikhail A. Kryshen + * + * $Id: Define.java,v 1.1.1.1 2006/05/16 14:04:09 mikhail Exp $ + */ + +package kryshen.tema.functions; + +import java.io.*; +import java.util.*; + +import kryshen.tema.*; + +public class Define extends Function { + public Define() { + super("define"); + } + + public int invoke(FunctionDataParser fdp, Writer out) + throws IOException, TemplateException { + + final String arg0 = fdp.getNextArg(); + final String data = fdp.getData(); + + Function newFunction = new Function(arg0) { + public int invoke(final FunctionDataParser fdp, final Writer out) + throws IOException, TemplateException { + + TemplateParser functionParser = + new TemplateParser(fdp.getTemplateParser()); + + functionParser.registerFunction(new Function("nextarg") { + public int invoke(FunctionDataParser unusedFdp, + final Writer out) + throws IOException, TemplateException { + + return fdp.parseNextArg(out); + } + }); + + functionParser.registerFunction(new Function("data") { + public int invoke(FunctionDataParser unusedFdp, + final Writer out) + throws IOException, TemplateException { + + return fdp.parseData(out); + } + }); + + return functionParser.parse(new StringReader(data), out); + } + }; + + fdp.getTemplateParser().registerFunction(newFunction); + + out.write(arg0); + return 1; + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/inctest.template Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,1 @@ +<%test:1 2 3%>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/macrotest Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,3 @@ +#!/bin/sh + +java -jar ../dist/tema.jar
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/main.template Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,3 @@ +<%define`test [%nextarg:%]+[%nextarg:%]=[%data:]%> +<%include`inctest.template%> +<%test:<%test:ab cd x%> [%\<%test\1 2 3%>%] y%>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/tema.properties Tue May 16 18:04:09 2006 +0400 @@ -0,0 +1,22 @@ +# Data source configuration +# resource : jdbc:odbc:biotopes-data +# driver : sun.jdbc.odbc.JdbcOdbcDriver + +# Base directory for images and files +# resource_base : C:\\biotopes\\db + +# Template to start processing with +main_template : main.template + +# File encodings +# input_encoding : ISO-8859-5 +# output_encoding : ISO-8859-5 + +# Cache templates +# cache_read : true + +# Output main_template parsing result to stderr +# output : stderr + +# File to output error messages (redirect stderr) +# log : dbreader.log