% $Id: xtpipes.tex 740 2020-06-13 22:35:32Z karl $ % htlatex xtpipes "xhtml,3,next" "" "-d./" % htlatex xtpipes "xhtml,3,next,doc" "" "-d./" % htlatex xtpipes "xhtml,3,next,win" % htlatex xtpipes "xhtml,3,next,win,doc" % generalize -i attribute to accept multiple directories, like for -classpath % gcj support these ``generics'' with a ``-5'' or ``-1.5'' switch % Copyright 2009-2020 TeX Users Group % Copyright 1996-2009 Eitan M. Gurari % Released under LPPL 1.3c+. % See tex4ht-cpright.tex for license text. \documentclass{article} \usepackage{url} \usepackage{verbatim} \input{common.tex} % make ` be the escape character, instead of | \Configure{ProTex}{java,<<<>>>,title,list,`} \begin{document} \input tex4ht-cpright.tex \input tex4ht-dir.tex \def\CNT{0} \bgroup \catcode`\^=7 \catcode`\^^M=13 % \gdef\OP#1{% \edef\temp{% \noexpand\<#1\noexpand\><<< \CNT >>> % } \temp % \immediate\write15{...... \CNT\space #1} \HAdvance\CNT by 1 % } % \egroup %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % \AddFile[optional: target file name; default: given file name] % (optional: target home dir; default MYDIR) % {file name}{dir} \ifOption{win} {\def\mv{move }} {\def\mv{mv }} \def\Slash{/} { \catcode`\/=0 \catcode`\\=12 /ifOption{win}{/gdef/Slash{\}}{} } \def\SLASH{/} \def\AddFile{\futurelet\ext\AddFileA} \def\AddFileA{% \if [\ext \def\ext[##1]{\def\ext{##1}\futurelet\dir\AddFileB}% \else \def\ext{\def\ext{}\futurelet\dir\AddFileB}\fi \ext} \def\AddFileB{% \if (\dir \def\dir(##1){\def\dir{##1}\AddFileC}% \else \def\dir{\let\dir\MYdir\AddFileC}\fi \dir} \def\AddFileC#1#2{% \expandafter\setStartDir \dir #2!% \bgroup \def\Slash{/}% \xdef\EndDir{\dir #2\Slash \ifx\ext\empty \if !#1!\else #1\fi \else \ext\fi}% \egroup \MakeDir \if !#1!\else \Needs{"\mv #1\space \dir #2\Slash \ifx\ext\empty #1\else \ext\fi"}% \fi } \ifOption{win} { \def\MakeDir{\relax \expandafter \ifx \csname !\StartDir\endcsname\relax \expandafter\let\csname !\StartDir\endcsname=\empty \Needs{"if NOT EXIST \StartDir \space mkdir -p \StartDir"}% \fi \ifx \EndDir\empty \else \expandafter\AppendDir \EndDir////*% \expandafter\MakeDir \fi } }{ \def\MakeDir{\relax \expandafter \ifx \csname !\StartDir\endcsname\relax \expandafter\let\csname !\StartDir\endcsname=\empty \Needs{"mkdir -p \StartDir"}% \fi \ifx \EndDir\empty \else \expandafter\AppendDir \EndDir////*% \expandafter\MakeDir \fi } } \def\AppendDir#1/#2/#3/*{% \def\temp{#2}\ifx \temp\empty \let\EndDir=\empty \else \edef\StartDir{\ifx \StartDir\empty\else \ifx \StartDir\SLASH \Slash \else \StartDir\Slash\fi \fi #1}% \def\EndDir{#2/#3}% \expandafter\MakeDir \fi } \def\setStartDir#1#2!{% \def\StartDir{#1}\ifx\StartDir\SLASH\else \def\StartDir{}\fi } % %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % % \AddFile[optional: target file name; default: given file name] % % (optional: target home dir; default MYDIR) % % {file name}{dir} % % \def\AddFile{\futurelet\ext\AddFileA} % \def\AddFileA{% % \if [\ext \def\ext[##1]{\def\ext{##1}\futurelet\dir\AddFileB}% % \else \def\ext{\def\ext{}\futurelet\dir\AddFileB}\fi % \ext} % \def\AddFileB{% % \if (\dir \def\dir(##1){\def\dir{##1}\AddFileC}% % \else \def\dir{\let\dir\MYdir\AddFileC}\fi % \dir} % \def\AddFileC#1#2{% % \expandafter\setStartDir \dir #2!% % \edef\EndDir{\ifx \dir\empty \else \dir/\fi % #2/\ifx\ext\empty \if !#1!XXX\else #1\fi\else \ext\fi}\MakeDir % \if !#1!\else % \Needs{"mv #1\space \dir /#2/\ifx\ext\empty #1\else \ext\fi"}% % \fi % } % \def\MakeDir{\relax % \expandafter \ifx \csname !\StartDir\endcsname\relax % \expandafter\let\csname !\StartDir\endcsname=\empty % \Needs{"mkdir -p \StartDir"}% % \fi % \ifx \EndDir\empty \else % \expandafter\AppendDir \EndDir////*% % \expandafter\MakeDir % \fi % } % \def\AppendDir#1/#2/#3/*{% % \def\temp{#2}\ifx \temp\empty \let\EndDir=\empty % \else % \edef\StartDir{\ifx \StartDir\empty\else % \ifx \StartDir\SLASH /\else % \StartDir/\fi \fi % #1}\def\EndDir{#2/#3}% % \fi % } % \def\setStartDir#1#2!{% % \def\StartDir{#1}\ifx\StartDir\SLASH\else % \def\StartDir{}\fi % } % \def\SLASH{/} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % TODO : make \WORK MSDOS / Linux agnostic. \def\MYdir{\WORK} \expandafter\let\csname !/\endcsname\empty \expandafter\let\csname !/\endcsname\empty \expandafter\let\csname !/home\endcsname\empty \expandafter\let\csname !/home/4\endcsname\empty \expandafter\let\csname !/home/4/gurari\endcsname\empty \expandafter\let\csname !/home/4/gurari/xtpipes.dir\endcsname\empty %\expandafter\let\csname !/home/4/gurari/tex4ht.dir/texmf\endcsname\empty %\expandafter\let\csname !/home/4/gurari/xtpipes.dir\endcsname\empty %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%% \part{Core} %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%% \section{Control} %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%% \subsection{Outline} %%%%%%%%%%%%%%%%%% \AtEndDocument{ \OutputCode[java]\ % double .java to avoid problems on MS \OutputCodE\ \OutputCodE\ } % \Needs{" % mkdir -p work.dir % ; % mkdir -p work.dir/xtpipes % "} \ifdojava \ifOption{win} {}{ \AtEndDocument{\Needs{" find \WORK\space -type f -iname '*.java' -print0 | xargs -0 javac -d \XTPIPES\space -sourcepath \WORK ; "}} } \fi \ifOption{win} { \def\BIN{} }{ \def\BIN{(\XTPIPES)} } % \expandafter\AddFile\BIN{xtpipes.dtd}{xtpipes\Slash lib} \AddFile{Xtpipes.java}{xtpipes} \<<< package xtpipes; /* Xtpipes.java (`version), generated from `jobname.tex Copyright (C) 2009-2010 TeX Users Group Copyright (C) `CopyYear.2002. Eitan M. Gurari ` */ ` ` public class Xtpipes { ` ` ` ` ` ` ` ` ` ` ` ` } ` >>> \Needs{"\mv xtpipes.java.java \MYdir xtpipes.java"} NOTE: We can not place Xtpipes.class and xtpipes.class at the same directory because MS Windows get confused between the two. \<<< /* xtpipes.java (`version), generated from `jobname.tex Copyright (C) 2009-2010 TeX Users Group Copyright (C) `CopyYear.2002. Eitan M. Gurari ` */ import xtpipes.*; public class xtpipes { public static void main(String [] args) throws Exception { Xtpipes.main(args); } } >>> \<<< public static String execute( Node node, String xml ) throws Exception { String name = "."; String old = (String) map.get(name); map.put( name, (Object) xml ); execute( node.getFirstChild() ); String s = (String) map.get(name); if( old != null ){ map.put( name, (Object) old ); } return s; } >>> \<<< private static HashMap map; private static boolean needScript; >>> The members of xtpipes need to be initiated each time the methods of the program are invoked from external point. That can happen multiple times for a given run. Hence, the fields are not initiated in the declaration points, but within the main method. All the external calls go directly or indirectly through that method. \<<< map = new HashMap (); needScript = true; >>> \<<< // import xtpipes.util.InputObject; // import xtpipes.util.FileInfo; import xtpipes.XtpipesPrintWriter; import java.net.URLConnection; import java.io.*; import java.lang.reflect.*; import java.util.HashMap; import java.util.Stack; import javax.xml.parsers.*; import javax.xml.transform.*; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.*; import org.w3c.dom.*; import org.xml.sax.*; import org.xml.sax.helpers.*; import java.net.URL; >>> %%%%%%%%%%%%% \subsection{Invocation Interfaces} %%%%%%%%%%%%% \<<< public static void main(String args[]) throws Exception { ` mainMethod(args); } >>> \<<< public static void xtpipes(String [] args, OutputStream out, PrintWriter log) throws Exception { ` outPrintWriter = new XtpipesPrintWriter( out, true ); logWriter = (log==null)? (new PrintWriter( System.err )) : log; mainMethod(args); outPrintWriter.flush(); } >>> \<<< public static void xtpipes(String [] args, OutputStreamWriter out, PrintWriter log) throws Exception { ` outPrintWriter = new XtpipesPrintWriter( out ); logWriter = (log==null)? (new PrintWriter( System.err )) : log; mainMethod(args); outPrintWriter.flush(); } >>> \<<< public static void xtpipes(String [] args, XtpipesPrintWriter out, PrintWriter log) throws Exception { ` outPrintWriter = out; logWriter = (log==null)? (new PrintWriter( System.err )) : log; mainMethod(args); outPrintWriter.flush(); } >>> \<<< private static boolean returnDom; private static String result; >>> \<<< returnDom = false; result = null; >>> \<<< public static Document getDOM(String args[]) throws Exception { ` returnDom = true; mainMethod(args); Document dom = null; if( result == null ){ System.err.println( "--- xtpipes warning --- getDOM without from 4xt file: " + scriptFile ); } else { try{ byte [] bytes = result.getBytes("UTF-8"); InputStream is = new ByteArrayInputStream( bytes ); dom = domBuilder.parse (is); } catch ( org.xml.sax.SAXParseException e ){ if( Xtpipes.trace ){ Xtpipes.logWriter.println( "\n---------------------------------------------------\n" + result + "\n---------------------------------------------------\n" ); } String s = ""; ` if( scriptFile != null ){ s += " script file: " + scriptFile; } instructionErr( null, "parsing error: " + e.getMessage() +s, 21 ); } catch ( Exception e ){ instructionErr( null, e.toString(), 5 ); } ` } return dom; } >>> \<<< public static Document getDOM(String s, String args[]) throws Exception { ` returnDom = true; inData = s; mainMethod(args); Document dom = null; if( result == null ){ System.err.println( "--- xtpipes warning --- getDOM without" + " from 4xt file: " + scriptFile ); } else { try{ byte [] bytes = result.getBytes("UTF-8"); InputStream is = new ByteArrayInputStream( bytes ); dom = domBuilder.parse (is); } catch ( org.xml.sax.SAXParseException e ){ instructionErr( null, "improper xml: " + e.getMessage() + "\n code starts with: " + result.substring(0, Math.min(100,result.length())) , 17 ); } catch ( Exception e ){ instructionErr( null, e.toString(), 6 ); } ` } return dom; } >>> \<<< public static Document getDOM(String args[], PrintWriter log) throws Exception { logWriter = (log==null)? new PrintWriter( System.err ) : log; return getDOM(args); } >>> \<<< public static Document getDOM(String s, String args[], PrintWriter log) throws Exception { logWriter = (log==null)? (new PrintWriter( System.err )) : log; return getDOM(s, args); } >>> \<<< static PrintWriter logWriter = new PrintWriter( System.err ); >>> %%%%%%%%%%%%% \subsection{Core Entry Code} %%%%%%%%%%%%% g \<<< private static void mainMethod(String args[]) throws Exception { try{ ` ` } catch (Exception e){ instructionErr( null, e.getMessage(), e.getStackTrace(), 31 ); } try { DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance(); domFactory.setValidating(true); DocumentBuilder validatingDomBuilder = domFactory.newDocumentBuilder(); validatingDomBuilder.setEntityResolver(`); validatingDomBuilder.setErrorHandler(`); ` ` while( needScript ){ if( scriptFile == null ){ instructionErr( null, "Missing 4xt script file name", 32 ); } ` Document script = validatingDomBuilder.parse(scriptFile); ` execute( script.getFirstChild() ); } ` Xtpipes.logWriter.flush(); } catch( org.xml.sax.SAXParseException e ){ String s = "Improper file " + scriptFile + ": " + e.getMessage(); instructionErr( null, s, 2 ); } catch( java.io.FileNotFoundException e ){ String s; if( scriptFile.equals( e.getMessage() ) ){ s = "Could not find file: " + scriptFile; } else { s = "Problem at script " + scriptFile + ": Could not find file " + e.getMessage(); } instructionErr( null, s, 3 ); } catch( Exception e ){ String s = "Problems at file: " + scriptFile + "\n " + e; instructionErr( null, s, 4 ); } } >>> %%%%%%%%%%%%% \subsection{Locate the Script File} %%%%%%%%%%%%% \<<< String f = FileInfo.searchFile( scriptFile ); if( f == null ){ throw new java.io.FileNotFoundException( scriptFile ); } else { scriptFile = f; } >>> [\HPage{System Properties} \<<< // `version import java.util.*; class sys{ public static void main( String [] args ) { java.util.Properties p = System.getProperties(); java.util.Enumeration keys = p.keys(); while( keys.hasMoreElements() ) { String name = (String) keys.nextElement(); String value = System.getProperty( name ); logWriter.println( name + " : " + value ); } } } >>> \EndHPage{}] %%%%%%%%%%%%% \subsection{Flow of Control} %%%%%%%%%%%%% \<<< private static void execute( Node node ) throws Exception { while( node != null ){ if( node.getNodeType()==Node.ELEMENT_NODE ){ String instruction = node.getNodeName(); ` if( instruction.equals( "xtpipes" ) ){ ` } else if( instruction.equals( "set" ) ){ ` } else if( instruction.equals( "get" ) ){ ` } else if( instruction.equals( "print" ) ){ ` } else if( instruction.equals( "return" ) ){ ` } else if( instruction.equals( "if" ) ){ ` } else if( instruction.equals( "xslt" ) ){ ` } else if( instruction.equals( "dom" ) ){ ` } else if( instruction.equals( "sax" ) ){ ` } else { instructionErr( node, "Improper instruction: " + instruction, 11 ); } } node = node.getNextSibling(); } } >>> %%%%%%%%%%%%% \subsection{Comamnd Line Options: Outline} %%%%%%%%%%%%% \<<< if( args[n] == null ){} else if( args[n].equals("") ){} else if( args[n].charAt(0)!='-' ){ inFile = args[n]; } else if( args[n].equals("-m") ){ messages = true; ` } else if( args[n].equals("-s") ){ ` } else if( args[n].equals("-S") ){ ` } else if( args[n].equals("-i") ){ ` } else if( args[n].equals("-o") ){ ` } else if( args[n].startsWith("-x") ){ ` } else if( args[n].equals("-E") ){ exceptionErrs = true; } else if( args[n].equals("-d") ){ ` } else if( args[n].equals("-trace") ){ trace=true; } else if( args[n].equals("-help") ){ help=true; } else { ` } >>> \<<< System.err.println( xtpipes_call ); >>> \<<< String xtpipes_call = " xtpipes (`version)" + "\n Command line options: " + "\n java xtpipes [-trace] [-help] [-m] [-E] [-s script_file]" + " [-S script_map]" + "\n [-i script_dir] [-o out_file] " + "\n [-x...ml2xml_arg...] " + "(-d in_data | in_file)" + "\n -m messages printing mode" + "\n -E error messages into exception calls" + "\n in_data XML data directly into the command line\n" ; >>> At least one `-x' command line option is required for ml2xml to be called. An empty postfix is also fine. \<<< for( int n=0; n>> %%%%%%%%%%%%% \subsection{Comamnd Line Options: Processing} %%%%%%%%%%%%% \<<< boolean help=false; for( int n=0; n } ` ` new FileInfo(logWriter, i_scriptDir, trace); if( inFile != null ){ inputObject = new InputObject( inFile, logWriter ); if( inputObject.getInputStream() == null ){ instructionErr( null, "Could not find or open file: " + inFile, 28 ); } inFile = inputObject.getFilename(); } else { inputObject = new InputObject( inData.getBytes("UTF-8"), logWriter ); } inputObject.buildProfile( trace ); >>> \<<< if( !returnDom ){ if( help || ((inFile == null) && (inData == null)) ){ ` if( (inFile == null) && (inData == null) ){ System.exit(0); } } } >>> \<<< if( !exceptionErrs ){ for(int i=n+1; i>> \<<< n++; if( n < args.length ){ inData = args[n]; } else { System.err.println( "--- Error --- Missing field for -d argument" ); inFile = null; inData = null; break; } >>> \<<< private static String inFile, inData; private static boolean exceptionErrs, messages; public static InputObject inputObject; >>> \<<< inFile = null; inData = null; exceptionErrs = false; messages = false; >>> %%%%%%%%%%%%% \subsection{Output File} %%%%%%%%%%%%% The output file name mentioned in the input command line `-o file.out' is employed in the following cases. \begin{itemize} \item Within sax commands without `name' argument \item Within the return instruction, if none of the sax commands wrote into the file. The returnToFile field is used for book keeping of whether a sax command used the file earlier for an output target. NOTE: check the case of `cond copy input preamble' ?? \end{itemize} \<<< n++; if( n < args.length ){ outFileName = args[n]; } else { System.err.println( "--- Error --- Missing field for -o argument" ); inFile = null; inData = null; break; } >>> \<<< private static String outFileName; private static PrintWriter outPrintWriter; private static boolean returnToFile = false; >>> \<<< outFileName = null; outPrintWriter = null; >>> \<<< if( outFileName != null ){ try { FileWriter fw = new FileWriter( outFileName ); outPrintWriter = new XtpipesPrintWriter( fw ); returnToFile = true; } catch(Exception e){ instructionErr( null, e.toString(), 12 ); } } >>> \<<< if( outFileName != null ){ outPrintWriter.close(); } >>> \<<< if( outPrintWriter == null ){ outPrintWriter = new XtpipesPrintWriter(System.out,true); } >>> % \AtEndDocument{ \OutputCodE\ } \AddFile{XtpipesPrintWriter.java}{xtpipes} \<<< package xtpipes; /* XtpipesPrintWriter.java (`version), generated from `jobname.tex Copyright (C) 2009-2010 TeX Users Group Copyright (C) `CopyYear.2002. Eitan M. Gurari ` */ import java.io.*; public class XtpipesPrintWriter extends PrintWriter { public XtpipesPrintWriter() { super(System.out, true); } public XtpipesPrintWriter (PrintStream ps, boolean b){ super(ps, b); } public XtpipesPrintWriter (OutputStream ps, boolean b){ super(ps, b); } public XtpipesPrintWriter (FileWriter fw){ super(fw); } public XtpipesPrintWriter (Writer wr){ super(wr); } public void print(String str) { super.print( XtpipesUni.toUni(str, "") ); } public void println(String str) { super.println( XtpipesUni.toUni(str, "") ); } } >>> %%%%%%%%%%%%%%%%%% \section{The xtpipes Script} %%%%%%%%%%%%%%%%%% The translation of a file is driven by a script that determines the transformations to be applied to the diffrent fragments of the input data. The name of the script may be found in different locations. \begin{itemize} \item A xtpipes processing instruction within the input \item Command line option `-s' \item A .map file that checks the data characteristics to determine the script. Currently available only to input files, not to input strings. \end{itemize} %%%%%%%%%%%%% \subsection{Command Line Options} %%%%%%%%%%%%% A script should satisfy the rules of `xtpipes.dtd', and a map should satisfy the rules of `xtpipes-map.dtd'. \<<< n++; if( n < args.length ){ scriptFile=args[n]; } else { System.err.println( "--- Error --- Missing field for -s argument" ); inFile = null; inData = null; break; } >>> \<<< n++; if( n < args.length ){ scriptMap=args[n]; } else { System.err.println( "--- Error --- Missing field for -S argument" ); inFile = null; inData = null; break; } >>> \<<< n++; if( n < args.length ){ i_scriptDir=args[n]; } else { System.err.println( "--- Error --- Missing field for -i argument" ); inFile = null; inData = null; break; } >>> \<<< public static String scriptFile; private static String scriptMap; static String i_scriptDir; >>> \<<< scriptFile = null; i_scriptDir = null; scriptMap = null; >>> %%%%%%%%%%%%% \subsection{Getting the Start Up Script} %%%%%%%%%%%%% The command line arguments may provide a pointer to a `scriptFile' and a pointer to an algorithm `scriptMap' for getting the script file name. With and without ml2xml \<<< if( scriptMap != null ){ try{ String f = FileInfo.searchFile( scriptMap ); if( f == null ){ throw new java.io.FileNotFoundException( scriptMap ); } else { scriptMap = f; } ` saxReader.setContentHandler( new DefaultHandler(){ ` } ); InputStream inputStream = (InputStream) (new File(scriptMap).toURI().toURL().openStream()); saxReader.parse( new InputSource(inputStream) ); saxReaderStack.push( saxReader ); } catch( java.io.FileNotFoundException e ){ instructionErr( null, "File not found: " + e.getMessage() + "; command line option -i", 33 ); } catch( Exception e ){ instructionErr( null, e.toString(), e.getStackTrace(), 27 ); } } if( scriptFile == null ){ scriptFile = "xtpipes-default.4xt"; } >>> \<<< private Stack condition = new Stack (); >>> \<<< public void startDocument () { condition.push( Boolean.valueOf(true) ); } >>> \<<< public void startElement(String ns, String sName, String qName, Attributes atts) { if( condition == null ){ return; } ` boolean cond = ((Boolean) condition.peek()).booleanValue(); if( qName.equals("when") ){ if( cond ){ ` } } else if( qName.equals("command-line") ){ if( scriptFile != null ){ ` condition = null; return; } } else if( qName.equals("processing-instruction") ){ if( cond ){ String s = inputObject.getXtpipes(); if( s != null ){ Xtpipes.scriptFile = s; ` condition = null; return; } } } else if( qName.equals("select") ){ if( cond ){ Xtpipes.scriptFile = atts.getValue("name"); ` condition = null; return; } } condition.push( Boolean.valueOf(cond) ); } >>> \<<< public void endElement(String ns, String sName, String qName) { if( condition == null ){ return; } ` condition.pop(); } >>> \<<< String name = atts.getValue("name"); String value = atts.getValue("value"); if( name.equals("system-id") ){ cond = value.equals(inputObject.getSystemId()); } else if( name.equals("public-id") ){ cond = value.equals(inputObject.getPublicId()); } else if( name.equals("dtd-root") ){ cond = value.equals(inputObject.getDtdRoot()); } else if( name.equals("root") ){ cond = value.equals(inputObject.getRoot()); } else if( name.equals("ext") ){ cond = inputObject.getFilename().endsWith("." + value); } else if( name.equals("prefix") ){ name = inputObject.getFilename(); if( name != null ){ int i = name.lastIndexOf('/'); if( (i != -1) && ((i+1) < name.length()) ){ name = name.substring(i+1); } i = name.lastIndexOf('\\'); if( (i != -1) && ((i+1) < name.length()) ){ name = name.substring(i+1); } cond = name.startsWith(value); } } else if( name.equals("meta-type") ){ cond = value.equals(inputObject.getMetaType()); } else if( name.equals("content-type") ){ cond = value.equals(inputObject.getContentType()); } >>> \<<< if( trace ){ Xtpipes.logWriter.println( " Found script file in map: " + Xtpipes.scriptFile ); } >>> \<<< if( Xtpipes.trace ){ String s = "<" + qName + "\n"; for(int i=0; i>> \<<< if( Xtpipes.trace ){ String s = ""; Xtpipes.logWriter.println( s ); } >>> %%%%%%%%%%%%% \subsection{DTDs} %%%%%%%%%%%%% %%%%%%%%%%%%% \immediate\openin15=xtpipes.dtd \ifeof15 \else \immediate\closein15 [\HPage{xtpipes.dtd} \verbatiminput{xtpipes.dtd} \EndHPage{}] \fi %%%%%%%%%%%%% % %%%%%%%%%%%%% \immediate\openin15=xtpipes-map.dtd \ifeof15 \else \immediate\closein15 [\HPage{xtpipes-map.dtd} \verbatiminput{xtpipes-map.dtd} \EndHPage{}] \fi %%%%%%%%%%%%% \begin{verbatim} ... \end{verbatim} \<<< )* > >>> % \AtEndDocument{ \OutputCodE\ } \expandafter\AddFile\BIN{xtpipes-map.dtd}{xtpipes\Slash lib} \<<< >>> %%%%%%%%%%%%% \subsection{Indirect Scripts} %%%%%%%%%%%%% If the root xtpipes element has no children, the input file is searched for an alternative script within a processing instruction of the form \verb++. \ ... \end{verbatim} If provided, the {\bf name attribute} is associated to the outcome. If omitted, the output file name from the command line is assumed. If such file name is not provided, the standard I/O stream is assumed. If the {\bf xml attribute} is not internally defined (within the hash table), a file name is assumed. If not provided, it stands for the input file name provided in the command line. The \verb+content-handler+ attribute gets a comma seperated list of classes names. The first argument refers to a content handler, the other arguments refer to filters. A content handler gets five arguments: output stream, an HashMap refering to the different scripts enclosed by the sax instruction, a method, log stream, and a boolean trace indicator. A filter and a lexical-constractor gets three arguments: output stream, log stream, and a boolean trace indicator. The sax instruction applies the filters and the content handler on the provided xml string. The script elements offer definitions of scripts delivered to the content handler. The ScriptsManager content handler of the distribution (Section~\ref{ScriptsManager}), for instance, invokes these scripts when their corresponding named elemets are encountered. \<<< | sax >>> \<<< )* > >>> \<<< String errMsg = ""; try{ ` ` ` ` XMLReader reader = saxReader; ` errMsg = "setContentHandler( " + className[0].trim() + " )"; saxReader.setContentHandler( (org.xml.sax.ContentHandler) ch ); ` ` if( inputSource==null ){ ` } else { errMsg = "xtpipes sax parsing error"; saxReader.parse( inputSource ); } ` saxReaderStack.push( reader ); } catch ( java.io.FileNotFoundException e ){ instructionErr( node, errMsg + "could not find file: " + e.getMessage(), 19 ); } catch ( ClassNotFoundException e ){ instructionErr( node, errMsg + " class not found: " + e.getMessage() + "\n classpath = " + System.getProperty("java.class.path") + " ---", 22 ); } catch ( java.lang.reflect.InvocationTargetException e ){ instructionErr( node, errMsg + ": " + e.getCause(), 23 ); } catch ( Exception e ){ Xtpipes.logWriter.flush(); e.printStackTrace(); instructionErr( node, errMsg + ": " + e.toString(), 29 ); } >>> \<<< errMsg = "While parsing file " + xml + ": "; InputStream inputStream = null; if( Xtpipes.ml2xml == null ){ if( Xtpipes.trace ){ Xtpipes.logWriter.println( "No request for ml2xml configuration (command line option -x)" ); } ` } else { ` } saxReader.parse( new InputSource(inputStream) ); ` >>> \<<< try{ inputStream = (InputStream) (new File(xml).toURI().toURL().openStream()); } catch ( java.io.FileNotFoundException ioe ){ try{ URL url = null; try { url = new URL(xml); } catch ( java.net.MalformedURLException fnf ){ url = new File(xml).toURI().toURL(); } inputStream = (InputStream) (url.openStream()); } catch ( java.io.FileNotFoundException fnf ){ inputStream = (InputStream) ( new File( new File(xml).toURI().toURL().toString() ) . toURI().toURL() . openStream() ); } } >>> %%%%%%%%%%%%% \subsubsection{SAX Reader} %%%%%%%%%%%%% The sax reader is pushed into the stack when its job is done, for use in other sax instructions. The stack is needed because nested sax instructions need unspecified number of readers. The filters may change the sax readers, so the readers need saving for later storing them in the stacks. \<<< XMLReader saxReader; if( saxReaderStack.empty() ){ SAXParser saxParser = saxFactory.newSAXParser(); saxReader = saxParser.getXMLReader(); ` } else { saxReader = (XMLReader) saxReaderStack.pop(); } >>> \<<< saxFactory = SAXParserFactory.newInstance(); saxFactory.setValidating(false); >>> \<<< private static Stack saxReaderStack; >>> \<<< saxReaderStack = new Stack (); >>> %%%%%%%%%%%%% \subsection{Handling DOCTYPE Statements} %%%%%%%%%%%%% The following code hides the DOCTYPE entry when searching the xtpipes processing instruction and when loading an input file. \<<< saxReader.setEntityResolver(new org.xml.sax.EntityResolver() { public InputSource resolveEntity( String publicId, String systemId) { if( (new File(systemId)).exists() ){ return new org.xml.sax.InputSource( systemId ); } StringReader strReader = new StringReader(""); return new org.xml.sax.InputSource(strReader); } }); >>> The default SAX behavior observes the DOCTYPE statement and assumes the following setup. \begin{verbatim} saxReader.setEntityResolver(new org.xml.sax.EntityResolver() { public InputSource resolveEntity( String publicId, String systemId) { return null; } }); \end{verbatim} %%%%%%%%%%%%% \subsubsection{Input} %%%%%%%%%%%%% \<<< Node xmlNode = node.getAttributes().getNamedItem( "xml" ); InputSource inputSource=null; String xml = null; if( xmlNode == null ){ ` } else { xml = xmlNode.getNodeValue(); String doc = (String) map.get(xml); if( doc!=null ){ byte [] bytes = doc.getBytes("UTF-8"); ByteArrayInputStream bais = new ByteArrayInputStream( bytes ); inputSource = new InputSource( bais ); } } >>> \<<< if( inData == null ){ xml = inFile; } else { byte [] bytes = inData.getBytes("UTF-8"); ByteArrayInputStream bais = new ByteArrayInputStream( bytes ); inputSource = new InputSource( bais ); } >>> %%%%%%%%%%%%% \subsubsection{Output Stream} %%%%%%%%%%%%% \<<< Node nameNode = node.getAttributes().getNamedItem("name"); PrintWriter out; CharArrayWriter caos = null; if( nameNode == null ){ out = outPrintWriter; returnToFile = false; } else { caos = new CharArrayWriter(); out = new PrintWriter( caos ); } >>> \<<< if( nameNode != null ){ String name = nameNode.getNodeValue(); char [] chars = caos.toCharArray() ; map.put( name, (Object) new String(chars) ); } >>> Note: Characters are prefered over bytes as they support unicode. %%%%%%%%%%%%% \subsection{Get Content Handler for SAX} %%%%%%%%%%%%% \<<< String [] className = node.getAttributes() .getNamedItem( "content-handler" ) .getNodeValue() .split(","); >>> The constructor of a content handler is provided five arguments: \begin{itemize} \item An output stream \item A hash map containing the enclosed defdinitions of scripts \item A method name \item A log stream \item A trace flag \end{itemize} \<<< Class [] argTypes = { PrintWriter.class, HashMap.class, Method.class, PrintWriter.class, boolean.class }; ` Object parmValues[] = new Object[5]; parmValues[0] = out; ` parmValues[1] = scripts; parmValues[2] = method; parmValues[3] = Xtpipes.logWriter; parmValues[4] = (Object) Xtpipes.trace; Class cls = Class.forName( className[0].trim() ); Constructor c = cls.getConstructor( argTypes ); Object ch = (Object) c.newInstance( parmValues ); >>> \<<< HashMap scripts = new HashMap (); Node script = node.getFirstChild(); while( script != null ){ if( script.getNodeType()==Node.ELEMENT_NODE ){ String element = script.getAttributes().getNamedItem( "element" ) .getNodeValue(); if( scripts.containsKey(element) ){ System.err.println( "--- Warning --- redfining script: " + element ); } scripts.put( element, (Object) script ); } script = script.getNextSibling(); } >>> \<<< Class cls = Xtpipes.class; Class [] argTypes = { Node.class, String.class }; method = cls.getMethod( "execute", argTypes ); >>> \<<< private static Method method; >>> %%%%%%%%%%%%% \subsection{Get Filters} %%%%%%%%%%%%% \<<< for( int i=1; i>> The filters are assumed to have a tri-parameter constructors which get an output stream for first arguments, log stream for second argument, and a trace boolean value for third argument. %%%%%%%%%%%%% \subsection{Get Lexical Handler for SAX} %%%%%%%%%%%%% The constructor of a lexical handler is provided the content handler as an argument. \<<< Node lexAttr = node.getAttributes() .getNamedItem( "lexical-handler" ); if( lexAttr != null ){ String lexName = lexAttr.getNodeValue(); argTypes = new Class[3]; argTypes[0] = Class.forName( className[0].trim() ); argTypes[1] = PrintWriter.class; argTypes[2] = boolean.class; parmValues = new Object[3]; parmValues[0] = ch; parmValues[1] = Xtpipes.logWriter; parmValues[2] = (Object) Xtpipes.trace; errMsg = "Class.forName( " + lexName.trim() + ") " ; cls = Class.forName( lexName.trim() ); errMsg = "get-constructor " + lexName.trim() + "( " + className[0].trim() + " ) " ; c = cls.getConstructor( argTypes ); errMsg = "get-object " + lexName.trim() + "( ... ) " ; Object xh = (Object) c.newInstance( parmValues ); errMsg = "set lexical handler " + lexName.trim() + " "; saxReader.setProperty( "http://xml.org/sax/properties/lexical-handler", (org.xml.sax.ext.LexicalHandler) xh ); } >>> %%%%%%%%%%%%%%%%%% \section{Entity Resolver} %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%% \subsection{Interface} %%%%%%%%%%%%% \<<< new XtpipesEntityResolver() >>> \<<< class XtpipesEntityResolver implements org.xml.sax.EntityResolver { ` } >>> %%%%%%%%%%%%% \subsection{Implementation} %%%%%%%%%%%%% \<<< public InputSource resolveEntity(String publicID, String systemID) throws SAXException { if( Xtpipes.trace ){ Xtpipes.logWriter.println( "Resolving: publicID = \" " + publicID + "\" systemID = \"" + systemID + "\"" ); } String file = FileInfo.searchFile( systemID ); if( file != null ){ try{ file = new File(file).toURI().toURL().toString(); return new InputSource( file ); } catch( java.net.MalformedURLException mfe){ throw new SAXException( "--- xtpipes error 30 --- improper file name: " + file ); } } return null; } >>> %%%%%%%%%%%%%%%%%% \section{File Information} %%%%%%%%%%%%%%%%%% %%%%%%%%%%%%% \subsection{Outline} %%%%%%%%%%%%% % \AtEndDocument{ \OutputCodE\ } \AddFile{FileInfo.java}{xtpipes} \<<< package xtpipes; /* FileInfo.java (`version), generated from `jobname.tex Copyright (C) 2009-2010 TeX Users Group Copyright (C) `CopyYear.2002. Eitan M. Gurari ` */ ` public class FileInfo{ ` public FileInfo(PrintWriter log, String iii_scriptDir, boolean trace) { FileInfo.log = log; FileInfo.ii_scriptDir = iii_scriptDir; FileInfo.trace = trace; ` ` } ` ` ` ` } >>> \<<< static String [] classPaths = null; static String [] scriptPaths = null; static java.util.HashMap registry = new java.util.HashMap (); static String slash = System.getProperty("file.separator"); static String ii_scriptDir; static PrintWriter log; static boolean trace; >>> \<<< import java.io.File; import java.io.PrintWriter; >>> %%%%%%%%%%%%% \subsection{Search Engine} %%%%%%%%%%%%% \<<< public static String searchFile( String file ){ String key = ((ii_scriptDir == null)? "" : ii_scriptDir ) + "!" + file; String result = (String) registry.get( key ); if( result == null ){ for(int i=0; i<2; i++){ if( trace ){ log.println( "Searching: " + file ); } if( (new File(file)).exists() ){ result = ( file.indexOf(slash) == -1 )? (System.getProperty("user.dir") + slash + file) : file; } else { if( ii_scriptDir != null ){ ` } if( result == null ){ ` } } if( result != null ){ break; } file = new File(file).getName(); } if( result != null ){ result = FileInfo.cleanPath(result); registry.put(key, result); } } if( trace ){ if( result == null ){ log.println( "Directory paths from xtpipes command line option -i: " + ii_scriptDir ); } else { log.println( "Found: " + result + "\n" ); } log.flush(); } return result; } >>> \<<< int k = scriptPaths.length; while( k>0 ){ k--; if( trace ){ log.println( "Searching: " + file + ", recursively in directory: " + scriptPaths[k] ); } result = searchDirectory( new File(scriptPaths[k]), file); if( result != null ){ break; } } String s = ii_scriptDir + file; if( (new File( s )).exists() ){ result = s; } >>> \<<< int k = classPaths.length; String toFile = "xtpipes" + slash + "lib" + slash + file; while( k>0 ){ k--; String s = classPaths[k] + toFile; if( trace ){ log.println( "Searching: " + s ); } if( new File(s).exists() ){ result = s; break; } } >>> \<<< static String searchDirectory(File dir, String file) { String result = null; if( dir.isDirectory() ){ String [] children = dir.list(); for (int i=0; i>> %%%%%%%%%%%%% \subsection{Class Paths} %%%%%%%%%%%%% \<<< classPaths = FileInfo.getPaths( System.getProperty("java.class.path") ); >>> Script paths are to be encoded in a similar manner as class paths. \<<< if( iii_scriptDir != null ){ scriptPaths = FileInfo.getPaths( iii_scriptDir ); } >>> \<<< static String [] getPaths( String dirs ){ String [] paths = null; paths = dirs.split( System.getProperty("path.separator") ); int k = paths.length; while( k>0 ){ k--; ` int len = paths[k].length(); if( (len>1) && (paths[k].lastIndexOf(slash + ".") == (len-1)) ){ paths[k] = paths[k].substring(0,len-1); } else if( (len>0) && ((len-1) != paths[k].lastIndexOf( slash )) ){ paths[k] += slash; } } return paths; } >>> \<<< paths[k] = cleanPath( paths[k] ); >>> \<\><<< if( (paths[k].length() > 0) && (paths[k].charAt(0) == '~') ){ if( (paths[k].length() == 1)|| (paths[k].charAt(1) != '~') ){ paths[k] = System.getProperty( "user.home" ) + paths[k].substring(1); } } if( paths[k].charAt(0) == '.' ){ paths[k] = System.getProperty( "user.dir" ) + slash + paths[k]; } >>> %%%%%%%%%%%%%%%%%% \section{Input Objects for XML Files} %%%%%%%%%%%%%%%%%% The XML files my contain faults as a brute force approach is applied in which the file is scanned directly without trying to build an XML object. %%%%%%%%%%%%% \subsection{Outline} %%%%%%%%%%%%% % \AtEndDocument{ \OutputCodE\ } \AddFile{InputObject.java}{xtpipes} \<<< package xtpipes; /* InputObject.java (`version), generated from `jobname.tex Copyright (C) 2009-2010 TeX Users Group Copyright (C) `CopyYear.2002. Eitan M. Gurari ` */ ` public class InputObject{ ` ` ` ` ` public InputStream getInputStream(){ return inputStream; } public String getFilename(){ return (url == null)? ( (connection == null)? filename : connection . getURL() . toString() ) : url; } public String getContentType(){ return contentType; } public String getMetaType(){ return metaType; } public String getPublicId(){ return publicId; } public String getSystemId(){ return systemId; } public String getXtpipes(){ return xtpipes; } public String getRoot(){ return root; } public String getDtdRoot(){ return dtdRoot; } } >>> \<<< InputStream inputStream = null; URLConnection connection = null; String filename = null; static PrintWriter log; >>> \<<< import java.io.PrintWriter; import java.net.URL; import java.net.URLConnection; import java.io.ByteArrayInputStream; import java.io.File; import java.io.InputStream; >>> %%%%%%%%%%%%% \subsection{Constructor} %%%%%%%%%%%%% \<<< public InputObject( String filename, PrintWriter log ){ InputObject.log = log; filename = filename.trim(); try{ inputStream = getInputStream(filename); } catch (Exception exp0){ if( !filename.startsWith( "http://" ) ){ try{ String name = "http://" + filename; inputStream = getInputStream( name ); filename = name; } catch (Exception exp1){ try{ String name = FileInfo.cleanPath(filename); inputStream = getInputStream( name ); filename = name; } catch (Exception exp2){ inputStream = null; } } } } this.filename = filename; } >>> \<<< public InputObject( byte [] bytes, PrintWriter log ){ InputObject.log = log; inputStream = new ByteArrayInputStream( bytes ); } >>> %%%%%%%%%%%%% \subsection{Stream from a File Name} %%%%%%%%%%%%% \<<< private java.io.InputStream getInputStream( String filename ) throws java.io.IOException{ if( filename == null ){ return null; } URL url; java.io.InputStream inputStream = null; // String loadingError = "Failed to get requested file."; try { url = new File(filename).toURI().toURL(); inputStream = getInputStream( url ); } catch (Exception ie) { try { url = new URL(filename); inputStream = getInputStream( url ); } catch (java.io.FileNotFoundException ife) { throw new java.io.IOException( "File not found: " + filename); } catch (Exception ife) { throw new java.io.IOException(ife + "\n" + ie); } } return inputStream; } >>> %%%%%%%%%%%%% \subsection{Stream from a URL} %%%%%%%%%%%%% \<<< private java.io.InputStream getInputStream( URL url ) throws java.io.FileNotFoundException, java.io.IOException { java.io.InputStream inputStream = null; String errMssg = ""; try{ connection = null; connection = url.openConnection(); connection.setRequestProperty("User-Agent", "[" + System.getProperty("os.name") + " / " + System.getProperty("os.arch") + "]" + "[" + System.getProperty("java.version") + " - " + System.getProperty("java.vendor") + "]" ); inputStream = connection.getInputStream(); } catch(java.io.FileNotFoundException ve){ errMssg = "File not found: " + url; throw new java.io.FileNotFoundException( "--- Ml2xml input error --- " + errMssg ); } catch (javax.net.ssl.SSLHandshakeException ve){ errMssg = "SSL Handshake Exception: " + ve.getMessage(); throw new javax.net.ssl.SSLHandshakeException( "--- Ml2xml input error --- " + errMssg ); } catch (java.net.UnknownHostException ve){ errMssg = "Unknown Host Exception: " + ve.getMessage(); throw new java.net.UnknownHostException( "--- Ml2xml input error --- " + errMssg ); } return inputStream; } >>> %%%%%%%%%%%%% \subsection{Clean Path} %%%%%%%%%%%%% \<<< public static String cleanPath( String path ){ String slash = System.getProperty("file.separator"); String userDir = System.getProperty( "user.dir" ); ` ` ` return path; } >>> \<<< if( (path.length() > 0) && (path.charAt(0) == '~') ){ if( (path.length() == 1) || (path.charAt(1) != '~') ){ path = System.getProperty( "user.home" ) + path.substring(1); } } >>> \<<< if( path.startsWith("..") ){ path = userDir.substring(0, Math.max(0,Math.max( userDir.lastIndexOf("/") , userDir.lastIndexOf("\\") ))) + path.substring(2); } if( path.startsWith(".") ){ path = userDir + slash + path.substring(1); } >>> \<<< int i; while( ((i=path.indexOf("/..")) != -1) || ((i=path.indexOf("\\..")) != -1) ){ String s = path.substring(0,i); int j = Math.max(s.lastIndexOf("/"), s.lastIndexOf("\\")); path = path.substring(0,j) + path.substring(i+3); } while( ((i=path.indexOf("/.")) != -1) || ((i=path.indexOf("\\.")) != -1) ){ String s = path.substring(0,i); int j = Math.max(s.indexOf("/"), s.indexOf("\\")); path = path.substring(0,j) + path.substring(i+2); } >>> %%%%%%%%%%%%% \subsection{Profile: Connecting and Reading the Input File} %%%%%%%%%%%%% \<<< public void buildProfile( boolean trace ){ if( trace ){ log.println( "xtpipes (`version)" + "\n java.version: " + System.getProperty("java.version") + "\n java.class.path: " + System.getProperty("java.class.path") + "\n os.name: " + System.getProperty("os.name") + "\n user.home: " + System.getProperty("user.home") + "\n user.dir: " + System.getProperty("user.dir") ); } if( connection != null ){ ` } ` if( trace ){ log.println( " url = " + url + "\n contentType = " + contentType + "\n publicId = " + publicId + "\n systemId = " + systemId + "\n xtpipes = " + xtpipes + "\n root = " + root + "\n dtdRoot = " + dtdRoot ); } } >>> \<<< contentType = connection . getContentType(); url = connection . getURL() . toString(); >>> \<<< int max = 8192; int buffSize = 4096; byte [] buff = new byte [ buffSize ]; int m = 0; int length = 0; int ch; int type = `; String token = null; while( m < max ){ try{ int k = Math.min( max - m, buffSize ); length = inputStream.read( buff, 0, k ); if( length == -1 ){ break; } if( length == 0 ){ continue; } } catch (java.io.IOException e){ System.err.println( "--- xtpipes error --- : " + e ); break; } for(int i = 0 ; i < length; i++ ){ ` m++; } } >>> %%%%%%%%%%%%% \subsection{Profile: Scanning the Different Cases} %%%%%%%%%%%%% \<<< switch( ch = buff[i] ){ case '<': token = ""; type = `; break; case '>': if( token != null ){ token = token . replaceAll( "\\s+", " "); ` token = null; } break; case '\n': case ' ': if( token != null ){ ` } break; case '"': case '\'': if( token == null ){ break; } ` default: if( token != null ){ if( type == `
 ){
                     if( ch == 'D' ){
                        type = `;
                        token += (char) ch;
                     } else { token = null; type = `; }
                  }
                  else
                  if( token.equals("") && (type == `) ){
                     `
                  } else { token += (char) ch; }
}              }
>>>


