/****************************************** * 程序编写: 陈林茂 * 编写日期: 2003-03-16 * 联系作者: [email protected] *******************************************/ 
众所周知,XML在现在的WEB应用程序中已非常炙手,但在程序中,我们如何很好的控制 
XML中的数据,同时如何组合您的XML数据,确是一个比较麻烦的问题,下面的例子中我 
将将我的一些解决办法介绍给大家: 
    1。首先,请大家看清下面的两个XML文件: 
   STRUCT.XML 为数据信息的具体结构描述; 
   Employees.xml : 则为具体的XML数据信息. 
下面为具体的XML文本内容:    struct.xml: 
<?xml version="1.0"?> <Fieldset>          <Field>        <FieldName>EmpNo</FieldName>        <FieldType>1</FieldType>        <FieldSize>4</FieldSize>   </Field>   <Field>        <FieldName>FirstName</FieldName>        <FieldType>1</FieldType>        <FieldSize>8</FieldSize>   </Field>   <Field>        <FieldName>LastName</FieldName>        <FieldType>1</FieldType>        <FieldSize>8</FieldSize>   </Field>   <Field>        <FieldName>PhoneExt</FieldName>        <FieldType>1</FieldType>        <FieldSize>20</FieldSize>   </Field>   <Field>        <FieldName>HireDate</FieldName>        <FieldType>3</FieldType>        <FieldSize>10</FieldSize>   </Field>   <Field>        <FieldName>DeptNo</FieldName>        <FieldType>1</FieldType>        <FieldSize>10</FieldSize>   </Field>   <Field>        <FieldName>JobCode</FieldName>        <FieldType>1</FieldType>        <FieldSize>10</FieldSize>   </Field>   <Field>        <FieldName>JobGrade</FieldName>        <FieldType>1</FieldType>        <FieldSize>10</FieldSize>   </Field>    <Field>        <FieldName>JobCountry</FieldName>        <FieldType>1</FieldType>        <FieldSize>20</FieldSize>   </Field>    <Field>        <FieldName>Salary</FieldName>        <FieldType>4</FieldType>        <FieldSize>20</FieldSize>   </Field>    <Field>        <FieldName>FullName</FieldName>        <FieldType>1</FieldType>        <FieldSize>30</FieldSize>   </Field> </Fieldset> ----------------------------------------------------------------------------------- Employees.xml 
<?xml version="1.0"?> <RecordSet>  <Record>   <EmpNo>2</EmpNo>   <FirstName>Robert</FirstName>   <LastName>Nelson</LastName>   <PhoneExt>250</PhoneExt>   <HireDate>1988-12-28</HireDate>   <DeptNo>600</DeptNo>   <JobCode>VP</JobCode>   <JobGrade>2</JobGrade>   <JobCountry>USA</JobCountry>   <Salary>105900.000000</Salary>   <FullName>Nelson, Robert</FullName>  </Record>  <Record>   <EmpNo>4</EmpNo>   <FirstName>Bruce</FirstName>   <LastName>Young</LastName>   <PhoneExt>233</PhoneExt>   <HireDate>1988-12-28</HireDate>   <DeptNo>621</DeptNo>   <JobCode>Eng</JobCode>   <JobGrade>2</JobGrade>   <JobCountry>USA</JobCountry>   <Salary>97500.000000</Salary>   <FullName>Young, Bruce</FullName>  </Record>  <Record>   <EmpNo>5</EmpNo>   <FirstName>Kim</FirstName>   <LastName>Lambert</LastName>   <PhoneExt>22</PhoneExt>   <HireDate>1989-02-06</HireDate>   <DeptNo>130</DeptNo>   <JobCode>Eng</JobCode>   <JobGrade>2</JobGrade>   <JobCountry>USA</JobCountry>   <Salary>102750.000000</Salary>   <FullName>Lambert, Kim</FullName>  </Record> </RecordSet> 
 2.为了很好的并且很直观的操纵XML的数据,我们将模拟一个类似于DELPHI中的QUERY 一样的组件,由于篇幅, 这里只提供它的简单实现: 它将包括三个基本的JAVA 类: XFIELD.JAVA  单个字段信息的描述类; XFIELDS.JAVA 单条记录信息的描述类; XQUERY.JAVA  类似于QUERY 一样的查询类的控件.下面为三个类具体实现的源代码: 
