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

类别:Java 点击:0 评论:0 推荐:

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

本文地址:http://com.8s8s.com/it/it17908.htm