📄 template.java
字号:
package MyNa.xml;
import MyNa.utils.*;
import java.io.*;
import java.util.*;
import java.sql.SQLException;
import org.w3c.dom.Node;
public class Template {
// handles an xml template defined according to template.dtd;
// output to a Writer. (This will sometimes be a StringWriter
// in order to use the template to define Env entries.)
// We start with an Env, which may or may not contain a
// DBHandler to connect us with a database. If there is no
// DBHandler, there are no dbOperation attributes. The Env
// may be generated by a RowSeq in which case
// substrow, substerr and substrowlist are legitimate;
// <substrowlist enumerateThrough="StrSeq" name="FieldName">
// may also be used to generate items from StrSeqs in an Env.
// in general, use this by identifying the top <template>
// node nd, the output out
Logger lg;
Writer out;
Env defs;
RowSeq rows;
int[]index;
int curIndex;
boolean substFailure;
public Template(){
lg=new Logger();
out=new PrintWriter(System.out);
defs=new Env(); rows=null;
index=new int[20];curIndex=-1;
substFailure=false;
lg.logIt("template default initialization");
}
public void setOut(Writer o){out=o;}
public void setDefs(Env e){defs=e;}
public void setRows(RowSeq re){
rows=re;
defs=re.getRow();
}
public Template(Env e,Writer o){
lg=new Logger();
out=o;defs=e; rows=null;
index=new int[20];curIndex=-1;
substFailure=false;
lg.logIt("template Env+Writer initialization");
}
public Template(RowSeq e,Writer o){
lg=new Logger();
rows=e;out=o;defs=e.getRow();
index=new int[20];curIndex=-1;
substFailure=false;
lg.logIt("template RowSeq+Writer initialization");
}
// these are the seven tagnames we use
static String templateN="template"; // only at root
static String textN="text";
static String substN="subst";
static String setdefN="setdef";
static String substrowN="substrow";
static String substerrN="substerr";
static String substrowlistN="substrowlist";
// the four attrs used are name,num,dbOperation, and enumerateThrough;
static String nameAttr="name";
static String numAttr="num";
static String dbOperationAttr="dbOperation";
static String enumerateThroughAttr="enumerateThrough";
// enumerateThrough has the two possible values ResultSet and StrSeq
static String resultsetAttrVal="ResultSet";
static String strseqAttrVal="StrSeq";
// given a node, we can choose what to do based on its name.
public void chooseRule(Node theNode,Writer out) throws TemplateException{
lg.logIt("choosing rule");
String tag=theNode.getNodeName();
lg.logIt("tag="+tag);
if(textN.equals(tag))doText(theNode,out);
else if(substN.equals(tag))doSubst(theNode,out);
else if(setdefN.equals(tag))doSetdef(theNode,out);
else if(substrowN.equals(tag))doSubstrow(theNode,out);
else if(substerrN.equals(tag))doSubsterr(theNode,out);
else if(substrowlistN.equals(tag))doSubstrowlist(theNode,out);
else if(templateN.equals(tag))doTemplate(theNode,out);
else throw new TemplateException("invalid tag "+tag+" in template DTD");
}
public void chooseRule(Node theNode)throws TemplateException{
chooseRule(theNode,out);
}
// after we process a node, we do its children.
public void doChildren(Node theNode,Writer out)
throws TemplateException{
lg.logIt("doChildren");
Node child=theNode.getFirstChild();
while(child!=null){
doDBOperation(child);
chooseRule(child,out);
child=child.getNextSibling();
}
}
// we can extract any of the four attributes; "num" is numeric,
// with default 0;
// and "enumerateThrough" has default value "ResultSet".
public String getNameAttr(Node theNode){
Node attr=theNode.getAttributes().getNamedItem(nameAttr);
String R=(attr==null)?null:attr.getNodeValue();
return R;
}
public String getdbOperationAttr(Node theNode){
Node attr=theNode.getAttributes().getNamedItem(dbOperationAttr);
String R=(attr==null)?null:attr.getNodeValue();
return R;
}
public int getNumAttr(Node theNode){
Node attr=theNode.getAttributes().getNamedItem(numAttr);
String R=(attr==null)?null:attr.getNodeValue();
if(null==R)return 0;
int n=Integer.parseInt(R);
if(n<0)return index[curIndex]; // -1 means use current index
return n;
}
public String getEnumerateThroughAttr(Node theNode){
Node attr=theNode.getAttributes().getNamedItem(enumerateThroughAttr);
String R=(attr==null)?null:attr.getNodeValue();
if(null==R)return resultsetAttrVal;
return R;
}
public String getTextNodeValue(Node textNode){
String S=textNode.getNodeValue();
if(S==null)S="";
Node C=textNode.getFirstChild();
while(C!=null){String cV=C.getNodeValue();
if(cV!=null)S+=cV;
C=C.getNextSibling();
}
return S;
}
public void doText(Node theNode,Writer out)
throws TemplateException{ // no children
lg.logIt("doText");
try{
String S=getTextNodeValue(theNode);
lg.logIt("text value=["+S+"]");
out.write(S);
}
catch(IOException e){
throw new TemplateException("I/O err in text: "+e);
}
}
public void doSubst(Node theNode,Writer out)
throws TemplateException{ // no children
lg.logIt("doSubst");
String key=getTextNodeValue(theNode);
lg.logIt("subst key="+key);
if(key==null)return;
int n=getNumAttr(theNode);
try{String val;
if(n==0)val=(defs.getStr(key));
else {
String[] A=defs.getStrSeq(key);
if(A==null || A.length==0 || A.length<n) return;
val=(A[n-1]);
}
lg.logIt("subst val="+val);
if(val!=null)out.write(val);
}catch(IOException e){
throw new TemplateException("I/O err in subst: "+e);
}
}
public void doSetdef(Node theNode,Writer out) // bypass out
throws TemplateException{
lg.logIt("doSetdef");
StringWriter sW=new StringWriter();
String key=getNameAttr(theNode);
if(key==null)throw new TemplateException("No Name on setDef node");
doChildren(theNode,sW);
int n=getNumAttr(theNode);
if(n==0)defs.put(key,sW.toString());
else {
String[] A=defs.getStrSeq(key);
if(A==null || A.length==0 || A.length<n)
throw new IndexOutOfBoundsException("invalid index "+n+"on key "+key+
"with value ["+defs.getStr(key)+"]");
A[n-1]=sW.toString();
defs.put(key,A); // in case it wasn't really a StrSeq before.
}
}
public void doSubstrow(Node theNode,Writer out)
throws TemplateException{
lg.logIt("doSubstrow");
if(substFailure || null==rows ||
!rows.next())
{substFailure=true; return;}
defs=rows.getRow();
doChildren(theNode,out);
}
public void doSubsterr(Node theNode,Writer out)
throws TemplateException{
lg.logIt("doSubsterr");
if(substFailure)doChildren(theNode,out);
}
public void doSubstrowlist(Node theNode,Writer out)
throws TemplateException{
lg.logIt("doSubstrowlist");
String enumType=getEnumerateThroughAttr(theNode);
if(strseqAttrVal.equals(enumType))
doEnumThroughStrSeq(theNode,out);
else if(substFailure || null==rows) return;
else {
while(rows.next()){
defs=rows.getRow();
doChildren(theNode,out);
}
}
}
public void doEnumThroughStrSeq(Node theNode,Writer out)
throws TemplateException{
lg.logIt("doEnumThroughStrSeq");
String ssName=getNameAttr(theNode);
lg.logIt("got ssname="+ssName);
if(ssName==null)
throw new TemplateException("no name for strseq enumthrough");
String[]ssVal=defs.getStrSeq(ssName);
if(ssVal==null)
throw new TemplateException("no val for "+ssName+" in enumthrough");
lg.logIt("got ssval=["+Misc.stringArrayJoin(ssVal,",")+"]");
curIndex++;
lg.logIt("curIndex="+curIndex);
if(index.length<=curIndex)
throw new TemplateException("stack overflow in enumthrough at "+ssName);
for(index[curIndex]=1;index[curIndex]<=ssVal.length;index[curIndex]++)
doChildren(theNode,out);
}
public void doTemplate(Node theNode,Writer out) // set up root
throws TemplateException{
lg.logIt("doTemplate");
doDBOperation(theNode);
lg.logIt("did dboperation");
doChildren(theNode,out);
}
public void doDBOperation(Node theNode)throws TemplateException{
String theOp=getdbOperationAttr(theNode);
lg.logIt("doDBOp "+theOp);
if(theOp==null)return;
defs.put(dbOperationAttr,theOp);
DBHandler theDBHandler=(DBHandler)defs.get("dbHandler");
if(theDBHandler==null)
throw new TemplateException("no dbhandler for op "+theOp);
try{
setRows(theDBHandler.getQueryRows(defs));
}catch(SQLException ex){
throw new TemplateException("dbHandler for op "+theOp+
"failed with SQLException "+ex);
}
}
}
/*
<!ELEMENT template (text | subst | substrow | substerr | substrowlist | setdef)*>
<!ELEMENT text (#PCDATA)>
<!ELEMENT subst (#PCDATA)>
<!ATTLIST subst
name CDATA #IMPLIED
num CDATA #IMPLIED
dbOperation CDATA #IMPLIED
>
<!ELEMENT setdef (#PCDATA)>
<!ATTLIST setdef
name CDATA #IMPLIED
num CDATA #IMPLIED
dbOperation CDATA #IMPLIED
>
<!ELEMENT subst (#PCDATA)>
<!ATTLIST subst
name CDATA #IMPLIED
num CDATA #IMPLIED
dbOperation CDATA #IMPLIED
>
<!ELEMENT substrow (text | subst | substrow | substerr | substrowlist)*>
<!ATTLIST substrow
name CDATA #IMPLIED
num CDATA #IMPLIED
dbOperation CDATA #IMPLIED
>
<!ELEMENT substerr (text | subst | substrow | substerr | substrowlist)*>
<!ATTLIST substerr
name CDATA #IMPLIED
num CDATA #IMPLIED
dbOperation CDATA #IMPLIED
>
<!ELEMENT substrowlist (text | subst | substrow | substerr | substrowlist)*>
<!ATTLIST substrowlist
name CDATA #IMPLIED
num CDATA #IMPLIED
dbOperation CDATA #IMPLIED
enumerateThrough CDATA #IMPLIED
>
<?xml version="1.0"?>
<!DOCTYPE template SYSTEM "template.dtd">
<myna:template>
<myna:text>
<?xml version="1.0"?>
<!DOCTYPE dbdata SYSTEM "dbdata.dtd">
<dbdata>
</myna:text>
<!-- up to here is just echoed, defines
<?xml version="1.0"?>
<!DOCTYPE dbdata SYSTEM "dbdata.dtd">
<dbdata>
-->
<myna:text>
<jdbc-info driver="</myna:text>
<myna:subst>theDBDriver</myna:subst>
<myna:text>" db_url="</myna:text>
<myna:subst>theDBURL</myna:subst>
<myna:text>" /></myna:text>
<!-- we have now sent the jdbc-info tag with substitutions -->
<myna:text>
<user-info>
<uname>
</myna:text>
<myna:subst>theUserName</myna:subst>
<myna:text>
</uname>
<upass>
</myna:text>
<myna:subst>theUserPassword</myna:subst>
<myna:text>
</upass>
</user-info>
</myna:text>
<!-- we have now sent the user-info tag with substitutions -->
<myna:text><table name="</myna:text>
<myna:subst num="1">Parameter</myna:subst>
<!-- that was Parameter[1], the table name, e.g.PresBirthday -->
<myna:text>
<headers>
</myna:text>
<myna:substrowlist enumerateThrough="StrSeq" StrSeq="FieldName">
<myna:text><header name="</myna:text>
<myna:subst num="-1">FieldName</myna:subst>
<myna:text>" fieldType="</myna:text>
<myna:subst num="-1">FieldType</myna:subst>
<myna:text>" /></myna:text>
</myna:substrowlist>
<myna:text>
</headers>
</myna:text>
<!-- and now we have sent the headers block, enumerating through
the FieldName strseq rather than through a rowenumeration, using
"-1" as a current-index indicator
-->
<myna:substrowlist> <!-- default enumerateThrough="resultSet" -->
<myna:text>
<row>
</myna:text>
<myna:substrowlist enumerateThrough="StrSeq" name="FieldName">
<myna:text><field name="</myna:text>
<myna:subst num="-1">FieldName</myna:subst>
<myna:text>"></myna:text>
<myna:subst num="-1">FieldValue</myna:subst>
</myna:substrowlist>
<myna:text>
</row>
</myna:text>
</myna:substrowlist>
<!-- we have now sent all the rows of the table -->
<myna:text>
</table>
</dbdata>
</myna:text>
</myna:template>
*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -