如何方便地操纵XML中的数据(JAVA代码具体实现)

/******************************************
* 程序编写: 陈林茂
* 编写日期: 2003-03-16
* 联系作者: linmaochen@sohu.com
*******************************************/

众所周知,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之中去.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值