\<<<
if( !token.trim().equals("") ){
   if( token.trim().charAt(0) == ch ){
     if( type == ` ){
        publicId = token.trim().substring(1);
        type = `;
        token = "";
        break;
     }
     else if( type == ` ){
        systemId = token.trim().substring(1);
        token = null;
        break;
     }
} }
>>>


\<<<
switch( ch ){
   case '!': type = `
;
             break;
   case '?': type = ` ;
             break;
   default:  if( Character.isLetter(ch)
                 && ((root == null) || (metaType == null)) ){
                type = `;
                token += (char) ch;
             } else { token = null; }
}
>>>

\<<<
if( type == ` ){
   if( xtpipes == null ){
      int n = token.length();
      if( (n > 1) && (token.charAt( n - 1 ) == '?')
                  && (token.startsWith("xtpipes") ) ){
         String s = token . substring(7,n-1) . replaceAll( "\\s+", "");
         n = s.length();
         if( (n>6) && (s.startsWith("file="))
                   && (s.charAt(5) == s.charAt(n-1)) ){
           xtpipes = s.substring(6,n-1);
   }  }  }
} else if( type == ` ){
   if( metaType == null ){
      token = token . replaceAll( "\\s+", "");
      int k = token.indexOf("http-equiv");
      int n = token.indexOf("content");
      if( (k != -1) && (n != -1) ){
         if( token.length() > (Math.max(k,n)+3) ){
            if( token.substring(k+12).startsWith("Content-Type") ){
               token = token.substring(n+9);
               n = token.indexOf(";");
               if( n !=-1 ){ metaType = token.substring(0,n); }
   }  }  }  }
} else if( (type == `) && (root == null) ){
   root = token;
}
>>>

\<<<
if( type == ` ){
   if( token.equals("meta") ){
      if( metaType == null ){
         type = `;
         token = " ";
      } else {
         token = null;
      }
   } else {
      if( root == null ){
        root = token;
      }
      token = null;
   }
} else if( type == ` ){
   if( token.equals("DOCTYPE") ){
      type = `;
      token = " ";
   } else { token = null; }
} else if( type == ` ){
   if( !token.trim().equals("") ){
      dtdRoot = token.trim();
      token = " ";
      type = `;
   } else { token = null; }
} else if( type == ` ){
   if( !token.trim().equals("") ){
      token = token.trim();
      if( token.equals("PUBLIC") ){
         type = `;
         token = "";
      } else if( token.equals("SYSTEM") ){
         type = `;
         token = "";
      } else { token = null; }
   }
} else { token += ' '; }
>>>


\<<<
String dtdRoot = null,
      publicId = null,
      systemId = null,
       xtpipes = null,
           url = null,
      metaType = null,
   contentType = null,
          root = null;
>>>

\OP{undef type}
\OP{new tok}
\OP{root or meta}
\OP{pre doctype}
\OP{doctype}
\OP{doctype root}
\OP{doctype id}
\OP{public id}
\OP{system id}
\OP{proc instruction}
\OP{proc root}
\OP{meta}


%%%%%%%%%%%%%%%%%%
\section{Input Objects for XML Strings}
%%%%%%%%%%%%%%%%%%



%%%%%%%%%%%%%
\subsection{Search String for Indirection}
%%%%%%%%%%%%%


\<<<
scriptFile = inputObject.getXtpipes();
rootName = inputObject.getRoot();
needScript = true;
>>>


Remove XtPipesSearch!!!!!!!!!!!!!!

\<\><<<
try{
       `
       saxReader.setContentHandler( new XtPipesSearch() );
      `
       saxReaderStack.push( saxReader );
} catch(Exception e){
e.printStackTrace();
   instructionErr( node, errMsg + e.toString(), 13 );
}
>>>

\<<<
errMsg = "Searching   in "
        + inData.substring(0, Math.min(70,inData.length()))
        + "... : ";
byte [] bytes = inData.getBytes("UTF-8");
ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
InputSource is = new InputSource( bais );
saxReader.parse(is);
>>>

%%%%%%%%%%%%%
\subsection{The Search Engine}
%%%%%%%%%%%%%



\<<<
private static class XtPipesSearch extends DefaultHandler {
   public void  endElement(String uri,
                           String localName, String qName){
     `
   }
   public void processingInstruction(String target, String attrs) {
     if( !needScript && target.equals("xtpipes") ){
        `
}  } }
>>>


The input file is
searched for an alternative script within a processing instruction of
the form \verb++.


\<<<
rootName = qName;
>>>


\<<<
try {
   `
   saxReader.setContentHandler(new DefaultHandler() {
      public void startElement(String uri, String localName,
         String qName, Attributes atts) {
         String filename = atts.getValue("file");
         if( filename != null ){
            scriptFile = filename;
            `
            needScript = true;
      }  }
   });
   String str = "";
   StringReader reader = new StringReader(str);
   InputSource in = new InputSource(reader);
   saxReader.parse(in);
   saxReaderStack.push( saxReader );
} catch(Exception e){
   System.err.println( "--- Error 10 --- " + e );
}
>>>







\<<<
private static String  rootName;
>>>


\<<<
rootName = null;
>>>




%%%%%%%%%%%%%%%%%%
\section{Information About the Transformation}
%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%
\subsection{User's System}
%%%%%%%%%%%%%



\<<<
logWriter.println(
     "xtpipes (`version)"
     + "\n java.version: "    + System.getProperty("java.version")
     + "\n java.class.path: " + System.getProperty("java.class.path")
     + "\n os.name: "         + System.getProperty("os.name")
     + "\n user.home: "       + System.getProperty("user.home")
     + "\n user.dir: "        + System.getProperty("user.dir")
);
for( int k=0; k>>

%%%%%%%%%%%%%
\subsection{Script to be Used}
%%%%%%%%%%%%%


\<<<
if( messages ){
   logWriter.println(
      "Requesting XtPipes script file: "
      + filename );
}
>>>


%%%%%%%%%%%%%
\subsection{Preamble Attribute}
%%%%%%%%%%%%%

\<<<
if ( (attr != null) && messages ) {
   logWriter.println( attr.getNodeValue() );
}
>>>



%%%%%%%%%%%%%
\subsection{Tracing}
%%%%%%%%%%%%%


\<<<
static boolean trace;
>>>

\<<<
trace = false;
>>>



\<<<
if( trace ){
   logWriter.print( "[##] = xtpipes => " + instruction );
   if( node.hasAttributes() ){
      NamedNodeMap attributes = node.getAttributes();
      for(int i=0; i < attributes.getLength(); i++ ){
         Node attr = attributes.item(i);
         logWriter.print( " "   + attr.getNodeName()
                         + "=\"" + attr.getNodeValue() + "\"" );
   } }
   logWriter.println(); logWriter.flush();
}
>>>

\<<<
if( trace ){
   logWriter.print( "--> true" );
}
>>>

\<<<
if( trace ){
   logWriter.print( "--> true" );
}
>>>


\<<<
if( trace ){
   logWriter.println( "(" + scriptFile + ")" );
}
>>>



%%%%%%%%%%%%%%%%%%
\section{loose Ends}
%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%
\subsection{Fix XML Defaults}
%%%%%%%%%%%%%%%%%%

\<<<
private static String [] ml2xml = null;
static Class ml2xmlClassObj = null;
>>>

\<<<
if( args[n].substring(2).equals("") ){
   if( ml2xml == null ){ ml2xml = new String[0]; }
} else {
   if( ml2xml == null ){
      ml2xml = new String[1];
   } else {
      String [] m2x = new String [ml2xml.length + 1];
      for(int cnt=0; cnt < ml2xml.length; cnt++){
        m2x[cnt] = ml2xml[cnt];
      }
      ml2xml = m2x;
   }
   ml2xml[ ml2xml.length - 1 ] = args[n].substring(2);
}
>>>


\<<<
try{
   ml2xmlClassObj = Class.forName( "ml2xml.Ml2xml" );
} catch (java.lang.ClassNotFoundException cnf ){
   instructionErr( null, "Class not found: ml2xml.Ml2xml", 25 );
}
Class [] argTyp = { String.class, String[].class };
Constructor con = ml2xmlClassObj.getConstructor( argTyp );
try{
   `
   inputStream = (InputStream) con.newInstance(
         new Object[]{xml, ml2xml}
      );
} catch(java.lang.reflect.InvocationTargetException ite){
   String s = "Problem at: ml2xml.Ml2xml(" + xml + ","
              + "new String[]{" ;
   for(int i=0; i < Xtpipes.ml2xml.length; i++){
      s += ((i==0)? "\"" : ", \"") + Xtpipes.ml2xml[i] + "\"";
   }
   s += "})";
   instructionErr( null, s + "; " + ite.getCause(), 38);
}
>>>

 ite.getTargetException().printStackTrace();


\<<<
if( Xtpipes.ml2xml != null ){
   Class [] argTyp = {};
   Method m = ml2xmlClassObj . getMethod( "closeFiles", argTyp );
   m.invoke( null, new Object[0] );
}
>>>

\<<<
if( Xtpipes.trace ){
   String s = "Calling: ml2xml.Ml2xml(inputStream,"
              + "new String[]{" ;
   for(int i=0; i < Xtpipes.ml2xml.length; i++){
      s += ((i==0)? "\"" : ", \"") + Xtpipes.ml2xml[i] + "\"";
   }
   s += "})";
   Xtpipes.logWriter.println( s );
}
>>>


\<<<
if( ml2xmlClassObj != null ){
  Class [] argTypes = { };
  Method m = ml2xmlClassObj.getMethod( "closeFiles", argTypes );
  Object parmValues[] = new Object[0];
  m.invoke( null, parmValues );
}
>>>


\<<<
import java.lang.reflect.Constructor;
>>>

Ml2xml is referenced through reflection instead of directly so that xtpipes can
be delivered also without that utility, e.g., for tex4ht where no treatment of faulty
XML file is to be done. In fact, this approach can be generalized to offer
arbitrary filter for the input.




%%%%%%%%%%%%%%%%%% 
\subsection{Unicode Filter}
%%%%%%%%%%%%%%%%%%

Non-ASCII characters are translated into unicode hexadecimal entities.
The same holds for ascii characters listed within the filter.

\AtEndDocument{
   \OutputCodE\
}
\AddFile{XtpipesUni.java}{xtpipes}


\<<<
/* XtpipesUni.java (`version), generated from `jobname.tex
   Copyright (C) 2009-2010 TeX Users Group
   Copyright (C) `CopyYear.2002. Eitan M. Gurari
` */
package xtpipes;
public class XtpipesUni{
   `
   `
}
>>>

\<<<
private static int D800 = Integer.parseInt("D800", 16);
private static int DFFF = Integer.parseInt("DFFF", 16);
private static int DC00 = Integer.parseInt("DC00", 16);
private static int X400 = Integer.parseInt("400",16);
private static int X10000 = Integer.parseInt("10000",16);


public static String toUni( char[] ch, int start, int length,
                                           String filter ){
   StringBuffer buf = new StringBuffer(length);
   for (int i = 0; i < length; i++) {
       int chr = ch[ start + i ];
       boolean ascii =  (chr == '\n')
                        || (chr > 31) && (chr < 127) ;
       if( filter.indexOf(chr) > -1 ){ ascii = false; }

       if( (chr >= D800) && (chr<= DFFF) ){
          chr = ((ch[i] - D800) * X400 + (ch[++i] - DC00)) + X10000;
       }


       buf.append(
         ascii ? Character.toString((char) chr)
               : ("&#x"
                 + Integer.toHexString(chr).toUpperCase()
                 + ";" ) );
   }
   return new String(buf);
}
>>>

\<<<
public static String toUni( String s, String filter ){
   char [] ch = s.toCharArray();
   int length = ch.length;
   return toUni(ch, 0, length, filter);
}
>>>







%%%%%%%%%%%%%
\subsection{Error Messagesg}
%%%%%%%%%%%%%






\<<<
private static void instructionErr( Node node, String e, int num )
                                     throws Exception {
   String err = "--- xtpipes error " + num + " --- ";
   if( node != null ){
      err += "At <" + node.getNodeName();
      NamedNodeMap attr = node.getAttributes();
      for(int i=0; i
   Xtpipes.logWriter.flush();
   if( exceptionErrs ) { throw new Exception( err );  }
   else {
      System.err.println( err );
      System.exit(1);
   }
}
>>>



\<<<
private static void instructionErr( Node node, String e,
                                StackTraceElement[] st, int num )
                                     throws Exception {
   Xtpipes.logWriter.println(
      "--- xtpipes error " + num + " --- " + e
   );
   for(int i=st.length-1; i>=0; i-- ){
      Xtpipes.logWriter.println( st[i].toString() );
   }
   instructionErr( node, e, num );
}
>>>




\<<<
new ErrorHandler() {
    public void warning(SAXParseException e) throws SAXParseException {
      showSpecifics("warning",e);
    }
    public void error(SAXParseException e) throws SAXParseException {
      showSpecifics("error",e);
    }
    public void fatalError(SAXParseException e) throws SAXParseException {
      showSpecifics("fatal error",e);
    }
    public void showSpecifics(String s, SAXParseException e)
                                                throws SAXParseException {
      String err =   "--- xtpipes " + s + " 24 --- " + e.getSystemId()
                     + " line " + e.getLineNumber()
                     + " col "  + e.getColumnNumber()
                     + " : "    + e.getMessage() ;
      if( exceptionErrs ) { throw new SAXParseException(
                                     err, (org.xml.sax.Locator) null ); }
      else {
         System.err.println( err );
         System.exit(1);
}   } }
>>>





The follower listeners catch errors but their messages are not
delivered through the call to the new exceptions (why?).  The field
errMssg is used so that error 16 will produce the same error messages.

\begin{description}
\item[Catches errors in the XSLT file]



\<<<
new ErrorListener() {
   public void warning(TransformerException e) throws TransformerException {
     showSpecifics(e);
   }
   public void error(TransformerException e) throws TransformerException {
     showSpecifics(e);
   }
   public void fatalError(TransformerException e) throws TransformerException {
     showSpecifics(e);
   }
   void showSpecifics(TransformerException e)
                                               throws  TransformerException{
     String err = e.getMessage() ;
     String loc = e.getLocationAsString();
     if( loc != null ){ err = loc + ": " + err; }
     err = "XSL stylesheet problem: " + err;
     if( errMssg == null ){ errMssg = err; }
     throw new TransformerException(err);
}  }
>>>


\item [Catches errors in the XML file]

\<<<
new ErrorListener() {
   public void warning(TransformerException e) throws TransformerException {
     showSpecifics(e);
   }
   public void error(TransformerException e) throws TransformerException {
     showSpecifics(e);
   }
   public void fatalError(TransformerException e) throws TransformerException {
     showSpecifics(e);
   }
   void showSpecifics(TransformerException e)
                                               throws  TransformerException{
     String err = e.getMessage() ;
     String loc = e.getLocationAsString();
     if( loc != null ){ err = loc + ": " + err; }
     if( errMssg == null ){ errMssg = err; }
     err = "XML document prblem: " + err;
     throw new TransformerException(err);
}  }
>>>


\<<<
new ErrorListener() {
   public void warning(TransformerException e) throws TransformerException {
     showSpecifics(e);
   }
   public void error(TransformerException e) throws TransformerException {
     showSpecifics(e);
   }
   public void fatalError(TransformerException e) throws TransformerException {
     showSpecifics(e);
   }
   void showSpecifics(TransformerException e)
                                               throws  TransformerException{
     String err = e.getMessage() ;
     String loc = e.getLocationAsString();
     if( loc != null ){ err = loc + ": " + err; }
     throw new TransformerException(err);
}  }
>>>



\end{description}


\<<<
public static String errMssg;
>>>

%%%%%%%%%%%%%%%%%%
\section{Serialize Dom}
%%%%%%%%%%%%%%%%%%


\<<<
static String serialize( Node root ){
   if( root.getNodeType() == Node.TEXT_NODE) {
         return root.getNodeValue();
   }
   if( root.getNodeType() == Node.ELEMENT_NODE) {
      String ser = "";
      String tagName = root.getNodeName();
      ser += "<" + tagName;
      `
      ser += "\n>";
      `
      ser += "";
      return ser;
   }
   if( root.getNodeType() == Node.DOCUMENT_NODE) {
      String ser = "";
      `
      return ser;
   }
   if( root == null ){ return "null"; }
   return "";
}
>>>

\<<<
NodeList children = root.getChildNodes();
if(children.getLength() > 0) {
   for(int i = 0; i < children.getLength(); i++) {
      ser += serialize(children.item(i));
}  }
>>>

\<<<
NamedNodeMap attributes = root.getAttributes();
for(int i = 0; i < attributes.getLength(); i++) {
   Attr attribute = (Attr) attributes.item(i);
   ser += "\n" + attribute.getName() + "=\""
               + attribute.getValue() + "\" ";
}
>>>




%%%%%%%%%%%%%
\subsection{Clean Xmlns}
%%%%%%%%%%%%%


\<<<
static ArrayList nsName, nsValue;
static void cleanXmlns( Node root ){
   if( root.getNodeType() == Node.ELEMENT_NODE) {
      int top = nsName.size();
      `
      `
       for(int i=nsName.size(); i>top; ){
         i--;
         nsName.remove(i);
         nsValue.remove(i);
       }
   } else if( root.getNodeType() == Node.DOCUMENT_NODE) {
      nsName = new ArrayList();
      nsValue = new ArrayList();
      `
      nsName = null;
      nsValue = null;
}  }
>>>



\<<<
NodeList children = root.getChildNodes();
if(children.getLength() > 0) {
   for(int i = 0; i < children.getLength(); i++) {
      cleanXmlns(children.item(i));
}  }
>>>

\<<<
ArrayList remove = new ArrayList();
NamedNodeMap attributes = root.getAttributes();
for(int i = 0; i < attributes.getLength(); i++) {
   Attr attribute = (Attr) attributes.item(i);
   String name = attribute.getName();
   if( name.startsWith("xmlns") ){
     if( (name.length() == 5) || (name.charAt(5) == ':') ){
        String value = attribute.getValue();
        `
        if( bool ){ remove.add(attribute);
        } else { nsName.add(name); nsValue.add(value); }
}  } }
for(int i=remove.size(); i>0; ){
   i--;
  ((Element) root).removeAttributeNode( (Attr) remove.get(i) );
}
remove = null;
>>>