/**  * <p>Title: 字段单元</p>  * <p>Description: 内存记录中字段信息描述</p>  * <p>Copyright: Copyright (c) 2002</p>  * <p>Company: </p>  * @author 陈林茂 2003-03-12  * @version 1.0  */ 
import java.lang.*; import java.lang.Double; 
/*  *  描述内存记录中的字段信息  */ 
/******************************************************* *  log: *  2003-03-12 : add XField ********************************************************/ 
public class XField { 
/*  * 字段类型说明:  *   ftInteger : 整数字段  *   ftString  : 字符串字段  *   ftDate    : 日期型字段  *   ftFloat   : 浮点型字段信息 */ private static int ftString = 1; private static int ftInteger = 2; private static int ftDate = 3; private static int ftFloat = 4; 
/**************************************/   private String FieldName;   private int    FieldType;   private String FieldValue;   private int    FieldSize = 0; 
  public XField() {   } 
  public XField(String fldName){     FieldName = fldName;   } 
  public XField(String fldName,int fldType){     FieldName = fldName;     FieldType = fldType;   } 
  public XField(String fldName,int  fldType,String fldValue){     FieldName = fldName;     FieldType = fldType;     FieldValue = fldValue;   } 
  //获取字段的名称   public String getFieldName(){     return this.FieldName ;   } 
  //获取字段的类别   public int getFieldType(){     return FieldType;   } 
  //设置字段的类别   public void setFieldType(int sFieldType){     this.FieldType = sFieldType ;   } 
  //设置字段的长度信息   public void setFieldSize(int sSize){     this.FieldSize = sSize ;   } 
  //获取当前字段的整型值   public int getAsInteger(){      if(IsInteger(FieldValue))        return Integer.parseInt(FieldValue);      return 0;   } 
  //获取当前字段的字符串值   public String getAsString(){ 
    return FieldValue;   } 
  //获取当前字段的浮点型值   public double getAsFloat(){     if(IsFloat(FieldValue)){        return Double.parseDouble(FieldValue);     }     return 0.0;   } 
  //设置字段的值   public void setFieldValue(String sFldValue){      this.FieldValue = sFldValue;   } 
  /*   *  判断一字段值是否为整数   */   private boolean IsInteger(String numStr){     int i=0;     for(i = 1;i < numStr.length(); i++){ 
      if((numStr.charAt(i) <='0') || (numStr.charAt(i) >= '9' )){            return false; 
      }     }     return true;   } 
  /*   *  判断一字段值是否为浮点数   */   private boolean IsFloat(String numStr){     int i=0;     for(i = 1;i < numStr.length(); i++){       if (numStr.charAt(i) != '.'){         if((numStr.charAt(i) <='0') || (numStr.charAt(i) >= '9' )){            return false;         }       }     }     return true;   } 
  /*   *  判断一字段值是否为日期型   */   private boolean IsDateTime(String dateStr){     //to do 
     return true;   } 
 } 
