以文本方式查看主题

-  W3CHINA.ORG讨论区 - 语义网·描述逻辑·本体·RDF·OWL  (http://bbs.xml.org.cn/index.asp)
--  『 XML 与 数据库 』  (http://bbs.xml.org.cn/list.asp?boardid=17)
----  将关系型数据转化为XML形式  (http://bbs.xml.org.cn/dispbbs.asp?boardid=17&rootid=&id=37008)


--  作者:Prentice2000
--  发布时间:8/20/2006 2:29:00 PM

--  将关系型数据转化为XML形式
这个程序是根据文章《Querying XML Views of Relational Data》中所提到的Default XML View。 将指定数据库中所有基本表的关系数据输出到一个XML文档中,形成对原来关系数据的Default XML View。我使用Java+JDOM,使用的开发工具是NetBeans 5.0,大家在使用的时候仅需修改数据库名,以及登陆SQL Server 2000的用户名和密码

这是小弟发的第一个帖子请大家多多指教

package XMLViewGenerator;

import org.jdom.*;
import org.jdom.output.*;
import java.sql.*;
import java.io.*;
import java.util.*;

public class DefaultXMLView {
    
    private java.sql.Connection con = null;
    private final String url = "jdbc:microsoft:sqlserver://";
    private final String serverName= "localhost";
    private final String portNumber = "1433";
    private final String databaseName= "Collage";
    private final String userName = "sa";
    private final String password = "";
    private final String selectMethod = "cursor";
    
    /** Creates a new instance of DefaultXMLView */
    public DefaultXMLView() {
    }
    private String getConnectionUrl() {
        return url+serverName+":"+portNumber+";databaseName="+databaseName+";selectMethod="+selectMethod+";"; }
    private java.sql.Connection getConnection() {
        try{ Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver");
        con = java.sql.DriverManager.getConnection(getConnectionUrl(),userName,password);
        if(con!=null)
            System.out.println("成功连接数据库:"+databaseName); } catch(Exception e) {
                e.printStackTrace();
                System.out.println("跟踪在方法getConnection()出现的错误 : " + e.getMessage()); }
        return con; }
    
    private void closeConnection() {
        try {
            if(con!=null)
                con.close();
            con=null; } catch(Exception e){ e.printStackTrace(); } }
    public void GenerateDefaultView() {
        DatabaseMetaData dbMetaData = null;
        ResultSet TableSet = null;
        ResultSet rs = null;
        ResultSetMetaData rmd = null;
        String RootName=databaseName;
        Document XMLDocument = new Document(new Element(RootName)); //创建文档ROOT元素,ROOT元素名即为数据库名
        try{con= this.getConnection();
        if(con!=null) {
            dbMetaData=con.getMetaData();
            ArrayList TableList=new ArrayList();
            TableSet=dbMetaData.getTables(null,null,null,null);//查找出数据库中所有表的名称,包括系统表和用户表
            int ListSize;
            while(TableSet.next()) {
                TableList.add(TableSet.getString("TABLE_NAME"));//将表的名称存入到ArrayList中
            }
            ListSize=TableList.size();
            for(int i=0;i<ListSize;i++) {
                //从ArrayList中依次取出每个表,然后用SELECT查询表中的所有字段
                String SQLInstruction="SELECT * FROM"+" "+TableList.get(i).toString();
                PreparedStatement pstmt = con.prepareStatement(SQLInstruction,
                        ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
                //将表名作为元素名
                Element TableElement = new Element(TableList.get(i).toString());
                rs = pstmt.executeQuery();
                rmd = rs.getMetaData();//获取元数据,如属性名等
                int colcount = rmd.getColumnCount();//获取属性列的个数
                while (rs.next()) {
                    Element RowElement = new Element("ROW");
                    //每一个元组构成一个元素“ROW”,“ROW”中的子元素就是元组中的属性
                    //取出元组中的每一个属性名和属性的取值
                    //属性名作为元素名,属性的取值作为元素的内容
                    for (int j = 1; j <= colcount; j++) {
                        Element TempElement=new Element(rmd.getColumnName(j).toString());
                        TempElement.setText(rs.getString(j));
                        RowElement.addContent(TempElement);
                    }
                    //将每一个“ROW”元素作为以表名作为元素名元素的子元素
                    TableElement.addContent(RowElement);
                }
                //添加到根元素中
                XMLDocument.getRootElement().addContent(TableElement);
                pstmt.close();
            }
            //关闭数据库连接
            rs.close();
            rs = null;
            closeConnection();
            
            XMLOutputter outp = new XMLOutputter(Format.getPrettyFormat()); //格式化输出,产生缩进和换行
            
            Format format = outp.getFormat();
            format.setEncoding("GB2312"); //设置语言
            format.setExpandEmptyElements(true); //设置输出空元素格式
            outp.setFormat(format);
            
            outp.output(XMLDocument, new FileOutputStream(databaseName+".XML"));//输出XML文档
            System.out.print("XML 文档生成完毕!");
        } else
            System.out.println("错误: 没有可用的数据库连接!");} catch(Exception e){ e.printStackTrace(); }
    }
    public static void main(String[] args) throws Exception {
        DefaultXMLView myDefaultView = new DefaultXMLView();
        myDefaultView.GenerateDefaultView();
    }
    
}



--  作者:Prentice2000
--  发布时间:8/20/2006 2:37:00 PM

--  
还有一个程序就是将使用SELECT查询得到的结果转化为XML的形式,也是用Java+JDOM

package XMLViewGenerator;
import org.jdom.*;
import org.jdom.output.*;
import java.sql.*;
import java.io.*;

public class GenerateXMLView {
    
    /** Creates a new instance of GenerateXMLView */
    public GenerateXMLView() {
    }
    public static void main(String[] args) throws Exception {
        Class.forName("com.microsoft.jdbc.sqlserver.SQLServerDriver").newInstance();
        String url ="jdbc:microsoft:sqlserver://localhost:1433;databaseName=Collage;selectMethod=cursor;";
        Connection conn = DriverManager.getConnection(url, "SA", "");
        PreparedStatement pstmt = conn.prepareStatement(
                "select Student.Sno,Student.Sname,Course.Cno,Course.Cname,SC.Grade from Student,Course,SC where SC.Sno=Student.Sno and SC.Cno=Course.Cno order by Student.Sno",
                ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
        ResultSet rs = pstmt.executeQuery();
        ResultSetMetaData rmd = rs.getMetaData();
        Document document = new Document(new Element("ResultSet")); //创建文档ROOT元素
        int colcount = rmd.getColumnCount();
        while (rs.next()) {
            Element RowElement = new Element("ROW");
            
            for (int i = 1; i <= colcount; i++) {
                Element TempElement=new Element(rmd.getColumnName(i).toString());
                TempElement.setText(rs.getString(i));
                RowElement.addContent(TempElement);
            }
            document.getRootElement().addContent(RowElement);
        }
        rs.close();
        pstmt.close();
        conn.close();
        XMLOutputter outp = new XMLOutputter(Format.getPrettyFormat()); //格式华输出,产生缩进和换行
        
        Format format = outp.getFormat();
        format.setEncoding("GB2312"); //设置语言
        format.setExpandEmptyElements(true); //设置输出空元素为<sample></sample>格式
        outp.setFormat(format);
        
        outp.output(document, new FileOutputStream("ResultSet.xml")); //输出XML文档
        System.out.print("XML 文档生成完毕!");
    }
}

小弟的研究方向是XML与关系型数据库,给大家推荐几篇经典的文章,这些文章在Google都能搜索到,是关于基于DTD在关系型数据库中存储XML文档的方法,它不是采用边模型的映射方法,采用的是结点模型映射方法,都是这位作者Jayavel Shanmugasundaram的文章
《Efficiently Publishing Relational Data as XML Documents》
《Relational database for querying XML Documents:Limitations and opportunities》
《Querying XML Views of Relational Data》
小弟现在正在考虑在不使用DTD或XML Schema情况下如何使用结点模型映射方法在关系数据库中存储XML,感兴趣的兄弟可以一起切磋一下
用E-mail联系或QQ吧
我的QQ:149220966


--  作者:zxywgg
--  发布时间:10/3/2006 9:49:00 AM

--  
LZ辛苦啦,8错哦,偶参考参考,谢谢啦
--  作者:lusb77
--  发布时间:11/15/2006 5:55:00 PM

--  
辛苦了,参考参考
--  作者:wanghao19820725
--  发布时间:11/27/2006 10:43:00 AM

--  
你所发的正是我想要的...谢谢!!!
--  作者:wanghao19820725
--  发布时间:11/27/2006 10:45:00 AM

--  
你所发的正是我想要的...谢谢!!!
--  作者:mlcqhga
--  发布时间:11/28/2006 11:39:00 AM

--  
谢谢了,有很多问题还得向你请教。
--  作者:weatherhrr
--  发布时间:12/9/2006 8:47:00 PM

--  
lz?怎么我在自己的机器上运行这段代码,始终出来不了有具体数据的XML文档啊?最后就是一个根目录!具体细节,希望LZ可以跟进……
不胜感激!
--  作者:weatherhrr
--  发布时间:12/10/2006 10:08:00 PM

--  
啊!解决了,呵呵,明白了,懂了!
多谢LZ的宝贵资源!
--  作者:forgetall
--  发布时间:1/4/2007 1:49:00 PM

--  [原创]这里有一个更好的通用程序,很灵活
总是在网络上copy别人的源代码,今天我也贴出自己今天写的源码,相信这个程序会对大家在平时的工作中需要频繁从数据库中提取数据转化成xml文件会有帮助。
    最近公司项目中有一件事就是从数据库表中读出数据,然后转换成xml文件供客户端下载,由于数据库中表太多,不可能为单独的每个表都写一个转换程序。于是,经过分析,写了一个通用的用ResultSet对象转换成xml文件的程序。这样,只需把查询结果集(ResultSet对象)和要生成的xml文件的路径传入,然后自己指派属性名称、元素名称并与对应的查询结果集中的字段相对应,最后调用designOver()函数,就可以生成所期望的xml文件了。最后,给出了一个示例程序。
    我是用dom解析的,用纯java语言编写,程序包括5个类:CreateXmlFile.java、Disposal.java、SaveAttrName.java、SaveEleName.java、WriteXmlFile.java
真正与用户交互的只有CreateXmlFile.java,如果不想了解程序逻辑,可不用管其他类。代码讲解及示例如下:

文件 CreateXmlFile.java 内容:
package currencycreatexml;

import java.sql.*;


public class CreateXmlFile
{
private ResultSet rs;     //从下面的程序可以看出,此字段可省略,懒得改了,呵呵
private String url;       //从下面的程序可以看出,此字段可省略,懒得改了,呵呵
private Disposal disposal; //自定义的用来收集和处理数据的类
private String root;       //xml文件的根元素名称
private String rootchild;  //根结点的子结点的元素名称
/**
  * @param rs : 创建xml文件所需的查询结果集
  * @param url : 指定xml文件的生成路径(包括xml文件的文件名)
  */
public CreateXmlFile(ResultSet rs,String url)
{
  this.rs=rs;
  this.url=url;
  disposal=new Disposal();
  disposal.setResultSet(this.rs,this.url);
}
//设定xml文件的根元素名称
public void setRootElementName(String root,String rootchild)
{
  this.root=root;
  this.rootchild=rootchild;
  disposal.setRootName(this.root,this.rootchild);
}
//设置属性的名字和索引位置,位置从1开始
/**
  * @param namestring 指定属性的名称
  * @param index 指定此属性的值在查询结果集中第几个字段(字段从1开始索引)
  */
public void setAttributeName(String namestring,int index)
{
  disposal.collectData(namestring,index,"attribute");
}
//设置元素的名字和索引位置,位置从1开始
/**
  * @param namestring 指定元素的名称
  * @param index 指定此元素的值在查询结果集中的第几个字段(字段从1开始索引)
  */
public void setElementName(String namestring,int index)
{
  disposal.collectData(namestring,index,"element");
}
/**
* 调用此方法则立即开始创建xml文件,在属性与元素都已指派完毕后调用此方法
*/
public void designOver()
{
  disposal.startWrite();
}
}


文件 Disposal.java 内容:

package currencycreatexml;

import java.util.*;
import java.sql.*;

class Disposal
{
private ResultSet rs;
private String url;
private ArrayList attrilist=new ArrayList();  //用来存储属性名和字段索引的集合类
private ArrayList elelist=new ArrayList();    //用来存储元素名和字段索引的集合类
private String root;
private String rootchild;
public void setResultSet(ResultSet rs,String url)
{
  this.rs=rs;
  this.url=url;
}
public void setRootName(String root,String rootchild)
{
  this.root=root;
  this.rootchild=rootchild;
}
@SuppressWarnings("unchecked")
public void collectData(String namestring,int index,String type )
{
  if(type.equals("attribute"))
   attrilist.add(new SaveAttrName(namestring,index));
  else
   elelist.add(new SaveEleName(namestring,index));
   //System.out.println("else");
  //System.exit(0);
}
public void startWrite()
{
  new WriteXmlFile(attrilist,elelist,rs,url).create(root,rootchild);
}
}


文件 SaveAttrName.java 内容:

package currencycreatexml;

class SaveAttrName
{
private String attributename;
private int index;
public SaveAttrName(String attributename,int index)
{
  this.attributename=attributename;
  this.index=index;
}
public String getAttributeName()
{
  return attributename;
}
public int getIndex()
{
  return index;
}
}

文件 SaveEleName.java 内容:

package currencycreatexml;

class SaveEleName
{
private String elementname;
private int index;
public SaveEleName(String elementname,int index)
{
  this.elementname=elementname;
  this.index=index;
}
public String getElementName()
{
  return elementname;
}
public int getIndex()
{
  return index;
}
}

文件 WriteXmlFile.java 内容:

package currencycreatexml;

import java.io.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.Iterator;
import javax.xml.parsers.*;

import org.w3c.dom.*;               //使用dom解析
import org.apache.crimson.tree.*;  //写xml文件需要用到的jar包

class WriteXmlFile
{
   private ResultSet rs;
   private String url;
   private ArrayList attrilist;
   private ArrayList elelist;
   public WriteXmlFile(ArrayList attrilist,ArrayList elelist,ResultSet rs,String url)
   {
      this.attrilist=attrilist;
      this.elelist=elelist;
      this.rs=rs;
      this.url=url;
   }
   /**
    * @param root : xml文件的根元素名
    */
   public void create(String root,String rootchild)
   {
      DocumentBuilderFactory dbf=DocumentBuilderFactory.newInstance();
      Document doc=null;
      try
      {
         DocumentBuilder db = dbf.newDocumentBuilder();
         doc = db.newDocument();
      }
      catch (ParserConfigurationException e)
      {
         e.printStackTrace();
      }
      Element rootelement=doc.createElement(root);
      doc.appendChild(rootelement);
      Iterator attri=attrilist.iterator();
      Iterator ele=elelist.iterator();
      //System.out.println("iterator");
      try
      {
         while(rs.next())
         {
            Element rootchildelement=doc.createElement(rootchild);
            //System.out.println("while");
            while(attri.hasNext())
            {
               /**
               *  循环到属性集合中取元素名称,之后从查询结果集中取得数据,创建元素属性
               */
               SaveAttrName temp=(SaveAttrName)attri.next();
               rootchildelement.setAttribute(temp.getAttributeName(),rs.getString(temp.getIndex()).trim());
            }  
            rootelement.appendChild(rootchildelement);
            while(ele.hasNext())
            {
               /**
               *  循环到元素集合中取元素名称,之后从查询结果集中取得数据,创建结点
               */
               SaveEleName temp=(SaveEleName)ele.next();
               Element tempelement=doc.createElement(temp.getElementName());
               Text temptextelement=doc.createTextNode(rs.getString(temp.getIndex()).trim());
               tempelement.appendChild(temptextelement);
               rootchildelement.appendChild(tempelement);
            }
            attri=attrilist.iterator(); //重复循环到集合中取值,下同
            ele=elelist.iterator();
         }
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
      writeXml(doc);
   }
   private void writeXml(Document doc)
   {
      try
      {
         FileOutputStream outStream = new FileOutputStream(url);
         OutputStreamWriter outWriter = new OutputStreamWriter(outStream);
         ((XmlDocument)doc).write(outWriter, "GB2312");
         outWriter.close();
         outStream.close();
         System.out.print("\nWrite xmlfile successful!\n");
      }
      catch (Exception e)
      {
         e.printStackTrace();
      }
   }
}

讲解:
假设数据库中有一个表,表名为“CCNUstudents”,
表中有几条记录,现将它转换为xml文件,我转换的规则为将记录的关键字作为元素的属性,其它作为了结点。当然,你也可以以自己的规则将数据库中的任何字段设置为属性或元素。所有元素及属性的名称可以自定义,表中的内容为:

学号     姓名      学校         系别       家庭住址
20033274   邪    华中师范大学 信息管理系  湖北省监利县龚场镇
20043225  阿维   中南民族大学    经济系   湖北省监利县周老咀镇

假设关键字段为“学号”,则可将此表转换为一个xml文件:
示例代码如下:
文件 test.java 中测试函数的内容:

public static void main(String[] args) throws Exception
{
  SQLExecute conn=new SQLExecute();
  ResultSet rs=conn.sqlQuery("select * from CCNUstudents");
  CreateXmlFile create = new CreateXmlFile(rs,"demo.xml");
  create.setRootElementName("学生基本信息","学生");
  create.setAttributeName("学生学号",1);
  create.setElementName("学生的姓名",2);
  create.setElementName("所在学校",3);
  create.setElementName("所在系",4);
                  create.setElementName("住址",5);
  create.designOver();
}
函数setAttributeName(String,int)及setElementName(String,int)中的String用来指定元素名或是属性名,int型数字用来关联此元素或属性的值是从表中的第几个字段取出来的。程序运行结果后,就会在当前目录下生成一个名为“demo.xml”的xml文件,文件内容为:

<?xml version="1.0" encoding="GB2312"?>

<学生基本信息>

<学生 学生学号="20033274">
<学生的姓名>邪</学生的姓名>
<所在学校>华中师范大学</所在学校>
<所在系>信息管理</所在系>
<住址>湖北省监利县龚场镇</住址>
</学生>

<学生 学生学号="20043225">
<学生的姓名>阿维</学生的姓名>
<所在学校>中南民族大学</所在学校>
<所在系>经济系</所在系>
<住址>湖北省监利县周老咀镇</住址>
</学生>

</学生基本信息>

当然,如果数据表中有多个关键字,也可以在程序中指定多个属性。
至此,一个xml文件就产生了。当然,为求程序简便,关于xml文件中的命名空间、CDATA都没有作处理。希望可以起到抛砖引玉的作用。
程序流程及逻辑可以参看类中的注释~。
(-小邪(QQ:156411203,欢迎交流)-2006.7.21)。
最后补充一点,你并不需要为每一个查询结果集中的字段都指派相应的元素或属性名,而只需根据你自己的需要,为你想要储存到xml文件中的那些字段指派名称就可以了,最后,别忘记了调用designOver()函数,告诉程序表示已经指派完毕了!^_^


--  作者:tangling
--  发布时间:1/26/2007 9:37:00 PM

--  
不错!值得研究一下!
--  作者:xm1984
--  发布时间:3/7/2007 6:12:00 PM

--  
对于您真是没话说了,我还没懂xml与数据库的交互,我一定从您这开始学习,谢谢!
--  作者:lili91326
--  发布时间:3/14/2007 9:46:00 AM

--  
受益匪浅,收下了,谢谢楼主
--  作者:pingxingheidong
--  发布时间:4/11/2007 3:28:00 PM

--  
谢谢你啊!!
--  作者:zf1018
--  发布时间:4/16/2007 1:03:00 PM

--  
非常不错,谢谢了

--  作者:血色it浪漫
--  发布时间:4/18/2007 3:20:00 PM

--  
不知道在jbuilder里可以运行不?
--  作者:han_zw
--  发布时间:5/20/2007 11:48:00 PM

--  
好,从中获益不少!支持
--  作者:龙藤
--  发布时间:7/4/2007 10:19:00 PM

--  
谢谢楼主,谢谢10楼


W 3 C h i n a ( since 2003 ) 旗 下 站 点
苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
7,042.969ms