\<<<
boolean bool = false;
for(int k=nsName.size(); k>0; ){
  k--;
  if( ((String) nsName.get(k)) . equals(name) ){
     bool = ((String) nsValue.get(k)) . equals(value);
     break;
} }
>>>

\<<<
import java.util.ArrayList;
>>>



%%%%%%%%%%%%%%%%%% 
\subsection{Default Script}
%%%%%%%%%%%%%%%%%%

\AtEndDocument{
   \OutputCodE\
}
\expandafter\AddFile\BIN{xtpipes-default.4xt}{xtpipes\Slash lib}

\<<<




>>>












%%%%%%%%%%%%%%%%%%
\part{Useful Pre Fabricated Modules}
%%%%%%%%%%%%%%%%%%




%%%%%%%%%%%%%
\section{ScriptsManager: A Content Handler}
%%%%%%%%%%%%%

\label{ScriptsManager}


%%%%%%%%%%%%% 
\subsection{Outline}
%%%%%%%%%%%%%

\AtEndDocument{
   \OutputCodE\
}
\AddFile{ScriptsManager.java}{xtpipes\Slash util}

\<<<
/* ScriptsManager.java (`version), generated from `jobname.tex
   Copyright (C) 2009-2010 TeX Users Group
   Copyright (C) `CopyYear.2002. Eitan M. Gurari
` */
package xtpipes.util;
`
public class ScriptsManager extends DefaultHandler {
     `
     PrintWriter out = null, log = null;
     HashMap scripts = null;
     Method method = null;
     boolean savemode=false;
     String code="", match = null;
     Stack stack = new Stack();
   public ScriptsManager( PrintWriter out,
                          HashMap scripts,
                          Method method,
                          PrintWriter log, boolean trace ){
     this.out = out;
     this.log = (log==null)? new PrintWriter( System.err ) : log;
     this.scripts = scripts;
     this.method = method;
   }
   public void characters(char[] ch, int start, int length){
     add( XtpipesUni.toUni(ch, start, length, "<>&") );
   }
   `
   `
   protected void add(String s){
      if( savemode ){ code+=s; }
      else { out.print(s); }
}  }
>>>