/**  * <p>Title: 内存单个记录信息类</p>  * <p>Description: 内存记录单个记录信息描述</p>  * <p>Copyright: Copyright (c) 2002</p>  * <p>Company: </p>  * @author 陈林茂  2003-03-13  * @version 1.0  */ 
import java.util.*; import java.lang.*; import excelsample.XField; 
/* *  XFields 类是将一些字段信息组合在一起, *                       从而组合成一个单条记录信息 *  它提供如下的功能: *  1: 查找某一个字段信息 *  2: 重新设置某个字段的值 */ 
public class XFields { 
//字段信息容器   private Vector vector = new Vector(100); 
  public XFields() {   } 
  //添加一字段信息   public void AddXField(XField sFld){     vector.add(sFld);   } 
  //移去一字段信息   public void RemoveXField(XField sFld){     if(vector.size()>0)       vector.remove(sFld);   } 
  //返回记录中字段的个数   public int getCount(){     return vector.size() ;   } 
  //根据名称获取某个字段信息   public XField getFieldByname(String sFldName){     int i;     int pos ;     XField xfield;     for(i=0; i<vector.size(); i++){       xfield = (XField)(vector.elementAt(i));       System.out.println("field name is :"+xfield.getFieldName());       pos =xfield.getFieldName().toUpperCase().indexOf(sFldName.toUpperCase());       if(pos >= 0)       {         return xfield;       } 
    }     return null;   } 
  //根据序号获取某个字段信息   public XField getField(int Index){     if(vector.size() > Index)       return (XField)(vector.elementAt(Index));     return null;   } 
  //复制某一个字段信息   public XField CopyField(int index){     XField sfield;     if(this.vector.size() > index){ 
       sfield =(XField)(vector.elementAt(index));        XField xfield =new XField(sfield.getFieldName(),                                  sfield.getFieldType(),                                  sfield.getAsString()); 
       return xfield;     } 
    return null;   } 
 } 
 /**  * <p>Title: 内存记录集</p>  * <p>Description: 将XML文件中提供的记录信息存放到内存中</p>  * <p>Copyright: Copyright (c) 2002</p>  * <p>Company: </p>  * @author 陈林茂 2003-03-15  * @version 1.0  */ 
/*  *  类的名称:XQuery  *  说明:  此类将模拟一个类似DELPHI QUERY 的结构信息;  *         1。 它提供记录的查找,移到第一条记录,移到下一条记录等操作;  *         2。 它同时包含结构及数据信息  *         3。 利用它可以方便地对内存中的数据进行检索  */ 
import java.lang.*; import java.util.*; 
public class XQuery { 
//内存记录容器   private Vector vector = new Vector(100); 
//内存记录的结构信息   private XFields Struct = null; 
//是否到记录的结尾   private boolean RecEof = true; 
//当前操作的记录   private XFields CurrXFields = null; 
//当前的记录编号   private int RecNo = 0; 
  public XQuery() { 
  } 
  //设置内存记录的结构信息   public void setSturcture(XFields sStruct){     this.Struct = sStruct;   } 
  //添加一记录信息   public void AddRecord(XFields xfields){     vector.add(xfields);   } 
  //移走一记录信息   public void RemoveRecord(XFields xfields){     if(vector.size() > 0 )       vector.remove(xfields);   } 
  //获取当前记录集的记录总数   public int getRecordCount(){     return vector.size();   } 
/*  *  记录集的相关操作函数   */ 
  //移到第一条记录   public void First(){     if(vector.size()<=0){       this.RecEof = true;       return ;     } 
    CurrXFields = (XFields)(vector.elementAt(0));     this.RecEof = false;     this.RecNo = 0;   } 
 //移到下一条记录  public void Next(){    if(vector.size() == (this.RecNo+1)){      this.RecEof = true;      this.CurrXFields = null;      return ;     } 
    this.RecNo = this.RecNo + 1;     this.CurrXFields = (XFields)(vector.elementAt(this.RecNo));     this.RecEof =false;  } 
 //新增一空白记录信息  public void insertRecord(){    int i=0;    XFields xfields = new XFields(); 
   for(i=0;i<this.Struct.getCount();i++){      xfields.AddXField(this.Struct.CopyField(i));    }    this.vector.add(xfields);    this.RecNo = this.vector.size();    this.CurrXFields = xfields;    System.out.println("insert a record!");  } 
 //获取记录集中的字段个数  public int getFieldsCount(){    return this.Struct.getCount() ;  } 
 //返回记录集的当前记录  public XFields RecordSet(){    return this.CurrXFields ;  } 
 //判断记录集是否到结尾  public boolean Eof(){    return this.RecEof ;  } 
} 
 3.最后,就是告诉大家如何如何将XML中的数据读取出来,并放到XQUERY类中去,请看具体的实现: 
