/****************************************** * 程序编写: 陈林茂 * 编写日期: 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之中去.

|