39
\noexpand\<#1\noexpand\><<<
43
\immediate\write15{...... \CNT\space #1}
52
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53
% \AddFile[optional: target file name; default: given file name]
54
% (optional: target home dir; default MYDIR)
65
/ifOption{win}{/gdef/Slash{\}}{}
69
\def\AddFile{\futurelet\ext\AddFileA}
71
\if [\ext \def\ext[##1]{\def\ext{##1}\futurelet\dir\AddFileB}%
72
\else \def\ext{\def\ext{}\futurelet\dir\AddFileB}\fi
75
\if (\dir \def\dir(##1){\def\dir{##1}\AddFileC}%
76
\else \def\dir{\let\dir\MYdir\AddFileC}\fi
81
\expandafter\setStartDir \dir #2!%
84
\xdef\EndDir{\ifx \dir\empty \else \dir\Slash\fi
92
\Needs{"\mv #1\space \dir \Slash#2\Slash
93
\ifx\ext\empty #1\else \ext\fi"}%
100
\expandafter \ifx \csname !\StartDir\endcsname\relax
101
\expandafter\let\csname !\StartDir\endcsname=\empty
102
\Needs{"if NOT EXIST \StartDir \space mkdir \StartDir"}%
104
\ifx \EndDir\empty \else
105
\expandafter\AppendDir \EndDir////*%
111
\expandafter \ifx \csname !\StartDir\endcsname\relax
112
\expandafter\let\csname !\StartDir\endcsname=\empty
113
\Needs{"mkdir \StartDir"}%
115
\ifx \EndDir\empty \else
116
\expandafter\AppendDir \EndDir////*%
122
\def\AppendDir#1/#2/#3/*{%
123
\def\temp{#2}\ifx \temp\empty
126
\edef\StartDir{\ifx \StartDir\empty\else
127
\ifx \StartDir\SLASH \Slash \else
128
\StartDir\Slash\fi \fi
134
\def\setStartDir#1#2!{%
135
\def\StartDir{#1}\ifx\StartDir\SLASH\else
141
% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
142
% % \AddFile[optional: target file name; default: given file name]
143
% % (optional: target home dir; default MYDIR)
146
% \def\AddFile{\futurelet\ext\AddFileA}
148
% \if [\ext \def\ext[##1]{\def\ext{##1}\futurelet\dir\AddFileB}%
149
% \else \def\ext{\def\ext{}\futurelet\dir\AddFileB}\fi
152
% \if (\dir \def\dir(##1){\def\dir{##1}\AddFileC}%
153
% \else \def\dir{\let\dir\MYdir\AddFileC}\fi
155
% \def\AddFileC#1#2{%
156
% \expandafter\setStartDir \dir #2!%
157
% \edef\EndDir{\ifx \dir\empty \else \dir/\fi
158
% #2/\ifx\ext\empty \if !#1!XXX\else #1\fi\else \ext\fi}\MakeDir
160
% \Needs{"mv #1\space \dir /#2/\ifx\ext\empty #1\else \ext\fi"}%
163
% \def\MakeDir{\relax
164
% \expandafter \ifx \csname !\StartDir\endcsname\relax
165
% \expandafter\let\csname !\StartDir\endcsname=\empty
166
% \Needs{"mkdir \StartDir"}%
168
% \ifx \EndDir\empty \else
169
% \expandafter\AppendDir \EndDir////*%
170
% \expandafter\MakeDir
173
% \def\AppendDir#1/#2/#3/*{%
174
% \def\temp{#2}\ifx \temp\empty \let\EndDir=\empty
176
% \edef\StartDir{\ifx \StartDir\empty\else
177
% \ifx \StartDir\SLASH /\else
179
% #1}\def\EndDir{#2/#3}%
182
% \def\setStartDir#1#2!{%
183
% \def\StartDir{#1}\ifx\StartDir\SLASH\else
27
189
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
28
% \AddFile[optional: target file name; default: given file name]
29
% (optional: target home dir; default MYDIR)
32
\def\AddFile{\futurelet\ext\AddFileA}
34
\if [\ext \def\ext[##1]{\def\ext{##1}\futurelet\dir\AddFileB}%
35
\else \def\ext{\def\ext{}\futurelet\dir\AddFileB}\fi
38
\if (\dir \def\dir(##1){\def\dir{##1}\AddFileC}%
39
\else \def\dir{\let\dir\MYdir\AddFileC}\fi
42
\expandafter\setStartDir \dir #2!%
43
\edef\EndDir{\ifx \dir\empty \else \dir/\fi
44
#2/\ifx\ext\empty \if !#1!XXX\else #1\fi\else \ext\fi}\MakeDir
46
\Needs{"mv #1\space \dir /#2/\ifx\ext\empty #1\else \ext\fi"}%
50
\expandafter \ifx \csname !\StartDir\endcsname\relax
51
\expandafter\let\csname !\StartDir\endcsname=\empty
52
\Needs{"mkdir \StartDir"}%
54
\ifx \EndDir\empty \else
55
\expandafter\AppendDir \EndDir////*%
59
\def\AppendDir#1/#2/#3/*{%
60
\def\temp{#2}\ifx \temp\empty \let\EndDir=\empty
62
\edef\StartDir{\ifx \StartDir\empty\else
63
\ifx \StartDir\SLASH /\else
65
#1}\def\EndDir{#2/#3}%
68
\def\setStartDir#1#2!{%
69
\def\StartDir{#1}\ifx\StartDir\SLASH\else
73
192
\def\MYdir{work.dir}
453
\subsection{Comamnd Line Options}
456
\<xtpipes members\><<<
457
private static String inFile,
459
static String scriptDir, scriptFile;
460
static boolean exceptionErrs, messages;
467
scriptFile = "xtpipes-default.4xt";
469
exceptionErrs = false;
636
\subsection{Comamnd Line Options: Outline}
642
if( args[n] == null ){}
643
else if( args[n].equals("") ){}
644
else if( args[n].charAt(0)!='-' ){ inFile = args[n]; }
645
else if( args[n].equals("-m") ){
647
`<output system info`>
649
else if( args[n].equals("-s") ){
650
`<scan script file name`>
652
else if( args[n].equals("-S") ){
653
`<scan script map file name`>
655
else if( args[n].equals("-i") ){
656
`<scan script dir name`>
658
else if( args[n].equals("-o") ){
659
`<scan output file name`>
661
else if( args[n].startsWith("-x") ){
662
`<scan ml2xml argument`>
664
else if( args[n].equals("-E") ){
665
exceptionErrs = true;
667
else if( args[n].equals("-d") ){
670
else if( args[n].equals("-trace") ){ trace=true; }
671
else if( args[n].equals("-help") ){ help=true; }
672
else { `<improper args[n]`> }
676
\<display command line syntax\><<<
677
System.err.println( xtpipes_call );
680
\<command line vars\><<<
681
String xtpipes_call =
682
" xtpipes (`version)"
683
+ "\n Command line options: "
684
+ "\n java xtpipes [-trace] [-help] [-m] [-E] [-s script_file]"
686
+ "\n [-i script_dir] [-o out_file] "
687
+ "\n [-x...ml2xml_arg...] "
688
+ "(-d in_data | in_file)"
689
+ "\n -m messages printing mode"
690
+ "\n -E error messages into exception calls"
691
+ "\n in_data XML data directly into the command line\n"
697
At least one `-x' command line option is required for ml2xml
698
to be called. An empty postfix is also fine.
702
\<s += input file name within args\><<<
703
for( int n=0; n<args.length; n++ ){
704
if( args[n].charAt(0)!='-' ){
705
s += " input file: " + args[n] + "."; break;
707
else if( args[n].equals("-s")
708
|| args[n].equals("-S")
709
|| args[n].equals("-i")
710
|| args[n].equals("-o")
711
|| args[n].equals("-d") ){ n++; }
716
\subsection{Comamnd Line Options: Processing}
474
721
\<process command line\><<<
475
722
boolean help=false;
476
723
for( int n=0; n<args.length; n++ ){
477
if( args[n].charAt(0)!='-' ){ inFile = args[n]; }
478
else if( args[n].equals("-m") ){
480
logWriter.println("xtpipes (`version)");
482
else if( args[n].equals("-s") ){
483
`<scan script file name`>
485
else if( args[n].equals("-i") ){
486
`<scan script dir name`>
488
else if( args[n].equals("-o") ){
489
`<scan output file name`>
491
else if( args[n].equals("-E") ){
492
exceptionErrs = true;
494
else if( args[n].equals("-d") ){
497
else if( args[n].equals("-trace") ){ trace=true; }
498
else if( args[n].equals("-help") ){ help=true; }
499
else if( !args[n].equals("") ){
501
"--- Error --- Improper argument: " + args[n] );
502
inFile = null; inData = null; break;
504
726
`<default stdio output`>
727
`<help message and stop on improper args in batch mode`>
728
new FileInfo(logWriter, i_scriptDir, trace);
729
if( inFile != null ){
730
inputObject = new InputObject( inFile, logWriter );
731
if( inputObject.getInputStream() == null ){
732
instructionErr( null, "Could not find or open file: " + inFile, 28 );
734
inFile = inputObject.getFilename();
736
inputObject = new InputObject( inData.getBytes("UTF-8"), logWriter );
738
inputObject.buildProfile( trace );
741
\<help message and stop on improper args in batch mode\><<<
505
742
if( !returnDom ){
506
743
if( help || ((inFile == null) && (inData == null)) ){
508
" Command line options: " +
509
"java xtpipes [-trace] [-help] [-m] [-E] [-s script_file]\n"
510
+ " [-i script_dir] [-o out_file] "
511
+ "[-d in_data] in_file\n\n"
512
+ " -m messages printing mode\n"
513
+ " -E error messages into exception calls\n"
514
+ " in_data XML data directly into the command line\n"
744
`<display command line syntax`>
516
745
if( (inFile == null) && (inData == null) ){
521
\<scan script file name\><<<
523
if( n < args.length ){ scriptFile=args[n]; }
526
"--- Error --- Missing field for -s argument" );
527
inFile = null; inData = null; break;
533
\<scan script dir name\><<<
535
if( n < args.length ){
539
"--- Error --- Missing field for -s argument" );
540
inFile = null; inData = null; break;
750
\<improper args[n]\><<<
751
if( !exceptionErrs ){
752
for(int i=n+1; i<args.length; i++ ){
753
if( args[i].equals("-E") ){ exceptionErrs = true; }
755
instructionErr( null,
756
"Improper argument: " + args[n] + "\n" + xtpipes_call, 26 );
684
\section{The Instructions}
890
\section{The xtpipes Script}
894
The translation of a file is driven by a script that determines the
895
transformations to be applied to the diffrent fragments of the input
896
data. The name of the script may be found in different locations.
900
A xtpipes processing instruction within the input
902
Command line option `-s'
904
A .map file that checks the data characteristics to determine the
905
script. Currently available only to input files, not to input strings.
911
\subsection{Command Line Options}
915
A script should satisfy the rules of `xtpipes.dtd',
916
and a map should satisfy the rules of `xtpipes-map.dtd'.
921
\<scan script file name\><<<
923
if( n < args.length ){ scriptFile=args[n]; }
926
"--- Error --- Missing field for -s argument" );
927
inFile = null; inData = null; break;
932
\<scan script map file name\><<<
934
if( n < args.length ){ scriptMap=args[n]; }
937
"--- Error --- Missing field for -S argument" );
938
inFile = null; inData = null; break;
943
\<scan script dir name\><<<
945
if( n < args.length ){
949
"--- Error --- Missing field for -i argument" );
950
inFile = null; inData = null; break;
957
\<xtpipes fields\><<<
958
public static String scriptFile;
959
private static String scriptMap;
960
static String i_scriptDir;
974
\subsection{Getting the Start Up Script}
977
The command line arguments may provide a pointer to
978
a `scriptFile' and a pointer to an algorithm `scriptMap'
979
for getting the script file name.
981
With and without ml2xml
983
\<scriptFile := entry script file name\><<<
984
if( scriptMap != null ){
986
String f = FileInfo.searchFile( scriptMap );
988
throw new java.io.FileNotFoundException( scriptMap );
993
saxReader.setContentHandler( new DefaultHandler(){
994
`<process script map`>
996
InputStream inputStream =
997
(InputStream) (new File(scriptMap).toURI().toURL().openStream());
998
saxReader.parse( new InputSource(inputStream) );
999
saxReaderStack.push( saxReader );
1000
} catch( java.io.FileNotFoundException e ){
1001
instructionErr( null,
1002
"File not found: " + e.getMessage()
1003
+ "; command line option -i",
1005
} catch( Exception e ){
1006
instructionErr( null, e.toString(), e.getStackTrace(), 27 );
1009
if( scriptFile == null ){
1010
scriptFile = "xtpipes-default.4xt";
1015
\<process script map\><<<
1016
private Stack <Boolean> condition = new Stack <Boolean> ();
1019
\<process script map\><<<
1020
public void startDocument () {
1021
condition.push( new Boolean(true) );
1025
\<process script map\><<<
1026
public void startElement(String ns, String sName,
1027
String qName, Attributes atts) {
1028
if( condition == null ){ return; }
1029
`<trace start map element`>
1030
boolean cond = ((Boolean) condition.peek()).booleanValue();
1031
if( qName.equals("when") ){
1032
if( cond ){ `<cond := when ...`> }
1035
if( qName.equals("command-line") ){
1036
if( scriptFile != null ){
1037
`<trace found script in map`>
1042
if( qName.equals("processing-instruction") ){
1044
String s = inputObject.getXtpipes();
1046
Xtpipes.scriptFile = s;
1047
`<trace found script in map`>
1052
if( qName.equals("select") ){
1054
Xtpipes.scriptFile = atts.getValue("name");
1055
`<trace found script in map`>
1059
condition.push( new Boolean(cond) );
1066
\<process script map\><<<
1067
public void endElement(String ns, String sName, String qName) {
1068
if( condition == null ){ return; }
1069
`<trace end map element`>
1076
\<cond := when ...\><<<
1077
String name = atts.getValue("name");
1078
String value = atts.getValue("value");
1079
if( name.equals("system-id") ){
1080
cond = value.equals(inputObject.getSystemId());
1083
if( name.equals("public-id") ){
1084
cond = value.equals(inputObject.getPublicId());
1087
if( name.equals("dtd-root") ){
1088
cond = value.equals(inputObject.getDtdRoot());
1091
if( name.equals("root") ){
1092
cond = value.equals(inputObject.getRoot());
1095
if( name.equals("ext") ){
1096
cond = inputObject.getFilename().endsWith("." + value);
1099
if( name.equals("prefix") ){
1100
name = inputObject.getFilename();
1102
int i = name.lastIndexOf('/');
1103
if( (i != -1) && ((i+1) < name.length()) ){
1104
name = name.substring(i+1);
1106
i = name.lastIndexOf('\\');
1107
if( (i != -1) && ((i+1) < name.length()) ){
1108
name = name.substring(i+1);
1110
cond = name.startsWith(value);
1113
if( name.equals("meta-type") ){
1114
cond = value.equals(inputObject.getMetaType());
1117
if( name.equals("content-type") ){
1118
cond = value.equals(inputObject.getContentType());
1128
\<trace found script in map\><<<
1130
Xtpipes.logWriter.println( " Found script file in map: "
1131
+ Xtpipes.scriptFile );
1136
\<trace start map element\><<<
1137
if( Xtpipes.trace ){
1138
String s = "<" + qName + "\n";
1139
for(int i=0; i<atts.getLength(); i++ ){
1140
String name = atts.getQName(i);
1141
s += " " + name + "=\"" + atts.getValue(i) + "\"";
1144
Xtpipes.logWriter.println( s );
1148
\<trace end map element\><<<
1149
if( Xtpipes.trace ){
1150
String s = "</" + qName + ">";
1151
Xtpipes.logWriter.println( s );
1164
\immediate\openin15=xtpipes.dtd
1166
\immediate\closein15
1167
[\HPage{xtpipes.dtd}
1168
\verbatiminput{xtpipes.dtd}
1174
\immediate\openin15=xtpipes-map.dtd
1176
\immediate\closein15
1177
[\HPage{xtpipes-map.dtd}
1178
\verbatiminput{xtpipes-map.dtd}
693
1183
\begin{verbatim}
694
1184
<xtpipes> ... </xtpipes>
701
1191
signature CDATA #IMPLIED >
704
If the element has no children, the input file is searched for an
705
alternative script within a processing instruction of the form
706
\verb+<?xtpipes file="..." ?>+.
709
\<execute xtpipes\><<<
712
if( node.hasChildNodes() ){
714
`<cond copy input preamble`>
715
execute( node.getFirstChild() );
1197
\OutputCodE\<xtpipes-map.dtd\>
1200
\expandafter\AddFile\BIN{xtpipes-map.dtd}{xtpipes\Slash lib}
1203
\<xtpipes-map.dtd\><<<
1204
<!-- xtpipes-map.dtd (`version) -->
1205
<!ELEMENT xtpipes-map (when | processing-instruction
1208
<!ELEMENT when (when | select
1209
| processing-instruction
1211
<!ELEMENT select EMPTY >
1212
<!ELEMENT processing-instruction EMPTY >
1213
<!ELEMENT command-line EMPTY >
1214
<!ATTLIST xtpipes-map
1215
signature CDATA #IMPLIED
1226
| prefix ) "public-id"
1227
value CDATA #IMPLIED
1228
case-sensitive (yes|no) "no"
1231
name CDATA #REQUIRED
1237
\subsection{Indirect Scripts}
1242
If the root xtpipes element has no children, the input file is
1243
searched for an alternative script within a processing instruction of
1244
the form \verb+<?xtpipes file="..." ?>+.
1246
\<script := xtpipes processing instruction\><<<
1247
if( inData == null ){
1248
`<search file for xtpipes instruction`>
719
saxReader.setContentHandler( new XtPipesSearch() );
720
if( inData == null ){
721
`<search file for xtpipes instruction`>
723
`<search string for xtpipes instruction`>
725
saxReaderStack.push( saxReader );
726
} catch(Exception e){
727
instructionErr( node, errMsg + e.toString(), 13 );
1250
`<search string for xtpipes instruction`>
1256
\subsection{Search File}
734
1262
\<search file for xtpipes instruction\><<<
735
errMsg = "Searching <?xtpipes file=\"...\"?> in "
1264
errMsg = "Searching <?xtpipes file=\"...\"?> in "
1267
scriptFile = inputObject.getXtpipes();
1268
rootName = inputObject.getRoot();
1272
\<search file for xtpipes instructionOLD\><<<
1273
errMsg = "Searching <?xtpipes file=\"...\"?> in "
1276
saxReader.setContentHandler( new XtPipesSearch() );
738
saxReader.parse( new File(inFile).toURL().toString() );
1278
saxReader.parse( new File(inFile).toURI().toURL().toString() );
739
1279
} catch ( java.io.FileNotFoundException ioe ){
741
1281
saxReader.parse( new InputSource(
742
1282
new URL(inFile) . openStream() ));
743
1283
} catch ( java.io.FileNotFoundException fnf ){
744
saxReader.parse( new File(inFile).toURL().toString() );
1284
saxReader.parse( new File(inFile).toURI().toURL().toString() );
750
\<search string for xtpipes instruction\><<<
751
errMsg = "Searching <?xtpipes file=\"...\"?> in "
752
+ inData.substring(0, Math.min(70,inData.length()))
754
byte [] bytes = inData.getBytes("UTF-8");
755
ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
756
InputSource is = new InputSource( bais );
766
\<xtpipes members\><<<
767
static class XtPipesSearch extends DefaultHandler {
768
public void endElement(String uri,
769
String localName, String qName){
770
`<extract root element name`>
772
public void processingInstruction(String target, String attrs) {
773
if( !needScript && target.equals("xtpipes") ){
774
`<extract script file name`>
780
\<xtpipes members\><<<
781
private static String rootName;
789
\<extract root element name\><<<
794
\<extract script file name\><<<
797
saxReader.setContentHandler(new DefaultHandler() {
798
public void startElement(String uri, String localName,
799
String qName, Attributes atts) {
800
String filename = atts.getValue("file");
801
if( filename != null ){
802
scriptFile = filename;
805
"Requesting XtPipes script file: "
811
String str = "<xtpipes " + attrs + "/>";
812
StringReader reader = new StringReader(str);
813
InputSource in = new InputSource(reader);
815
saxReaderStack.push( saxReader );
816
} catch(Exception e){
817
System.err.println( "--- Error 10 --- " + e );
1286
saxReaderStack.push( saxReader );
822
1290
\subsection{Copy Preamble}
1294
Copy into th eoutput the code preceeding the root. Note: assumes proper
1295
XML file as it doesn't use ml2xml. NEEDS FIXING.
1299
----> <?xml version="1.0" encoding="UTF-8"?>
1300
----> <!DOCTYPE math:math PUBLIC "-//W3C//DTD MathML 2.0//EN" "math.dtd">
1301
----> <?xtpipes file="oo-math.4xt" ?>
1302
----> <!-- try-m12 by TeX4ht from try.tex line 69 2007-01-09-11:20
1303
----> (http://www.cse.ohio-state.edu/~gurari/TeX4ht/) -->
825
1308
\<cond copy input preamble\><<<
826
1309
if( node.hasAttributes() ){
827
1310
Node attr = node.getAttributes()
828
1311
.getNamedItem( "signature" );
829
if ( (attr != null) && messages ) {
830
logWriter.println( attr.getNodeValue() );
1312
`<preamble output into log`>
832
1313
attr = node.getAttributes()
833
1314
.getNamedItem( "preamble" );
834
1315
if( (attr != null)
1851
\section{Generic Content Handler}
1856
\subsection{Outline}
1859
\label{ScriptsManager}
1862
\OutputCodE\<ScriptsManager.java\>
1864
\AddFile{ScriptsManager.java}{xtpipes/lib}
1867
\<ScriptsManager.java\><<<
1869
package xtpipes.lib;
1870
import xtpipes.XtpipesUni;
1872
import org.xml.sax.helpers.DefaultHandler;
1873
import org.xml.sax.*;
1875
import java.lang.reflect.*;
1876
import java.util.HashMap;
1877
import java.util.Stack;
1879
public class ScriptsManager extends DefaultHandler {
1880
`<ScriptsManager vars`>
1881
PrintWriter out = null;
1882
HashMap scripts = null;
1883
Method method = null;
1884
boolean savemode=false;
1885
String code="", match = null;
1886
Stack<Object[]> stack = new Stack<Object[]>();
1887
public ScriptsManager( PrintWriter out,
1888
HashMap scripts, Method method ){
1890
this.scripts = scripts;
1891
this.method = method;
1893
public void characters(char[] ch, int start, int length){
1894
add( XtpipesUni.toUni(ch, start, length, "<>&") );
1896
`<ScriptsManager: void startElement(ns, sName, qName, atts)`>
1897
`<ScriptsManager: void endElement(ns, sName, qName)`>
1898
public void add(String s){
1899
if( savemode ){ code+=s; }
1900
else { out.print(s); }
1907
\subsection{Start Elements}
1913
\<ScriptsManager: void startElement(ns, sName, qName, atts)\><<<
1914
public void startElement(String ns, String sName,
1915
String qName, Attributes atts) {
1917
String s = "<" + qName + "\n";
1918
for(int i=0; i<atts.getLength(); i++ ){
1919
String name = atts.getQName(i);
1920
if( name != "xmlns" ){
1921
s += " " + name + "=\"" +
1922
XtpipesUni.toUni(atts.getValue(i), "<>&\"") + "\"";
1925
`<flag := start new save?`>
1926
`<set start element`>
1931
\<ScriptsManager vars\><<<
1932
boolean inBody = false;
1936
\<flag := start new save?\><<<
1937
String key = (atts==null)?
1939
: (qName + "::" + atts.getValue("class"));
1940
boolean flag = (key != null) && scripts.containsKey(key);
1944
flag = scripts.containsKey(key);
1948
\<set start element\><<<
1950
Object [] state = { new Boolean(savemode), code, match };
1951
stack.push( state );
1952
savemode=true; code=""; match= key;
1954
Object [] state = { new Boolean(savemode), null, null };
1955
stack.push( state );
1960
The parsing of an XML string is similar to that of done by a
1961
left-to-right bottom up parser of a programming language.
1962
Specifically, the token are read and send on to the output stream,
1963
until an element whose name appears in the hash table of scripts is
1964
encountered. When such an element is encountered, its body is
1965
assembled and the corresponding script is applied on the body. The
1966
processing might be recursive, in the sense that enclosed elements
1967
might also have scripts to process them.
1969
The above applies also to an element name concatenated with its class
1970
attribute value, with the substring `::' as a separator.
1974
\subsection{End Elements}
1979
\<ScriptsManager: void endElement(ns, sName, qName)\><<<
1980
public void endElement(String ns, String sName, String qName){
1981
String s = "</" + qName + ">";
1982
if( savemode ){ code+=s; }
1983
else { out.print(s); }
1984
Object [] state = (Object []) stack.pop();
1985
if( (String) state[1] != null ){
1998
\<invoke script\><<<
1999
Object parmValues[] = new Object[2];
2000
parmValues[0] = scripts.get( match );
2001
parmValues[1] = code;
2003
s = (String) method.invoke( null, parmValues );
2004
} catch (Exception e){
2006
"--- ScriptsManager Error --- " + e );
2011
Can't invoke exception above.
2013
\<set end element\><<<
2014
savemode = ((Boolean) state[0]).booleanValue();
2015
code = (String) state[1];
2016
match = (String) state[2];
2025
\subsection{Generic Lexical Handler}
2028
\label{ScriptsManagerLH}
2031
The lexical handler sends its strings to the content hadler.
2036
\OutputCodE\<ScriptsManagerLH.java\>
2039
\AddFile{ScriptsManagerLH.java}{xtpipes/lib}
2043
\<ScriptsManagerLH.java\><<<
2045
package xtpipes.lib;
2046
import org.xml.sax.ext.LexicalHandler;
2047
import org.xml.sax.ContentHandler;
2048
public class ScriptsManagerLH implements LexicalHandler {
2049
ScriptsManager contentHandler;
2050
public ScriptsManagerLH( ScriptsManager contentHandler ){
2051
this.contentHandler = contentHandler;
2053
public void comment(char[] ch, int start, int length){
2054
if( contentHandler.inBody ){
2055
String s = new String(ch, start, length);
2056
contentHandler.add( "<!--" + s + "\n-->");
2058
public void startEntity(String x){}
2059
public void endEntity(String x){}
2060
public void startCDATA(){}
2061
public void endCDATA(){}
2062
public void startDTD(String x, String y, String z){}
2063
public void endDTD(){}
2069
The line breaks in the comments are to avoid sequences of comments
2070
loosing their intermediate line breaks and as a result causing
2071
overflow of buffers.
2073
\item The comments in the preamble are included through the
2074
preamble pattribute of xtpipes.
2081
\section{Unicode Filter}
2084
Non ascii characters are translated into unicode hexadecimal entities.
2085
The same holds for ascii characters listed within the filter.
2088
\OutputCodE\<XtpipesUni.java\>
2090
\AddFile{XtpipesUni.java}{xtpipes}
2093
\<XtpipesUni.java\><<<
2096
public class XtpipesUni{
2097
`<String toUni( char[], start, length, filter )`>
2098
`<String toUni( String, filter )`>
2102
\<String toUni( char[], start, length, filter )\><<<
2103
public static String toUni( char[] ch, int start, int length,
2105
StringBuffer buf = new StringBuffer(length);
2106
for (int i = 0; i < length; i++) {
2107
int chr = ch[ start + i ];
2108
boolean ascii = (chr == '\n')
2109
|| (chr > 31) && (chr < 127) ;
2110
if( filter.indexOf(chr) > -1 ){ ascii = false; }
2112
ascii ? Character.toString((char) chr)
2114
+ Integer.toHexString(chr).toUpperCase()
2117
return new String(buf);
2121
\<String toUni( String, filter )\><<<
2122
public static String toUni( String s, String filter ){
2123
char [] ch = s.toCharArray();
2124
int length = ch.length;
2125
return toUni(ch, 0, length, filter);
2135
2500
%%%%%%%%%%%%%%%%%%
2767
\section{Input Objects for XML Files}
2770
The XML files my contain faults as a brute force approach is applied in
2771
which the file is scanned directly without trying to build an XML object.
2774
\subsection{Outline}
2779
\OutputCodE\<InputObject.java\>
2782
\AddFile{InputObject.java}{xtpipes}
2785
\<InputObject.java\><<<
2788
InputObject.java (`version)
2790
`<InputObject imports`>
2792
public class InputObject{
2793
`<InputObject fields`>
2794
`<public InputObject(...)`>
2795
`<java.io.InputStream getInputStream( filename )`>
2796
`<java.io.InputStream getInputStream( url )`>
2797
`<void buildProfile( boolean trace )`>
2798
public InputStream getInputStream(){ return inputStream; }
2799
public String getFilename(){
2800
return (url == null)?
2801
( (connection == null)? filename
2803
connection . getURL() . toString()
2807
public String getContentType(){ return contentType; }
2808
public String getMetaType(){ return metaType; }
2809
public String getPublicId(){ return publicId; }
2810
public String getSystemId(){ return systemId; }
2811
public String getXtpipes(){ return xtpipes; }
2812
public String getRoot(){ return root; }
2813
public String getDtdRoot(){ return dtdRoot; }
2817
\<InputObject fields\><<<
2818
InputStream inputStream = null;
2819
URLConnection connection = null;
2820
String filename = null;
2821
static PrintWriter log;
2824
\<InputObject imports\><<<
2825
import java.io.PrintWriter;
2826
import java.net.URL;
2827
import java.net.URLConnection;
2828
import java.io.ByteArrayInputStream;
2829
import java.io.File;
2830
import java.io.InputStream;
2834
\subsection{Constructor}
2840
\<public InputObject(...)\><<<
2841
public InputObject( String filename, PrintWriter log ){
2842
InputObject.log = log;
2843
filename = filename.trim();
2845
inputStream = getInputStream(filename);
2846
} catch (Exception exp0){
2847
if( !filename.startsWith( "http://" ) ){
2849
String name = "http://" + filename;
2850
inputStream = getInputStream( name );
2852
} catch (Exception exp1){
2854
String name = FileInfo.cleanPath(filename);
2855
inputStream = getInputStream( name );
2857
} catch (Exception exp2){ inputStream = null; }
2859
this.filename = filename;
2863
\<public InputObject(...)\><<<
2864
public InputObject( byte [] bytes, PrintWriter log ){
2865
InputObject.log = log;
2866
inputStream = new ByteArrayInputStream( bytes );
2873
\subsection{Stream from a File Name}
2878
\<java.io.InputStream getInputStream( filename )\><<<
2879
private java.io.InputStream getInputStream(
2881
throws java.io.IOException{
2882
if( filename == null ){ return null; }
2884
java.io.InputStream inputStream = null;
2885
// String loadingError = "Failed to get requested file.";
2887
url = new File(filename).toURI().toURL();
2888
inputStream = getInputStream( url );
2889
} catch (Exception ie) {
2891
url = new URL(filename);
2892
inputStream = getInputStream( url );
2893
} catch (java.io.FileNotFoundException ife) {
2894
throw new java.io.IOException(
2895
"File not found: " + filename);
2896
} catch (Exception ife) {
2897
throw new java.io.IOException(ife + "\n" + ie);
2905
\subsection{Stream from a URL}
2908
\<java.io.InputStream getInputStream( url )\><<<
2909
private java.io.InputStream getInputStream( URL url )
2910
throws java.io.FileNotFoundException,
2911
java.io.IOException {
2912
java.io.InputStream inputStream = null;
2913
String errMssg = "";
2916
connection = url.openConnection();
2917
connection.setRequestProperty("User-Agent",
2919
+ System.getProperty("os.name")
2921
+ System.getProperty("os.arch")
2924
+ System.getProperty("java.version")
2926
+ System.getProperty("java.vendor")
2930
inputStream = connection.getInputStream();
2931
} catch(java.io.FileNotFoundException ve){
2932
errMssg = "File not found: " + url;
2933
throw new java.io.FileNotFoundException(
2934
"--- Ml2xml input error --- " + errMssg );
2935
} catch (javax.net.ssl.SSLHandshakeException ve){
2936
errMssg = "SSL Handshake Exception: " + ve.getMessage();
2937
throw new javax.net.ssl.SSLHandshakeException(
2938
"--- Ml2xml input error --- " + errMssg );
2939
} catch (java.net.UnknownHostException ve){
2940
errMssg = "Unknown Host Exception: " + ve.getMessage();
2941
throw new java.net.UnknownHostException(
2942
"--- Ml2xml input error --- " + errMssg );
2951
\subsection{Clean Path}
2956
\<static String cleanPath( path )\><<<
2957
public static String cleanPath( String path ){
2958
String slash = System.getProperty("file.separator");
2959
String userDir = System.getProperty( "user.dir" );
2960
`<clean leading wigle`>
2961
`<clean leading dots`>
2962
`<clean internal dots`>
2967
\<clean leading wigle\><<<
2968
if( (path.length() > 0) && (path.charAt(0) == '~') ){
2969
if( (path.length() == 1) || (path.charAt(1) != '~') ){
2970
path = System.getProperty( "user.home" )
2971
+ path.substring(1);
2975
\<clean leading dots\><<<
2976
if( path.startsWith("..") ){
2977
path = userDir.substring(0,
2978
Math.max(0,Math.max(
2979
userDir.lastIndexOf("/")
2981
userDir.lastIndexOf("\\")
2983
+ path.substring(2);
2985
if( path.startsWith(".") ){
2986
path = userDir + slash + path.substring(1);
2990
\<clean internal dots\><<<
2993
((i=path.indexOf("/..")) != -1)
2995
((i=path.indexOf("\\..")) != -1)
2997
String s = path.substring(0,i);
2998
int j = Math.max(s.lastIndexOf("/"), s.lastIndexOf("\\"));
2999
path = path.substring(0,j) + path.substring(i+3);
3002
((i=path.indexOf("/.")) != -1)
3004
((i=path.indexOf("\\.")) != -1)
3006
String s = path.substring(0,i);
3007
int j = Math.max(s.indexOf("/"), s.indexOf("\\"));
3008
path = path.substring(0,j) + path.substring(i+2);
3015
\subsection{Profile: Connecting and Reading the Input File}
3018
\<void buildProfile( boolean trace )\><<<
3019
public void buildProfile( boolean trace ){
3022
"xtpipes (`version)"
3023
+ "\n java.version: " + System.getProperty("java.version")
3024
+ "\n java.class.path: " + System.getProperty("java.class.path")
3025
+ "\n os.name: " + System.getProperty("os.name")
3026
+ "\n user.home: " + System.getProperty("user.home")
3027
+ "\n user.dir: " + System.getProperty("user.dir")
3030
if( connection != null ){
3031
`<profile info from connection`>
3033
`<profile from preamble of file`>
3037
+ "\n contentType = " + contentType
3038
+ "\n publicId = " + publicId
3039
+ "\n systemId = " + systemId
3040
+ "\n xtpipes = " + xtpipes
3041
+ "\n root = " + root
3042
+ "\n dtdRoot = " + dtdRoot
3048
\<profile info from connection\><<<
3049
contentType = connection . getContentType();
3050
url = connection . getURL() . toString();
3055
\<profile from preamble of file\><<<
3057
int buffSize = 4096;
3058
byte [] buff = new byte [ buffSize ];
3062
int type = `<undef type`>;
3063
String token = null;
3066
int k = Math.min( max - m, buffSize );
3067
length = inputStream.read( buff, 0, k );
3068
if( length == -1 ){ break; }
3069
if( length == 0 ){ continue; }
3070
} catch (java.io.IOException e){
3071
System.err.println( "--- xtpipes error --- : " + e );
3074
for(int i = 0 ; i < length; i++ ){
3075
`<search preamble info`>
3082
\subsection{Profile: Scanning the Different Cases}
3088
\<search preamble info\><<<
3089
switch( ch = buff[i] ){
3090
case '<': token = "";
3093
case '>': if( token != null ){
3094
token = token . replaceAll( "\\s+", " ");
3100
case ' ': if( token != null ){
3105
case '\'': if( token == null ){ break; }
3106
`<public and system ids`>
3107
default: if( token != null ){
3108
if( type == `<pre doctype`> ){
3112
} else { token = null; type = `<undef type`>; }
3115
if( token.equals("") && (type == `<new tok`>) ){
3117
} else { token += (char) ch; }
3122
\<public and system ids\><<<
3123
if( !token.trim().equals("") ){
3124
if( token.trim().charAt(0) == ch ){
3125
if( type == `<public id`> ){
3126
publicId = token.trim().substring(1);
3127
type = `<system id`>;
3131
else if( type == `<system id`> ){
3132
systemId = token.trim().substring(1);
3140
\<get token type\><<<
3142
case '!': type = `<pre doctype`>;
3144
case '?': type = `<proc instruction`> ;
3146
default: if( Character.isLetter(ch)
3147
&& ((root == null) || (metaType == null)) ){
3148
type = `<root or meta`>;
3150
} else { token = null; }
3155
if( type == `<proc instruction`> ){
3156
if( xtpipes == null ){
3157
int n = token.length();
3158
if( (n > 1) && (token.charAt( n - 1 ) == '?')
3159
&& (token.startsWith("xtpipes") ) ){
3160
String s = token . substring(7,n-1) . replaceAll( "\\s+", "");
3162
if( (n>6) && (s.startsWith("file="))
3163
&& (s.charAt(5) == s.charAt(n-1)) ){
3164
xtpipes = s.substring(6,n-1);
3166
} else if( type == `<meta`> ){
3167
if( metaType == null ){
3168
token = token . replaceAll( "\\s+", "");
3169
int k = token.indexOf("http-equiv");
3170
int n = token.indexOf("content");
3171
if( (k != -1) && (n != -1) ){
3172
if( token.length() > (Math.max(k,n)+3) ){
3173
if( token.substring(k+12).startsWith("Content-Type") ){
3174
token = token.substring(n+9);
3175
n = token.indexOf(";");
3176
if( n !=-1 ){ metaType = token.substring(0,n); }
3178
} else if( (type == `<root or meta`>) && (root == null) ){
3183
\<at token space\><<<
3184
if( type == `<root or meta`> ){
3185
if( token.equals("meta") ){
3186
if( metaType == null ){
3198
} else if( type == `<doctype`> ){
3199
if( token.equals("DOCTYPE") ){
3200
type = `<doctype root`>;
3202
} else { token = null; }
3203
} else if( type == `<doctype root`> ){
3204
if( !token.trim().equals("") ){
3205
dtdRoot = token.trim();
3207
type = `<doctype id`>;
3208
} else { token = null; }
3209
} else if( type == `<doctype id`> ){
3210
if( !token.trim().equals("") ){
3211
token = token.trim();
3212
if( token.equals("PUBLIC") ){
3213
type = `<public id`>;
3215
} else if( token.equals("SYSTEM") ){
3216
type = `<system id`>;
3218
} else { token = null; }
3220
} else { token += ' '; }
3224
\<InputObject fields\><<<
3225
String dtdRoot = null,
3244
\OP{proc instruction}
3250
\section{Input Objects for XML Strings}
3256
\subsection{Search String for Indirection}
3260
\<search string for xtpipes instruction\><<<
3261
scriptFile = inputObject.getXtpipes();
3262
rootName = inputObject.getRoot();
3267
Remove XtPipesSearch!!!!!!!!!!!!!!
3272
saxReader.setContentHandler( new XtPipesSearch() );
3273
`<body of search string for xtpipes instruction`>
3274
saxReaderStack.push( saxReader );
3275
} catch(Exception e){
3276
e.printStackTrace();
3277
instructionErr( node, errMsg + e.toString(), 13 );
3281
\<body of search string for xtpipes instruction\><<<
3282
errMsg = "Searching <?xtpipes file=\"...\"?> in "
3283
+ inData.substring(0, Math.min(70,inData.length()))
3285
byte [] bytes = inData.getBytes("UTF-8");
3286
ByteArrayInputStream bais = new ByteArrayInputStream( bytes );
3287
InputSource is = new InputSource( bais );
3288
saxReader.parse(is);
3292
\subsection{The Search Engine}
3297
\<xtpipes fields DELETED\><<<
3298
private static class XtPipesSearch extends DefaultHandler {
3299
public void endElement(String uri,
3300
String localName, String qName){
3301
`<extract root element name`>
3303
public void processingInstruction(String target, String attrs) {
3304
if( !needScript && target.equals("xtpipes") ){
3305
`<extract script file name`>
3311
searched for an alternative script within a processing instruction of
3312
the form \verb+<?xtpipes file="..." ?>+.
3315
\<extract root element name\><<<
3320
\<extract script file name\><<<
3323
saxReader.setContentHandler(new DefaultHandler() {
3324
public void startElement(String uri, String localName,
3325
String qName, Attributes atts) {
3326
String filename = atts.getValue("file");
3327
if( filename != null ){
3328
scriptFile = filename;
3329
`<show script file name in log file`>
3333
String str = "<xtpipes " + attrs + "/>";
3334
StringReader reader = new StringReader(str);
3335
InputSource in = new InputSource(reader);
3336
saxReader.parse(in);
3337
saxReaderStack.push( saxReader );
3338
} catch(Exception e){
3339
System.err.println( "--- Error 10 --- " + e );
3349
\<xtpipes fields\><<<
3350
private static String rootName;
3362
\section{Information About the Transformation}
3366
\subsection{User's System}
3371
\<output system info\><<<
3373
"xtpipes (`version)"
3374
+ "\n java.version: " + System.getProperty("java.version")
3375
+ "\n java.class.path: " + System.getProperty("java.class.path")
3376
+ "\n os.name: " + System.getProperty("os.name")
3377
+ "\n user.home: " + System.getProperty("user.home")
3378
+ "\n user.dir: " + System.getProperty("user.dir")
3380
for( int k=0; k<args.length; k++ ){
3381
logWriter.println( " " + args[k] );
3386
\subsection{Script to be Used}
3390
\<show script file name in log file\><<<
3393
"Requesting XtPipes script file: "
3400
\subsection{Preamble Attribute}
3403
\<preamble output into log\><<<
3404
if ( (attr != null) && messages ) {
3405
logWriter.println( attr.getNodeValue() );
3412
\subsection{Tracing}
3416
\<xtpipes fields\><<<
3417
static boolean trace;
3426
\<trace element\><<<
3428
logWriter.print( "[##] = xtpipes => " + instruction );
3429
if( node.hasAttributes() ){
3430
NamedNodeMap attributes = node.getAttributes();
3431
for(int i=0; i < attributes.getLength(); i++ ){
3432
Node attr = attributes.item(i);
3433
logWriter.print( " " + attr.getNodeName()
3434
+ "=\"" + attr.getNodeValue() + "\"" );
3436
logWriter.println(); logWriter.flush();
3440
\<trace if true\><<<
3442
logWriter.print( "--> true" );
3446
\<trace if false\><<<
3448
logWriter.print( "--> true" );
3453
\<trace open script\><<<
3455
logWriter.println( "(" + scriptFile + ")" );
2335
3461
%%%%%%%%%%%%%%%%%%
2336
3462
\section{loose Ends}
2337
3463
%%%%%%%%%%%%%%%%%%
2341
\subsection{Error Messages}
2349
\<static void instructionErr( node, e, num )\><<<
2350
static void instructionErr( Node node, String e, int num )
3466
\subsection{Fix XML Defaults}
3469
\<xtpipes fields\><<<
3470
private static String [] ml2xml = null;
3471
static Class<?> ml2xmlClassObj = null;
3474
\<scan ml2xml argument\><<<
3475
if( args[n].substring(2).equals("") ){
3476
if( ml2xml == null ){ ml2xml = new String[0]; }
3478
if( ml2xml == null ){
3479
ml2xml = new String[1];
3481
String [] m2x = new String [ml2xml.length + 1];
3482
for(int cnt=0; cnt < ml2xml.length; cnt++){
3483
m2x[cnt] = ml2xml[cnt];
3487
ml2xml[ ml2xml.length - 1 ] = args[n].substring(2);
3492
\<inputStream := (InputStream) new Ml2xml(filename, "foo.m2x")\><<<
3494
ml2xmlClassObj = Class.forName( "ml2xml.Ml2xml" );
3495
} catch (java.lang.ClassNotFoundException cnf ){
3496
instructionErr( null, "Class not found: ml2xml.Ml2xml", 25 );
3498
Class<?> [] argTyp = { String.class, String[].class };
3499
Constructor<?> con = ml2xmlClassObj.getConstructor( argTyp );
3501
`<trace call to ml2xml`>
3502
inputStream = (InputStream) con.newInstance(
3503
new Object[]{xml, ml2xml}
3505
} catch(java.lang.reflect.InvocationTargetException ite){
3506
String s = "Problem at: ml2xml.Ml2xml(" + xml + ","
3508
for(int i=0; i < Xtpipes.ml2xml.length; i++){
3509
s += ((i==0)? "\"" : ", \"") + Xtpipes.ml2xml[i] + "\"";
3512
instructionErr( null, s + "; " + ite.getCause(), 38);
3516
ite.getTargetException().printStackTrace();
3519
\<Ml2xml close files\><<<
3520
if( Xtpipes.ml2xml != null ){
3521
Class<?> [] argTyp = {};
3522
Method m = ml2xmlClassObj . getMethod( "closeFiles", argTyp );
3523
m.invoke( null, new Object[0] );
3527
\<trace call to ml2xml\><<<
3528
if( Xtpipes.trace ){
3529
String s = "Calling: ml2xml.Ml2xml(inputStream,"
3531
for(int i=0; i < Xtpipes.ml2xml.length; i++){
3532
s += ((i==0)? "\"" : ", \"") + Xtpipes.ml2xml[i] + "\"";
3535
Xtpipes.logWriter.println( s );
3540
\<close ml2xml files\><<<
3541
if( ml2xmlClassObj != null ){
3542
Class<?> [] argTypes = { };
3543
Method m = ml2xmlClassObj.getMethod( "closeFiles", argTypes );
3544
Object parmValues[] = new Object[0];
3545
m.invoke( null, parmValues );
3550
\<xtpipes imports\><<<
3551
import java.lang.reflect.Constructor;
3554
Ml2xml is referenced through reflection instead of directly so that xtpipes can
3555
be delivered also without that utility, e.g., for tex4ht where no treatment of faulty
3556
XML file is to be done. In fact, this approach can be generalized to offer
3557
arbitrary filter for the input.
3563
\subsection{Unicode Filter}
3566
Non ascii characters are translated into unicode hexadecimal entities.
3567
The same holds for ascii characters listed within the filter.
3570
\OutputCodE\<XtpipesUni.java\>
3572
\AddFile{XtpipesUni.java}{xtpipes}
3575
\<XtpipesUni.java\><<<
3578
public class XtpipesUni{
3579
`<String toUni( char[], start, length, filter )`>
3580
`<String toUni( String, filter )`>
3584
\<String toUni( char[], start, length, filter )\><<<
3585
private static int D800 = Integer.parseInt("D800", 16);
3586
private static int DFFF = Integer.parseInt("DFFF", 16);
3587
private static int DC00 = Integer.parseInt("DC00", 16);
3588
private static int X400 = Integer.parseInt("400",16);
3589
private static int X10000 = Integer.parseInt("10000",16);
3592
public static String toUni( char[] ch, int start, int length,
3594
StringBuffer buf = new StringBuffer(length);
3595
for (int i = 0; i < length; i++) {
3596
int chr = ch[ start + i ];
3597
boolean ascii = (chr == '\n')
3598
|| (chr > 31) && (chr < 127) ;
3599
if( filter.indexOf(chr) > -1 ){ ascii = false; }
3601
if( (chr >= D800) && (chr<= DFFF) ){
3602
chr = ((ch[i] - D800) * X400 + (ch[++i] - DC00)) + X10000;
3607
ascii ? Character.toString((char) chr)
3609
+ Integer.toHexString(chr).toUpperCase()
3612
return new String(buf);
3616
\<String toUni( String, filter )\><<<
3617
public static String toUni( String s, String filter ){
3618
char [] ch = s.toCharArray();
3619
int length = ch.length;
3620
return toUni(ch, 0, length, filter);
3631
\subsection{Error Messagesg}
3639
\<static void instructionErr(...)\><<<
3640
private static void instructionErr( Node node, String e, int num )
2351
3641
throws Exception {
2352
3642
String err = "--- xtpipes error " + num + " --- ";
2353
3643
if( node != null ){
2405
\<transformer error listener\><<<
2406
new ErrorListener() {
2407
public void warning(TransformerException e) throws TransformerException {
2408
showSpecifics(".....warning", e);
2410
public void error(TransformerException e) throws TransformerException {
2411
showSpecifics(".....error", e);
2413
public void fatalError(TransformerException e) throws TransformerException {
2414
showSpecifics("fatal .....error", e);
2416
void showSpecifics(String s, TransformerException e)
2417
throws TransformerException{
2418
String err = e.getMessage() ;
2419
String loc = e.getLocationAsString();
2420
if( loc != null ){ err = loc + ": " + err; }
2421
throw new TransformerException(err);
2428
\subsection{Tracing}
2432
\<xtpipes members\><<<
2433
static boolean trace;
2442
\<trace element\><<<
2444
logWriter.print( "= xtpipes => " + instruction );
2445
if( node.hasAttributes() ){
2446
NamedNodeMap attributes = node.getAttributes();
2447
for(int i=0; i < attributes.getLength(); i++ ){
2448
Node attr = attributes.item(i);
2449
logWriter.print( " " + attr.getNodeName()
2450
+ "=\"" + attr.getNodeValue() + "\"" );
2452
logWriter.println(); Xtpipes.logWriter.flush();
2456
\<trace if true\><<<
2458
logWriter.print( "--> true" );
2462
\<trace if false\><<<
2464
logWriter.print( "--> true" );
2469
\<trace open script\><<<
2471
logWriter.println( "(" + scriptFile + ")" );
3713
The follower listeners catch errors but their messages are not
3714
delivered through the call to the new exceptions (why?). The field
3715
errMssg is used so that error 16 will produce the same error messages.
3718
\item[Catches errors in the XSLT file]
3722
\<transformer factory XSLT error listener\><<<
3723
new ErrorListener() {
3724
public void warning(TransformerException e) throws TransformerException {
3727
public void error(TransformerException e) throws TransformerException {
3730
public void fatalError(TransformerException e) throws TransformerException {
3733
void showSpecifics(TransformerException e)
3734
throws TransformerException{
3735
String err = e.getMessage() ;
3736
String loc = e.getLocationAsString();
3737
if( loc != null ){ err = loc + ": " + err; }
3738
err = "XSL stylesheet problem: " + err;
3739
if( errMssg == null ){ errMssg = err; }
3740
throw new TransformerException(err);
3745
\item [Catches errors in the XML file]
3747
\<transformer XML error listener\><<<
3748
new ErrorListener() {
3749
public void warning(TransformerException e) throws TransformerException {
3752
public void error(TransformerException e) throws TransformerException {
3755
public void fatalError(TransformerException e) throws TransformerException {
3758
void showSpecifics(TransformerException e)
3759
throws TransformerException{
3760
String err = e.getMessage() ;
3761
String loc = e.getLocationAsString();
3762
if( loc != null ){ err = loc + ": " + err; }
3763
if( errMssg == null ){ errMssg = err; }
3764
err = "XML document prblem: " + err;
3765
throw new TransformerException(err);
3770
\<identity transformer XML error listener\><<<
3771
new ErrorListener() {
3772
public void warning(TransformerException e) throws TransformerException {
3775
public void error(TransformerException e) throws TransformerException {
3778
public void fatalError(TransformerException e) throws TransformerException {
3781
void showSpecifics(TransformerException e)
3782
throws TransformerException{
3783
String err = e.getMessage() ;
3784
String loc = e.getLocationAsString();
3785
if( loc != null ){ err = loc + ": " + err; }
3786
throw new TransformerException(err);
3795
\<xtpipes fields\><<<
3796
public static String errMssg;
3800
\section{Serialize Dom}
3804
\<static String serialize( dom )\><<<
3805
static String serialize( Node root ){
3806
if( root.getNodeType() == Node.TEXT_NODE) {
3807
return root.getNodeValue();
3809
if( root.getNodeType() == Node.ELEMENT_NODE) {
3811
String tagName = root.getNodeName();
3812
ser += "<" + tagName;
3813
`<res += serialize attributes`>
3815
`<res += serialize children`>
3816
ser += "</" + tagName + ">";
3819
if( root.getNodeType() == Node.DOCUMENT_NODE) {
3821
`<res += serialize children`>
3824
if( root == null ){ return "null"; }
3829
\<res += serialize children\><<<
3830
NodeList children = root.getChildNodes();
3831
if(children.getLength() > 0) {
3832
for(int i = 0; i < children.getLength(); i++) {
3833
ser += serialize(children.item(i));
3837
\<res += serialize attributes\><<<
3838
NamedNodeMap attributes = root.getAttributes();
3839
for(int i = 0; i < attributes.getLength(); i++) {
3840
Attr attribute = (Attr) attributes.item(i);
3841
ser += "\n" + attribute.getName() + "=\""
3842
+ attribute.getValue() + "\" ";
3850
\subsection{Clean Xmlns}
3854
\<static void cleanXmlns( dom )\><<<
3855
static ArrayList<String> nsName, nsValue;
3856
static void cleanXmlns( Node root ){
3857
if( root.getNodeType() == Node.ELEMENT_NODE) {
3858
int top = nsName.size();
3859
`<clean xmlns attributes`>
3860
`<clean xmlns in children`>
3861
for(int i=nsName.size(); i>top; ){
3866
} else if( root.getNodeType() == Node.DOCUMENT_NODE) {
3867
nsName = new ArrayList<String>();
3868
nsValue = new ArrayList<String>();
3869
`<clean xmlns in children`>
3877
\<clean xmlns in children\><<<
3878
NodeList children = root.getChildNodes();
3879
if(children.getLength() > 0) {
3880
for(int i = 0; i < children.getLength(); i++) {
3881
cleanXmlns(children.item(i));
3885
\<clean xmlns attributes\><<<
3886
ArrayList<Attr> remove = new ArrayList<Attr>();
3887
NamedNodeMap attributes = root.getAttributes();
3888
for(int i = 0; i < attributes.getLength(); i++) {
3889
Attr attribute = (Attr) attributes.item(i);
3890
String name = attribute.getName();
3891
if( name.startsWith("xmlns") ){
3892
if( (name.length() == 5) || (name.charAt(5) == ':') ){
3893
String value = attribute.getValue();
3894
`<bool := xmlns active?`>
3895
if( bool ){ remove.add(attribute);
3896
} else { nsName.add(name); nsValue.add(value); }
3898
for(int i=remove.size(); i>0; ){
3900
((Element) root).removeAttributeNode( (Attr) remove.get(i) );
3905
\<bool := xmlns active?\><<<
3906
boolean bool = false;
3907
for(int k=nsName.size(); k>0; ){
3909
if( ((String) nsName.get(k)) . equals(name) ){
3910
bool = ((String) nsValue.get(k)) . equals(value);
3915
\<xtpipes imports\><<<
3916
import java.util.ArrayList;
2476
3921
%%%%%%%%%%%%%%%%%%
3952
\part{Useful Pre Fabricated Modules}
3959
\section{ScriptsManager: A Content Handler}
3962
\label{ScriptsManager}
3966
\subsection{Outline}
3971
\OutputCodE\<ScriptsManager.java\>
3973
\AddFile{ScriptsManager.java}{xtpipes\Slash util}
3976
\<ScriptsManager.java\><<<
3978
package xtpipes.util;
3979
`<ScriptsManager imports`>
3981
import org.xml.sax.helpers.DefaultHandler;
3982
import org.xml.sax.*;
3984
import java.lang.reflect.*;
3985
import java.util.HashMap;
3986
import java.util.Stack;
3988
public class ScriptsManager extends DefaultHandler {
3989
`<ScriptsManager fields`>
3990
PrintWriter out = null, log = null;
3991
HashMap<String,Object> scripts = null;
3992
Method method = null;
3993
boolean savemode=false;
3994
String code="", match = null;
3995
Stack<Object[]> stack = new Stack<Object[]>();
3996
public ScriptsManager( PrintWriter out,
3997
HashMap<String,Object> scripts, Method method,
3998
PrintWriter log, boolean trace ){
4000
this.log = (log==null)? new PrintWriter( System.err ) : log;
4001
this.scripts = scripts;
4002
this.method = method;
4004
public void characters(char[] ch, int start, int length){
4005
add( XtpipesUni.toUni(ch, start, length, "<>&") );
4007
`<ScriptsManager: void startElement(ns, sName, qName, atts)`>
4008
`<ScriptsManager: void endElement(ns, sName, qName)`>
4010
if( savemode ){ code+=s; }
4011
else { out.print(s); }
4017
\subsection{Start Elements}
4023
\<ScriptsManager: void startElement(ns, sName, qName, atts)\><<<
4024
public void startElement(String ns, String sName,
4025
String qName, Attributes atts) {
4026
`<save status of xmlns above element`>
4027
`<flag := start new save?`>
4029
String s = "<" + qName + "\n";
4030
for(int i=0; i<atts.getLength(); i++ ){
4031
String name = atts.getQName(i),
4032
value = atts.getValue(i);
4034
s += " " + name + "=\"" +
4035
XtpipesUni.toUni(value, "<>&\"") + "\"";
4037
if( flag ){ `<add missing xmlns attributes`> }
4039
`<set start element`>
4044
\<ScriptsManager fields\><<<
4045
boolean inBody = false;
4049
\<flag := start new save?\><<<
4050
String key = (atts==null)?
4052
: (qName + "::" + atts.getValue("class"));
4053
boolean flag = (key != null) && scripts.containsKey(key);
4057
flag = scripts.containsKey(key);
4061
\<set start element\><<<
4063
Object [] state = { new Boolean(savemode), code, match };
4064
stack.push( state );
4065
savemode=true; code=""; match= key;
4067
Object [] state = { new Boolean(savemode), null, null };
4068
stack.push( state );
4073
The parsing of an XML string is similar to that of done by a
4074
left-to-right bottom up parser of a programming language.
4075
Specifically, the token are read and send on to the output stream,
4076
until an element whose name appears in the hash table of scripts is
4077
encountered. When such an element is encountered, its body is
4078
assembled and the corresponding script is applied on the body. The
4079
processing might be recursive, in the sense that enclosed elements
4080
might also have scripts to process them.
4082
The above applies also to an element name concatenated with its class
4083
attribute value, with the substring `::' as a separator.
4086
\subsection{End Elements}
4091
\<ScriptsManager: void endElement(ns, sName, qName)\><<<
4092
public void endElement(String ns, String sName, String qName){
4093
String s = "</" + qName + ">";
4095
Object [] state = (Object []) stack.pop();
4096
if( (String) state[1] != null ){
4099
`<recall status of xmlns above element`>
4100
`<remove xmlns attributes supported from above`>
4102
} else { `<recall status of xmlns above element`> }
4112
\<invoke script\><<<
4113
Object parmValues[] = new Object[2];
4114
parmValues[0] = scripts.get( match );
4115
parmValues[1] = code;
4117
s = (String) method.invoke( null, parmValues );
4118
} catch(java.lang.reflect.InvocationTargetException e){
4119
log.println("--- ScriptsManager Error 1 --- " + e.getCause() );
4121
} catch (Exception e){
4122
log.println("--- ScriptsManager Error 2 --- " + e );
4128
Can't invoke exception above.
4130
\<set end element\><<<
4131
savemode = ((Boolean) state[0]).booleanValue();
4132
code = (String) state[1];
4133
match = (String) state[2];
4140
\subsection{Name Spaces}
4144
if( name.startsWith("xmlns") ){
4145
if( (name.length() == 5) || (name.charAt(5) == ':') ){
4146
`<bool := xmlns active?`>
4148
nsName.add(name); nsValue.add(value);
4155
\<save status of xmlns above element\><<<
4156
int top = nsName.size();
4157
nsStack.push( new Integer(top) );
4160
\<recall status of xmlns above element\><<<
4161
int top = ((Integer) nsStack.pop()) . intValue();
4162
for(int i=nsName.size(); i>top; ){
4172
\<add missing xmlns attributes\><<<
4173
HashSet<String> registry = new HashSet<String>();
4174
for(int i=nsName.size(); i>top; ){
4176
registry.add( (String) nsName.get(i) );
4178
for(int i=top; i>0; ){
4180
String nm = (String) nsName.get(i);
4181
if( ! registry.contains(nm) ){
4183
s += " " + nm + "=\"" +
4184
XtpipesUni.toUni( (String) nsValue.get(i), "<>&\"") + "\"";
4191
\<ScriptsManager fields\><<<
4192
ArrayList<String> nsName = new ArrayList<String>(),
4193
nsValue = new ArrayList<String>();
4194
Stack<Integer> nsStack = new Stack<Integer>();
4197
\<ScriptsManager imports\><<<
4198
import java.util.ArrayList;
4199
import java.util.HashSet;
4200
import xtpipes.XtpipesUni;
4203
\<remove xmlns attributes supported from above\><<<
4204
int m = s.indexOf('>');
4205
char [] attrs = s.substring(0,m).toCharArray();
4206
int result = qName.length()+1,
4209
control = `<xmlns name`>;
4210
char delimiter = ' ';
4213
for(int i=result; i<m; i++ ){
4214
attrs[result++] = attrs[i];
4216
case `<xmlns name`>: { `<insert attribute name`> break; }
4217
case `<xmlns quote`>: { `<insert attribute quote`> break; }
4218
case `<xmlns value`>: { `<insert attribute value`> break; }
4220
s = (new String(attrs,0,result)) + s.substring(m);
4225
\<insert attribute name\><<<
4226
if( attrs[i] == '=' ){
4227
name = (new String(attrs,mark,result-mark-1)).trim();
4228
control = `<xmlns quote`>;
4232
\<insert attribute quote\><<<
4233
if( (attrs[i] == '"') || (attrs[i] == '\'') ){
4234
delimiter = attrs[i];
4235
control = `<xmlns value`>;
4240
\<insert attribute value\><<<
4241
if( attrs[i] == delimiter ){
4242
if( name.startsWith("xmlns")
4243
&& ((name.length() == 5) || (name.charAt(5) == ':')) ){
4244
String value = (new String(attrs,from,result-from-1)).trim();
4245
`<bool := xmlns active?`>
4246
if( bool ){ result = mark; }
4249
control = `<xmlns name`>;
4261
\section{ScriptsManagerLH: A Lexical Handler}
4264
\label{ScriptsManagerLH}
4267
The lexical handler sends its strings to the content hadler.
4272
\OutputCodE\<ScriptsManagerLH.java\>
4275
\AddFile{ScriptsManagerLH.java}{xtpipes\Slash util}
4279
\<ScriptsManagerLH.java\><<<
4281
package xtpipes.util;
4282
import org.xml.sax.ext.LexicalHandler;
4283
// import org.xml.sax.ContentHandler;
4284
import java.io.PrintWriter;
4285
public class ScriptsManagerLH implements LexicalHandler {
4286
ScriptsManager contentHandler;
4288
public ScriptsManagerLH( ScriptsManager contentHandler,
4289
PrintWriter log, boolean trace ){
4290
this.contentHandler = contentHandler;
4291
this.log = (log==null)? new PrintWriter( System.err ) : log;
4293
public void comment(char[] ch, int start, int length){
4294
if( contentHandler.inBody ){
4295
String s = new String(ch, start, length);
4296
contentHandler.add( "<!--" + s + "\n-->");
4298
public void startEntity(String x){}
4299
public void endEntity(String x){}
4300
public void startCDATA(){}
4301
public void endCDATA(){}
4302
public void startDTD(String x, String y, String z){}
4303
public void endDTD(){}
4309
The line breaks in the comments are to avoid sequences of comments
4310
loosing their intermediate line breaks and as a result causing
4311
overflow of buffers.
4313
\item The comments in the preamble are included through the
4314
preamble pattribute of xtpipes.
2496
4327
%%%%%%%%%%%%%%%%%%%%%%%
2497
4328
\begin{thebibliography}{10}