(1) 建立一个解析XML文件的类(详见JBUILDER 中自带的示例): 
import java.io.IOException; import org.xml.sax.*; import org.xml.sax.helpers.*; import org.apache.xerces.parsers.SAXParser; 
public class xmlParser  extends DefaultHandler{ 
  private static int INDENT = 4;   private static String attList = ""; 
  //记录表信息   public static XQuery query =new XQuery(); 
  //记录的结构信息   public XFields xfields=new XFields(); 
  //临时的字段信息   private XField xfield = null;   private String elementName = ""; 
   /*解析行为:    *   0: 解析XML文件中的信息为记录表的结构定义信息    *   1: 解析XML文件中的信息为记录表的具体的记录信息   */   private static int parseMode  =0;      private int idx = 0; 
  public void characters(char[] ch, int start, int length) throws SAXException {     String s = new String(ch, start, length);     if (ch[0] == '\n')       return;     System.out.println(getIndent() + " Value: " + s);     if(this.parseMode == 0){         if(this.elementName.indexOf("FieldName") >= 0) {           this.xfield = new XField(s);           System.out.println("Fieldname is :"+this.xfield.getFieldName());         } 
        if(this.elementName.indexOf("FieldType") >= 0){           if(this.xfield != null) {             try{               this.xfield.setFieldType(Integer.parseInt(s));               System.out.println("Fieldtype is:"+this.xfield.getFieldType());             }catch(Exception e){               e.printStackTrace();             }           } 
        } 
        if(this.elementName.indexOf("FieldSize") >= 0) {          if(this.xfield != null){            this.xfield.setFieldSize(Integer.parseInt(s)) ;            //添加一字段定义            this.xfields.AddXField(this.xfield);            System.out.println("record fields count is :" +this.xfields.getCount());           } 
        }     } 
    //     if(this.parseMode == 1) {       this.query.RecordSet().getFieldByname(this.elementName).setFieldValue(s);     } 
  }   public void endDocument() throws SAXException {     idx -= INDENT;     System.out.println(getIndent() + "end document");     System.out.println("...PARSING ends");     if(this.parseMode ==0)       this.query.setSturcture(this.xfields); 
  }   public void endElement(String uri, String localName, String qName) throws SAXException {     if (!attList.equals(""))       System.out.println(getIndent() + " Attributes: " + attList);     attList = "";     System.out.println(getIndent() + "end document");     idx -= INDENT;     System.out.println("the idx is :"+String.valueOf(idx));   }   public void startDocument() throws SAXException {     idx = 0;     idx += INDENT;     System.out.println("PARSING begins...");     System.out.println(getIndent() + "start document: "); 
  }   public void startElement(String uri, String localName, String qName,       Attributes attributes) throws SAXException {     idx += INDENT;     System.out.println('\n' + getIndent() + "start element: " + localName);     if (attributes.getLength() > 0) {       idx += INDENT;       for (int i = 0; i < attributes.getLength(); i++) {         attList = attList + attributes.getLocalName(i) + " = " + attributes.getValue(i);         if (i < (attributes.getLength() - 1))           attList = attList + ", ";       }       idx-= INDENT;     } 
    //判断是否为具体信息层     switch(this.parseMode){       case 0:             this.elementName = localName;             break;       case 1:             this.elementName = localName ;             if(this.elementName.indexOf("Record") >= 0)             if(idx == 12){               this.query.insertRecord();             }             break;     }   } 
  private String getIndent() {     StringBuffer sb = new StringBuffer();     for (int i = 0; i < idx; i++)       sb.append(" ");     return sb.toString();   } 
  public static void setQuery(XQuery sxquery){     query = sxquery;   } 
  //设置识别模式   public static void setMode(int sMode){     parseMode = sMode;   } 
  
} 
(2) 如何从XML中读取数据出来,并放到XQUERY去,并且自由的操作数据: /**  * <p>Title: Excel 文件信息写入类</p>  * <p>Description: 从一个XML文件中读取信息并写入到EXCEL文件中去</p>  * <p>Copyright: Copyright (c) 2002</p>  * <p>Company: </p>  * @author 陈林茂  2003-03-15  * @version 1.0  */ 
 /*  *  EXCEL记录写入演示  *  说明: 它主要分三个步骤:  *        1 读取STRUCT.XML文件,建立记录的字段结构信息;  *        2 读取RECORD.XML文件,获取具体的记录信息;  *        3 根据记录信息,将信息写入EXCEL文件  */ 
import java.io.File; import java.util.Date; import jxl.*;           //为EXCEL开源支持类库 import jxl.write.*; import java.io.IOException; import org.xml.sax.*; import org.xml.sax.helpers.*; import org.apache.xerces.parsers.SAXParser; 
 public class ExcelWrite { 
  public ExcelWrite() {   } 
  public static void main(String argv[]){ 
    if(argv.length != 3){       System.out.println("The Application argument is  "                           +"java ExcelWrite [struct.xml] [record.xml] [output.xls]");       System.exit(-1);     } 
    String StructFile = argv[0];     String RecordFile = argv[1];     String outputFile = argv[2];     int i = 0;     int m = 0;     XQuery sQuery =new XQuery(); 
    //建立内存记录信息     try { 
      //建立XML解析器        XMLReader parser = XMLReaderFactory.createXMLReader("org.apache.xerces.parsers.SAXParser");       xmlParser MySaxParserInstance = new xmlParser();       xmlParser.setQuery(sQuery);       parser.setContentHandler(MySaxParserInstance); 
      //解析记录集的结构信息       xmlParser.setMode(0);       parser.parse(StructFile);       System.out.println("the recordset fields count is :"+sQuery.getFieldsCount()); 
      //解析记录集的数据信息       xmlParser.setMode(1);       parser.parse(RecordFile);       System.out.println("the recordset record count is :"+sQuery.getRecordCount());     }     catch(IOException ioe) {       ioe.printStackTrace();     }     catch(SAXException saxe) {       saxe.printStackTrace();     } 
  
    //开始写入数据信息     try{         //建立一EXCEL文件写入类         WritableWorkbook workbook = Workbook.createWorkbook(new File(outputFile)); 
        //建立一工作薄         WritableSheet sheet = workbook.createSheet("员工记录数据", 0); 
        //建立每列的标题信息,具体操纵XQUERY中的数据         String s = "";         for(i = 0; i<sQuery.getFieldsCount(); i++){            s = sQuery.RecordSet().getField(i).getFieldName();            Label label = new Label(i, 0, s);            sheet.addCell(label);         }        //依次填入记录信息        m = 1 ;        sQuery.First();        while (sQuery.Eof()==false){          for(i=0; i<sQuery.getFieldsCount(); i++){            s = sQuery.RecordSet().getField(i).getAsString();            Label label = new Label(i, m, s);            sheet.addCell(label);          }          sQuery.Next();          m = m + 1;        } 
        //write the  data to File         workbook.write();         workbook.close(); 
    }catch(Exception e){       e.printStackTrace();     } 
  } } 
 4.总结:        首先建立记录的原始记录信息,分成两个XML文件,其中一个为数据具体的结构描述,    另外一个为具体的数据信息;    然后建立一个类似QUERY的类,可以方便地控制内存中的数据信息(包括记录的上移 下移等);        接下来,建立一XML的解析器,首先解析结构信息,并初始化具体的XQUERY类; 
   然后解析数据信息,将数据信息填充到XQUERY之中去.
   
 
  |