\<<<
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.*;
import java.io.*;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Stack;
>>>

%%%%%%%%%%%%%
\subsection{Start Elements}
%%%%%%%%%%%%%




\<<<
public void startElement(String ns, String sName,
                        String qName, Attributes atts) {
   `
   `
   inBody = true;
   String s =  "<" + qName + "\n";
   for(int i=0; i
      s += " " + name + "=\"" +
         XtpipesUni.toUni(value, "<>&\"") + "\"";
   }
   if( flag ){ ` }
   s += ">" ;
   `
}
>>>


\<<<
boolean inBody = false;
>>>


\<<<
String key = (atts==null)?
               null
             : (qName + "::" + atts.getValue("class"));
boolean flag = (key != null) && scripts.containsKey(key);

if( !flag ){
   key = qName;
   flag = scripts.containsKey(key);
}
>>>

\<<<
if( flag ){
   Object [] state = { Boolean.valueOf(savemode), code, match };
   stack.push( state );
   savemode=true; code=""; match= key;
} else {
   Object [] state = { Boolean.valueOf(savemode), null, null };
   stack.push( state );
}
add( s );
>>>

The parsing of an XML string is similar to that of done by a
left-to-right bottom up parser of a programming language.
Specifically, the token are read and send on to the output stream,
until an element whose name appears in the hash table of scripts is
encountered.  When such an element is encountered, its body is
assembled and the corresponding script is applied on the body.  The
processing might be recursive, in the sense that enclosed elements
might also have scripts to process them.

The above applies also to an element name concatenated with its class
attribute value, with the substring `::' as a separator.

%%%%%%%%%%%%%
\subsection{End Elements}
%%%%%%%%%%%%%



\<<<
public void endElement(String ns, String sName, String qName){
   String s = "";
   add( s );
   Object [] state = (Object []) stack.pop();
   if( (String) state[1] != null ){
     `
     `
     `
     if( !s.equals("") ){
       `
       add( s );
     }
   } else { ` }
}
>>>







