ResultSet转XML

一·、需求

一个功能类,能将一个给定的sql select语句的执行结果集按照一定格式生成xml文件

比如,一个sql语句"select * from star;"的执行结果是这样的:

---------------------------

name age gender

---------------------------

James 26 male

Bryant 33 male

要求生成后的xml的根节点名叫"star"且每条数据使用一个<row>标签来代表,就像下面的这样:

<?xml version="1.0" encoding="UTF-8" standalone="no" ?>

<star xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

<row>

<name>James</name>

<age>26</age>

<gender>male</gender>

</row>

<row>

<name>Bryant</name>

<age>33</age>

<gender>male</gender>

</row>

</star>

二、早期作法

早期分析这个需求的时候,很自然的将需求分成了两块功能来完成,一块用来生成xml,另一块用来将xml输出文件

1、生成xml:

生成xml的方式的总体思路是,首先通过JDBC连接执行sql得到结果集,然后遍历结果集将内容填充到一个

org.w3c.dom.Document对象,最后使用javax.xml.transform.Transformer将Document对象转换成xml。

@Component("xmlMaker") public class XmlMaker{ private static DataSource datasource; private static final String XSDNS="http://ww.w3.org/2001/XMLSchema"; private static final String ROW_ELEMENT_NAME="row"; private String content; @Resource(name="mydatasource") public void setDataSource(DataSource dataSource){ this.dataSource=datasource; } public String generateXML(String sql,String rootElementName){ Connection con = null; PreparedStatement ps = null; ResultSet rs = null; String result = null; try{ con = dataSource.getConnection(); // 创建一个可滚动的只读结果集,普通类型的结果集的游标无法自由上下移动 ps = con.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY); rs = ps.executeQuery(); result = makeXMLFromresultSet(rs,rootElementName); } catch(Exception e){ //todo }finally{ try{ if(null != rs){ rs.close(); } if(null != ps){ ps.close(); } if(null != con){ con.close(); } }catch(sqlException e){ //todo  } } return result; } private String makeXMLFromresultSet(ResultSet rs,String rootElementName) throws Exception{ Document doc = resultSet2Dom(rs,rootElementName); String ret = null; StringWriter sw = new StringWriter(); Transformer t = null; try{ TransformerFactory tf = TransformerFactory.newInstance(); t = tf.newTransformer(); t.setoutputProperty(OutputKeys.OMIT_XML_DECLaraTION,"no"); t.setoutputProperty(OutputKeys.METHOD,"xml");  t.setoutputProperty(OutputKeys.ENCODING,"UTF-8");
      t.setoutputProperty(OutputKeys.INDENT,"yes");
DOMSource domSource = new DOMSource(doc);
      StreamResult sr = new StreamResult(sw);
      transformer.transform(domSource,sr);
      content = sw.toString();
 }catch(Exception e){ //todo }finally{ doc = null; try{ sw.close(); }catch(IOException e){ } } return content; } private Document resultSet2Dom(ResultSet rs,String rootElementName){ Document myDocument = null; try{ myDocument = ((DocumentBuilderFactory.newInstance()).newDocumentBuilder()).newDocument(); }catch(ParserConfigurationException pce){ //todo } Element root = myDocument.createElement(rootElementName); root.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"); myDocument.appendChild(root); ResultSetMetaData rsmd = rs.getMetaData(); Element element,row; String value; if(rs.next()){ rs.prevIoUs();//使用rs.next()来判断结果集是否有至少一条数据,如果有就将游标退回初始位置准备开始遍历。 while(rs.isLast() == false){ rs.next(); row = myDocument.createElement(ROW_ELEMENT_NAME); root.appendChild(row); for(int i=1;i<=rsmd.getColumnCount();i++){ element = myDocument.createElement(rsmd.getColumnLabel(i).toLowerCase()); int columnType = rsmd.getColumnType();//此处得到列类型是方便对特殊类型数据的处理,比如当数据是浮点型时四舍五入。本例略 value = rs.getString(i); if(value == null){ element.setAttribute("xsi:nil","true"); }else{ element.appendChild(myDocument.createTextNode(value)); } row.appendChild(element); } } return myDocument; } }

2、将xml写成文件

public class FileMaker{
  public void static writeFile(String filePath,Sring fileName,String content){
    File fileDirectory = new File(filePath);
    File targetFile = new File(filePath + File.separator + fileName);
    if(!(fileDirectory.isDirectory())){
      fileDirectory.mkdirs();//如果传过来的文件路径不存在,就先创建这个路径
    }
    if(!(targetFile.isFile())){
      try{
        targetFile.createNewFile();//如果目标文件不存在就创建文件
      }catch(IOException e){
        //todo
      }
    }
    FileOutputStream fos = null;
    try{
      fos = new FileOutputStream(targetFile);
      org.apache.commons.io.IoUtils.write(content,fos,"UTF-8");
    }catch(IOException e){
      //todo
    }finally{
      IoUtils.closeQuietly(fos);
    }
  }
}

三、遇到问题

在数据量小时,这种做法能正常工作,但有一天别人在使用的时候系统卡死了,Debug后发现在结果集过大(当时有三百万条数据)时,内存溢出了。因为依照上面的做法,需要将一个有三百万条数据的结果集转成一个Dom对象放在内存中。于是我加大内存,终

于挨过了生成xml这个环节,得到了一个庞大的字符串content。但由于Dom对象的引用虽然被指向了null但它之前所占用的内存并不可能立即释放,所以在写文件时内存又不够了,又溢出。其实,加内存并不是解决问题的办法,因为数据量不固定,这终究是一

个不健壮的程序。

四、修改方案,解决问题

将结果集硬生生的打造成一个大Dom对象的方式已被证明不可行,我考虑在遍历结果集的同时边读边写文件

感谢 http://www.clipclip.org/wqmd/clips/detail/1204498 的作者。

使用SAX的方式在遍历结果集的同时生成xml文件

public void resultSet2XML(ResultSet rs,String rootElementName,String filePath) throws Exception{ SAXTransformerFactory fac = (SAXTransformerFactory)SAXTransfomerFactory.newInstance(); TransformerHandler handler = fac.newTransformerHandler(); Transformer transformer = handler.getTransformer(); Transformer.setoutputProperty(OutputKeys.OMIT_XML_DECLaraTION,"no"); Transformer.setoutputProperty(OutputKeys.METHOD,"xml"); Transformer.setoutputProperty(OutputKeys.ENCODING,"UTF-8"); Transformer.setoutputProperty(OutputKeys.INDENT,"yes"); Transformer.setoutputProperty(OutputKeys.STANDALONE,"no"); FileOutputStream fos = new FileOutputStream(filePath); Result resultxml = new StreamResult(fos); handler.setResult(resultxml); ResultSetMetaData rsmd = rs.getMetaData(); String value = ""; AttributeImpl rootElementAttribute = new AttributesImpl(); rootElementAttribute.addAttribute("","","xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"); handler.startDocument(); handler.startElement("",rootElementName,rootElementAttribute); if(rs.next()){ rs.prevIoUs(); while(rs.isLast() == false){ rs.next(); handler.startElement("",ROW_ELEMENT_NAME,null); for(int i=1;i<=rsmd.getColumnCount();i++){ int columnType = rsmd.getColumnType(); value = rs.getString(i); String columnName = rsmd.getColumnLabel(i).toLowerCase(); if(value == null){ AttributesImpl tempAttribute = new AttributesImpl(); tempAttribute.addAttribute("","xsi:nil","true"); handler.startElement("",columnName,tempAttribute); }else{ handler.startElement("",null); } handler.character(value.tochararray(),value.length()); handler.endElement("",ROW_ELEMENT_NAME); } handler.endElement("",rootElementName); handler.endDocument(); fos.close(); } } }

上面的方法执行完的同时,文件输出流fos也完整地结束了写文件的工作并关闭,从此,再大的结果集我们都不怕了。

BTW:XML的标签不能以数字开头,本例略去了对节点名是否合法的判断。

///////////////////////

众所周知XML已经成不同应用程序之间数据交换的事实上的标准。在实际工作中,我们经常需要把JDBC返回的结果集(ResultSet)转化为XML表达形式,便于把数据传送到其他的应用程序。这里提供一个简单的例子,它可以把ResultSet转化为XML格式的文本,并存放在字符串(String)作为返回结果。
这个程序通用之处在于它与选用的数据库结构无关。就是说,如果数据库结构发生了变化,本文提供的程序也可以正确运行。如果你有相同的需要,希望本文能给您一点帮助和启发。


Java代码
  1. import java.io.FileOutputStream;
  2. import java.sql.Connection;
  3. import java.sql.DriverManager;
  4. import java.sql.ResultSet;
  5. import java.sql.ResultSetMetaData;
  6. import java.sql.sqlException;
  7. import java.sql.Statement;
  8. public class ResultSetToXML {
  9. /**
  10. * @param ResultSet
  11. * rs输入的结果集
  12. * @return String 返回XML串
  13. * @exception sqlException
  14. */
  15. public String generateXML(final ResultSet rs) throws sqlException {
  16. final StringBuffer buffer = new StringBuffer(1024 * 4);
  17. if (rs == null)
  18. return "";
  19. buffer.append("<?xml version=\"1.0\" encoding=\"GB2312\"?>\n"); // XML的头部信息
  20. buffer.append("<ResultSet>\n");
  21. ResultSetMetaData rsmd = rs.getMetaData(); // 得到结果集的定义结构
  22. int colCount = rsmd.getColumnCount(); // 得到列的总数
  23. // 对放回的全部数据逐一处理
  24. for (int id = 1; rs.next(); id++) {
  25. // 格式为row id,col name,col context
  26. buffer.append("\t<row id=\"").append(id).append("\">\n");
  27. for (int i = 1; i <= colCount; i++) {
  28. String type = rsmd.getColumnTypeName(i); // 获取字段类型
  29. buffer.append("\t\t<col name=\"" + rsmd.getColumnName(i)
  30. + "\">");
  31. buffer.append(getValue(rs,i,type));
  32. buffer.append("</col>\n");
  33. }
  34. buffer.append("\t</row>\n");
  35. }
  36. buffer.append("</RowSet>");
  37. rs.close();
  38. return buffer.toString();
  39. }
  40. /**
  41. * This method gets the value of the specified column
  42. * 通用的读取结果集某一列的值并转化为String表达
  43. *
  44. * @param ResultSet
  45. * rs 输入的纪录集
  46. * @param int
  47. * colNum 第几列
  48. * @param int
  49. * type 数据类型
  50. */
  51. private String getValue(final ResultSet rs,int colNum,String type)
  52. throws sqlException {
  53. Object value = null;
  54. if (type.equals("nchar") || type.equals("nvarchar"))
  55. value = rs.getString(colNum);
  56. else
  57. value = rs.getobject(colNum);
  58. if (value != null)
  59. return value.toString().trim();
  60. return "null";
  61. }
  62. public static void main(String args[]) {
  63. ResultSet result;
  64. try {
  65. Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
  66. Connection con = DriverManager.getConnection("jdbc:odbc:MyDataSource","sa","123456");
  67. // 普通查询
  68. Statement stat = con.createStatement();
  69. result = stat.executeQuery("Select * from Orders");
  70. JDBCToXML obj = new JDBCToXML();
  71. String res = obj.generateXML(result);
  72. FileOutputStream fswriter = new FileOutputStream("result.xml",true);
  73. fswriter.write(res.getBytes());
  74. fswriter.close();
  75. con.close();
  76. } catch (Exception e) {
  77. System.out.println("Error" + e);
  78. }
  79. }
  80. }

//////////////////

2012-12-01 13:32

数据查询结果集ResultSet转成xml格式的文件和xml String的方法

1.将ResultSet转成xmL文件

public static Document todocument(ResultSet rs)
throws ParserConfigurationException,sqlException
{
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.newDocument();

Element results = doc.createElement("Results");
doc.appendChild(results);

ResultSetMetaData rsmd = rs.getMetaData();
int colCount = rsmd.getColumnCount();

while (rs.next())
{
Element row = doc.createElement("Row");
results.appendChild(row);

for (int i = 1; i <= colCount; i++)
{
String columnName = rsmd.getColumnName(i);
Object value = rs.getobject(i);

Element node = doc.createElement(columnName);
node.appendChild(doc.createTextNode(value==null ? "" :value.toString()));
row.appendChild(node);
}
}
return doc;
}
/**
* 序列化DOM为一个字符串
*
*/

public static String ConvertXMLToString(Document doc){
OutputFormat of = new OutputFormat(doc);
of.setIndenting(true);
StringWriter sw = new StringWriter();
XMLSerializer serializer = new XMLSerializer(sw,of);
try {
serializer.serialize(doc);
} catch (IOException e) {
e.printstacktrace();
}
return sw.toString();
}

//main interface

public String GetXMLString(String sqlsentance) {
dbconn();
ResultSet r1=dataset(sqlsentance);
try {
Document dcmt = todocument(r1);
str= ConvertXMLToString(dcmt);
// xmlstr = sayHello(str);
} catch (ParserConfigurationException e1) {
e1.printstacktrace();
} catch (sqlException e1) {
e1.printstacktrace();
}
dbclose();
return str;
}

2.将查询结果集ResultSet 转换成String类型的xml方法

public static String convertResultSetToXML(ResultSet rs){
StringBuffer sb = new StringBuffer();
try{
ResultSetMetaData rsmd = rs.getMetaData();
if (rsmd.getColumnCount()>=0){

///sb.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
///sb.append("<response>");

while(rs.next()){
sb.append("<row>\n");
for(int j=1;j<=rsmd.getColumnCount();j++){
sb.append("<" +rsmd.getColumnName(j).toLowerCase()+ ">")
.append( rs.getobject(j)==null?"":rs.getobject(j) )
.append("</" +rsmd.getColumnName(j).toLowerCase()+ ">\n");
}
sb.append("</row>\n");
}
///sb.append("</response>");
}

}catch(Exception e){
e.printstacktrace();
}
return sb.toString();
}

public String Getxmlstring(String sqlsentance){ dbconn(); ResultSet rs1=dataset(sqlsentance); String xmlstr = convertResultSetToXML(rs1); return xmlstr; }

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


php输出xml格式字符串
J2ME Mobile 3D入门教程系列文章之一
XML轻松学习手册
XML入门的常见问题(一)
XML入门的常见问题(三)
XML轻松学习手册(2)XML概念
xml文件介绍及使用
xml编程(一)-xml语法
XML文件结构和基本语法
第2章 包装类
XML入门的常见问题(二)
Java对象的强、软、弱和虚引用
JS解析XML文件和XML字符串详解
java中枚举的详细使用介绍
了解Xml格式
XML入门的常见问题(四)
深入SQLite多线程的使用总结详解
PlayFramework完整实现一个APP(一)
XML和YAML的使用方法
XML轻松学习总节篇