\<<<
Object parmValues[] = new Object[2];
parmValues[0] = scripts.get( match );
parmValues[1] = code;
try {
  s = (String) method.invoke( null, parmValues );
} catch(java.lang.reflect.InvocationTargetException e){
   log.println("--- ScriptsManager Error 1 --- " + e.getCause() );
   log.flush();
} catch (Exception e){
   log.println("--- ScriptsManager Error 2 --- " + e );
   log.flush();
}
>>>


Can't invoke exception above.

\<<<
savemode = ((Boolean) state[0]).booleanValue();
code = (String) state[1];
match = (String) state[2];
>>>




%%%%%%%%%%%%%
\subsection{Name Spaces at Start of Elements}
%%%%%%%%%%%%%

\<<<
if( name.startsWith("xmlns") ){
  if( (name.length() == 5) || (name.charAt(5) == ':') ){
     `
     if( !bool ){
        nsName.add(name); nsValue.add(value);
} }  }
>>>





\<<<
HashSet registry = new HashSet();
for(int i=nsName.size(); i>top; ){
  i--;
  registry.add( (String) nsName.get(i) );
}
for(int i=top; i>0; ){
  i--;
  String nm = (String) nsName.get(i);
  if( ! registry.contains(nm) ){
     registry.add( nm );
     s += " " + nm + "=\"" +
         XtpipesUni.toUni( (String) nsValue.get(i), "<>&\"") + "\"";
} }
>>>




\<<<
ArrayList nsName = new ArrayList(),
                         nsValue = new ArrayList();
Stack nsStack = new Stack();
>>>

\<<<
import java.util.ArrayList;
import java.util.HashSet;
import xtpipes.XtpipesUni;
>>>


%%%%%%%%%%%%%
\subsection{Name Spaces at End of Elements}
%%%%%%%%%%%%%


\<<<
int m = s.indexOf('>');
char [] attrs = s.substring(0,m).toCharArray();
int result = qName.length()+1,
    mark = result,
    from=-1,
    control = `;
char delimiter = ' ';
String name="";
for(int i=result; i: { `  break; }
    case `: { ` break; }
    case `: { ` break; }
} }
s =  (new String(attrs,0, Math.min(result,attrs.length)))
          + s.substring(m);
>>>



\<<<
if( attrs[i] == '=' ){
   name = (new String(attrs,mark,result-mark-1)).trim();
   control = `;
}
>>>

\<<<
if( (attrs[i] == '"') || (attrs[i] == '\'') ){
   delimiter = attrs[i];
   control = `;
   from = result;
}
>>>

\<<<
if( attrs[i] == delimiter ){
   if( name.startsWith("xmlns")
       && ((name.length() == 5) || (name.charAt(5) == ':')) ){
      String value = (new String(attrs,from,result-from-1)).trim();
      `
      if( bool ){ result = mark; }
   }
   mark = result;
   control = `;
}
>>>



%%%%%%%%%%%%%
\subsection{Name Spaces Inheritence}
%%%%%%%%%%%%%





\<<<
int top = nsName.size();
nsStack.push( Integer.valueOf(top) );
>>>

\<<<
int top = ((Integer) nsStack.pop()) . intValue();
for(int i=nsName.size(); i>top; ){
  i--;
  nsName.remove(i);
  nsValue.remove(i);
}
>>>





\OP{xmlns name}
\OP{xmlns quote}
\OP{xmlns value}












%%%%%%%%%%%%%%%%%% 
\section{ScriptsManagerLH: A Lexical Handler}
%%%%%%%%%%%%%%%%%%

\label{ScriptsManagerLH}

The lexical handler sends its strings to the content hadler.

\AtEndDocument{
   \OutputCodE\
}
\AddFile{ScriptsManagerLH.java}{xtpipes\Slash util}

\<<<
/* ScriptsManagerLH.java (`version), generated from `jobname.tex
   Copyright (C) 2009-2010 TeX Users Group
   Copyright (C) `CopyYear.2002. Eitan M. Gurari
` */
package xtpipes.util;
import org.xml.sax.ext.LexicalHandler;
// import org.xml.sax.ContentHandler;
import java.io.PrintWriter;
public class ScriptsManagerLH implements LexicalHandler {
       ScriptsManager contentHandler;
       PrintWriter log;
   public ScriptsManagerLH( ScriptsManager contentHandler,
                          PrintWriter log, boolean trace ){
     this.contentHandler = contentHandler;
     this.log = (log==null)? new PrintWriter( System.err ) : log;
   }
   public void comment(char[] ch, int start, int length){
     if( contentHandler.inBody ){
        String s = new String(ch, start, length);
        contentHandler.add(  "");
   } }
   public void startEntity(String x){}
   public void endEntity(String x){}
   public void startCDATA(){}
   public void endCDATA(){}
   public void startDTD(String x, String y, String z){}
   public void endDTD(){}
}
>>>

\begin{itemize}
\item
The line breaks in the comments are to avoid sequences of comments
loosing their intermediate line breaks and as a result causing
overflow of buffers.

\item The comments in the preamble are included through the
preamble pattribute of xtpipes.
\end{itemize}











%%%%%%%%%%%%%%%%%%%%%%%
\begin{thebibliography}{10}
\bibitem{ref}
{\sl The Reflection API},
Tutorial, Sun Microsystems,
\url{http://java.sun.com/docs/books/tutorial/reflect/TOC.html}.
\end{thebibliography}




%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\ifOption{win}
{
     \AtEndDocument{
        \OutputCodE\
        \Needs{"dodoc"}
     }
}
{ \ifOption{doc}{
  \AtEndDocument{\Needs{"
     mkdir -p doc.dir
     ;
     cd doc.dir
     ;
     java
        -classpath
        ..:../cgjsapi.jar:../../../jldir.dir:../../../jldir.dir/jldoc.jar:../../../ml2xml.dir/ml2xml.dir/bin/ml2xml.jar
        jldoc.Jldoc
        -title "Xtpipes APIs"
        ../work.dir
     ;
     cd ..
     ;
     /usr/bin/rm -r doc.dir
  "}}}{}
}




\<<<
cd work.dir
if NOT EXIST bin mkdir bin
 javac -Xlint:unchecked  -d bin  xtpipes/*.java
 javac -Xlint:unchecked  -d bin  xtpipes/util/*.java
 javac -Xlint:unchecked  -d bin  *.java
cd bin
 jar cf xtpipes.jar *
cd ..
cd xtpipes
if NOT EXIST bin mkdir bin
 move ..\bin\xtpipes.jar bin\.
cd ..
cd ..
>>>

\ifOption{win}{
\immediate\write16{......... work.dir\string \xtpipes\string \lib\string \*}
\immediate\write16{......... work.dir\string \xtpipes\string \bin\string \xtpipes.jar}
}{}


\ifOption{doc}{\let\DOC\def}{}



\ifx\DOC\def
%%%%%%%%%%%%%%%%%%%%%%%
\<<<
if NOT EXIST doc.dir mkdir doc.dir
cd doc.dir
java -classpath ../../jldoc.dir;../../jldoc.dir/jldoc.jar;../../ml2xml.dir/ml2xml.dir/bin/ml2xml.jar jldoc.Jldoc -title "Xtpipes APIs"  ../work.dir/xtpipes
cd ..
rmdir /s /q doc.dir
>>>
%%%%%%%%%%%%%%%

\fi
\




../../..;..;../../jldoc;../../xtpipes/cgjsapi.jar;../../xtpipes/xtpipes.jar;../../jldoc/jldoc.jar;../../ml2xml.dir/ml2xml.dir/bin/ml2xml.jar

\ifdojava
\ifOption{win} {}{
\AtEndDocument{\Needs{%
    "pushd \XTPIPES || exit 1
     ;
     jar cf xtpipes.jar *
     ;
     popd
     ;
     mkdir -p \LIB || exit 1
     ;
     mv \XTPIPES xtpipes.jar \LIB
     ;
     mkdir -p \HOME texmf/tex4ht/xtpipes/. || exit 1
     ;
     cp \XTPIPES xtpipes/lib/*
        \HOME texmf/tex4ht/xtpipes/.
"}}
}
\fi



\ifdojava
\ifOption{win} {}{
  \AtEndDocument{\Needs{"
      mkdir -p \LIB\space || exit 1
      ;
      find \WORK\space -type f -iname '*.java' -print0
      | xargs -0 javac -d \XTPIPES\space -sourcepath \WORK
      ;
      pushd \XTPIPES || exit 1
      ;
      jar cf xtpipes.jar *
      ;
      popd
      ;
      mv \XTPIPES xtpipes.jar \LIB
      ;
      "}}}
\fi


\end{document}