树型目录的XML实现(二)jsp+XML+js,跟CSDN的论坛列表相同?

本功能实现有些复杂,涉及的知识点:
*java的XML遍历——SAX实现
*java的XML更新——DOM实现
*HTML页面js的无刷新提交数据——XMLHTTP实现,需要MSXML2支持
*js的XML遍历——XMLDOM实现,需要Microsoft插件支持
*HTML及JSP页面让cache立即过期的代码实现
第三和第四点也是实现无刷新聊天室的核心技术!!!
总共包括四个文件:
tree2.htm——树型结构的客户端显示,用户的所有操作(打开、增加和删除节点)都从这个页面提交
tree2.xml——树型的数据和结构
tree2.jsp——XML树型结构的遍历
do_tree2.jsp——树型节点的增加与删除操作(测试用,如果只是显示树型,可以不要)
几点说明:
1、这个功能实现脱离了数据库DB,其数据来源是XML文件,tree2.xml文件的基本结构如下:
<?xml version="1.0" encoding="GB2312"?><!--XML的版本及编码方式申明-->
    <root><!--XML的根节点,是XML文件必须的,根树型结构的实现关系不大-->
        <xiruo parentid="0"><!--树型结构节点及父节点ID号-->
            <id>2</id><!--树型节点ID号-->
            <message>2</message><!--树型节点显示的信息-->
            <childcount>0</childcount><!--本节点所包含的子节点数目-->
        </xiruo>
    </root>
2、HTML及JSP页面让cache立即过期的代码实现
HTML:
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="1970-1-1 00:00:00">
JSP:
response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
3、方便起见,所有的代码都在JSP中实现,很多功能可以自己做成javabean
4、为了清楚说明引用类的完整路径,所有的类都以完整路径引用
5、本文的版权属于beyond_xiruo,如果需要转载请注名出处
6、希望本文对你的学习有帮助,如果有什么不明白的地方可以来信,我的技术邮箱[email protected]
********************
*         tree2.htm         *
********************
<title>用jsp+js+xml种树</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<META HTTP-EQUIV="pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache, must-revalidate">
<META HTTP-EQUIV="expires" CONTENT="1970-1-1 00:00:00"><!--HTML让页面立即过期的实现-->
<style><!--页面mouseover,mouseout,mousedown不同效果的样式单的定义-->
BODY
{
 font-family:宋体;
 cursor:default;
 font-size:9pt;
}

table
{
 font-family:宋体;
 cursor:default;
 font-size:9pt;
}

.container {
 position:relative;
 top:4px;
 padding:1px;
 padding-top:5px;
 width:13px;
 height:13px;
 border:solid 1px black;
 background-color:#ffffff;
 }

SPAN.clsCollapse
{
 top:3px;
 padding-left:1px;
 padding-top:26px;
 overflow:hidden;
 line-height:3px;
 font-size:13px;
}

SPAN.clsExpand
{
 padding-left:1px;
 overflow:hidden;
 line-height:3px;
 font-size:13px;
 padding-top:3px;
}

SPAN.clsLeaf
{
 top:0px;
 padding-left:3px;
 overflow:hidden;
 line-height:0px;
 font-size:11px;
 cursor:normal;
}

SPAN.clsLabel
{

 height:17px;
 overflow:hidden;
 padding-left:3px;
 padding-top:2px;
 border:1px solid #FFFFFF
}

SPAN.clsMouseOver
{
 position:relative;
 height:17px;
 overflow:hidden;
 padding-left:3px;
 padding-top:2px;
 background-color:#CCCCCC;
 border:1px solid #999999;
 cursor:hand;
}

SPAN.clsMouseOut
{
 position:relative;
 height:17px;
 overflow:hidden;
 padding-left:3px;
 padding-top:2px;
 background-color:#CCCCCC;
 border:1px solid #FFFFFF;
}

SPAN.clsMouseDown
{
 position:relative;
 height:17px;
 overflow:hidden;
 padding-left:3px;
 padding-top:2px;
 background-color:#999999;
 border:1px solid #999999;
}
SPAN.clsCurrentHasFocus
{
 position:relative;
 height:17px;
 overflow:hidden;
 padding-left:3px;
 padding-top:2px;
 background-color:#FFFFFF;
 border:1px solid #999999;
 cursor:hand;
}

SPAN.clsNotReady
{
 position:relative;
 height:17px;
 overflow:hidden;
 padding-left:3px;
 padding-top:2px;
 background-color:#CCCCCC;
 border:1px solid #FFFFFF;
}
DIV.focusColor {backgroud-color:red}
DIV.normalColor {backgroud-color:green}
</style>
<script language="JavaScript">
<!--
function SelectStart()
{
 window.event.cancelBubble = true;
 window.event.returnValue = false;
 return false;
}

function onMouseOver()
{
 if(window.event.srcElement.tagName=="SPAN" && window.event.srcElement.className=="clsLabel")
 {
  window.event.srcElement.className="clsMouseOver"
  window.event.srcElement.title=window.event.srcElement.innerText
 }
}
function onMouseOut()
{

if(window.event.srcElement.tagName=="SPAN" && window.event.srcElement.className=="clsMouseDown")
{
 window.event.srcElement.className="clsCurrentHasFocus"
 return
}

if(window.event.srcElement.tagName=="SPAN" && window.event.srcElement.className=="clsMouseOver")
 window.event.srcElement.className="clsLabel"
}

function onMouseDown()
{
 for(i=0;i<document.getElementsByTagName("SPAN").length;i++)
 {
  if(document.getElementsByTagName("SPAN")[i].className=="clsCurrentHasFocus") document.getElementsByTagName("SPAN")[i].className="clsLabel";
 }

 if(window.event.srcElement.tagName=="SPAN" && (window.event.srcElement.className=="clsMouseOver" || window.event.srcElement.className=="clsLabel"))
 {
  window.event.srcElement.className="clsMouseDown";
  parentid.value=window.event.srcElement.id;
 }
}

window.document.onmouseover = onMouseOver;
window.document.onmouseout = onMouseOut;
window.document.onmousedown = onMouseDown;

var oDiv;
var xmlhttp;
var np;
function window.onload() {
 readXML(0);
}

function readXML(id) {
oDiv = document.createElement("DIV");
nP = parseInt(document.all["pid"+id].style.paddingLeft);
oDiv.innerHTML = "<div style='display:;padding-left:"+nP+"px'><span class='container'><span class='clsLeaf'>.</span></span> " + "<span class='clsNotReady' style='color:#000000;'>正在装载栏目数据,请稍侯.......</span></div>"
oDiv.style.paddingLeft= nP + "px";
document.all["pid"+id].appendChild(oDiv);
var str="parentid="+id;
xmlhttp=new ActiveXObject("MSXML2.XMLHTTP");//提取树型结构数据的核心就在这里
xmlhttp.onreadystatechange=getReady;
xmlhttp.open("get","tree2.jsp?"+str,true);//提交数据到tree2.jsp
xmlhttp.send();
}

function getReady() {
if(xmlhttp.ReadyState==4) {
if(xmlhttp.status==200) {
 var xmldom = new ActiveXObject("Microsoft.XMLDOM")
 xmldom.loadXML(xmlhttp.responseText);//当tree2.jsp操作完成,用xmldom获取这些xml数据
 if(xmldom==null||xmldom.documentElement==null) {
  oDiv.innerHTML="<div style='display:;padding-left:"+nP+"px'><span class='container'><span class='clsLeaf'>.</span></span> " + "<span class='clsNotReady'>抱歉,装载数据失败。原因:返回的数据不是一个XML结构的文档。</span>< /div>";
  return;
 }
 
 
 var nodes = xmldom.documentElement.selectNodes("/root/xiruo");
 if(nodes == null ){
  oDiv.innerHTML = "<div style='display:;padding-left:"+nP+"px'><span class='container'><span class='clsLeaf'>.</span></span> " + "<span class='clsNotReady'>抱歉,装载数据失败。原因:没有返回正确的XML结构格式。</span>< /div>";
  return;
 }
 
 
 var str = "";
 for(var i=0;i<nodes.length;i++) {
  parentid.options.add(new Option(nodes[i].selectSingleNode("id").text,nodes[i].selectSingleNode("id").text));
  if(nodes[i].selectSingleNode("childcount").text!='0') {
   str += "<div style='display:;padding-left:"+nP+"px' id='pid" + nodes[i].selectSingleNode("id").text + "'><nobr><span class='container'><span class='clsCollapse' status='' onclick='hideshow(this,\"pid" + nodes[i].selectSingleNode("id").text +"\")'>+</span></span> ";
   str += "<span class='clsLabel' id='"+nodes[i].selectSingleNode("id").text+"'>"+ nodes[i].selectSingleNode("message").text + " id="+nodes[i].selectSingleNode("id").text+"</span></nobr></div>";
  } else {
   str += "<div style='display:;padding-left:"+nP+"px' id='pid" + nodes[i].selectSingleNode("id").text + "'><nobr><span class='container'><span class='clsLeaf' onclick='hideshow(this,\"pid"+  nodes[i].selectSingleNode("id").text +"\")'>.</span></span> "
   str += "<span class='clsLabel' id='"+nodes[i].selectSingleNode("id").text+"'>"+ nodes[i].selectSingleNode("message").text + " id="+nodes[i].selectSingleNode("id").text+"</span></nobr></div>";
  }
 }
 str+="";
 oDiv.innerHTML = str;
} else {
 oDiv.innerHTML = "<div style='display:;padding-left:"+nP+"px'><span class='container'><span class='clsLeaf'>.</span></span> " + "<span class='clsNotReady'>抱歉,装载数据失败。</span></div>";
}
}
}

function hideshow(o,oId)
{

 var subjectid = oId.substr(3,oId.length)
 if (o.status=="")
 {
  readXML(subjectid)
  o.innerText="-";
  o.status="old";
  return;
 }

 var oChild = null
 for(var i=0;i<document.all[oId].childNodes.length;i++)
 {
  if(document.all[oId].childNodes(i).tagName=="DIV") oChild = document.all[oId].childNodes(i)
 }
 if(oChild==null) return

 if(oChild.style.display=="")
 {
  o.innerText="+";
  oChild.style.display="none";
 }
 else
 {
  o.innerText="-";
  oChild.style.display="";
 }
 event.returnValue=false;
 return false;
}

function addTreeNode() {//添加节点
 var str="parentid="+parentid.value+"&message="+message.value+"&action=add";
 pid0.innerText="";
 parentid.innerText="";
 var xmlhttp=new ActiveXObject("MSXML2.XMLHTTP");
 xmlhttp.onreadystatechange=function addReady(){
  if(xmlhttp.ReadyState==4&&xmlhttp.status==200) {
   if(xmlhttp.responseText.indexOf("error")!=-1) {
    var oDiv = document.createElement("DIV");
    pid0.appendChild(oDiv);
    oDiv.innerHTML="<div style='display:;padding-left:"+nP+"px'><span class='container'><span class='clsLeaf'>.</span></span> " + "<span class='clsNotReady'>抱歉,节点添加失败。</span></div>";
   } else {
    parentid.options.add(new Option("0","0"));
    readXML(0);
   }
  }
 };
 xmlhttp.open("get","do_tree2.jsp?"+str,true);
 xmlhttp.send();
}

function deleteTreeNode() {//删除节点
 if(parentid.value=="0") {
  alert("不存在ID为0的节点!");
  return;
 }
 var str="parentid="+parentid.value+"&action=delete";
 pid0.innerText="";
 parentid.innerText="";
 var xmlhttp=new ActiveXObject("MSXML2.XMLHTTP");
 xmlhttp.onreadystatechange=function addReady(){
  if(xmlhttp.ReadyState==4&&xmlhttp.status==200) {
   if(xmlhttp.responseText.indexOf("error")!=-1) {
    var oDiv = document.createElement("DIV");
    pid0.appendChild(oDiv);
    oDiv.innerHTML="<div style='display:;padding-left:"+nP+"px'><span class='container'><span class='clsLeaf'>.</span></span> " + "<span class='clsNotReady'>抱歉,节点删除失败。</span></div>";
   } else {
    parentid.options.add(new Option("0","0"));
    readXML(0);
   }
  }
 };
 xmlhttp.open("get","do_tree2.jsp?"+str,true);
 xmlhttp.send();
}
//-->
</script>
<table>
<tr><td height="300" valign="top">
<div id="pid0" style="padding-left:6px"></div>
</td></tr>
<tr><td valign="top">
parentid:
<select name="parentid" id="parentid">
<option value="0">0</option>
</select>
0-表示根节点,
message:<input type="text" name="message">
<input type="button" value="add" onClick="addTreeNode();">&nbsp;<input type="button" value="delete" onClick="deleteTreeNode();">
</td></tr></table>
********************
*         tree2.jsp           *//这个是遍历并返回xml数据的文件
********************
<%@ page contentType="text/xml; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>

<%!//方便起见就不写成javabean了
class myHandler extends org.xml.sax.helpers.DefaultHandler {//继承org.xml.sax.helpers.DefaultHandler,然后通过SAX遍历XML
  String s="",parentid="",tarValue="";
  boolean isxiruo=false;
  public myHandler(String parentid) {
    this.parentid=parentid;
  }

  public void startDocument() {
    s+="<?xml version=\"1.0\" encoding=\"gb2312\"?>\r\n\r\n<root>\r\n";
  }

  public void startElement(String namespaceURI,String localName,String qName,org.xml.sax.Attributes attr) {
    if(qName.equals("xiruo")) {
      if(attr.getValue("parentid").equals(parentid)) {
        isxiruo=true;
        s+="\t<xiruo parentid=\""+parentid+"\">\r\n";
      } else
        isxiruo=false;
    }
  }

  public void endElement(String namespaceURI,String localName,String qName) {
    if(isxiruo) {
      if(qName.equals("xiruo"))
        s+="\t</xiruo>\r\n";
      else
        s+="\t\t<"+qName+">"+tarValue+"</"+qName+">\r\n";
    }
  }

  public void endDocument() {
    s+="</root>";
  }

  public void characters(char[] ch,int start,int length) {
    tarValue=new String(ch,start,length);
  }

  public String getXML() {
    return this.s;
  }
}

class buildXML {
 public buildXML(javax.servlet.http.HttpServletRequest request,javax.servlet.jsp.JspWriter out) throws Exception {
 if(request.getParameter("parentid")==null)return;
     javax.xml.parsers.SAXParserFactory spf=javax.xml.parsers.SAXParserFactory.newInstance();
 javax.xml.parsers.SAXParser sp=spf.newSAXParser();
      org.xml.sax.XMLReader xmlreader=sp.getXMLReader();
       myHandler h=new myHandler(request.getParameter("parentid"));//通过构造器输入过滤条件,实现SAX的的XML遍历
        xmlreader.setContentHandler(h);
 xmlreader.parse(request.getRealPath("tree\\tree2.xml"));//我的tree2.xml文件放在tree目录下,如果放在别的地方,需要改这个路径
        out.println(h.getXML());//返回SAX遍历的结果,这里返回的是一个XML的数据结构
 }
}
%>
<!--以上可以写成javabean-->
<%
response.setHeader("Cache-Control","no-cache"); //HTTP 1.1//JSP让页面立即过期的实现
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
new buildXML(request,out);//通过buildXML的构造器打印xml数据
%>
********************
*       do_tree2.jsp        *
********************//这个是添加和删除节点操作的dom实现,实现过程有些复杂,因为是测试用跟树型结构的显示无关,因此可以不必深究
<%@ page contentType="text/html; charset=gb2312" language="java" import="java.sql.*" errorPage="" %>
<%!//方便起见,就不写成javabean了
class buildXML {
String parentid="0";
String message="";
String action="";
boolean getField(javax.servlet.http.HttpServletRequest request) throws Exception {
if(request.getParameter("parentid")==null||request.getParameter("parentid").equals("")||request.getParameter("action")==null)
 return false;
this.parentid=request.getParameter("parentid");
this.action=request.getParameter("action");
if(request.getParameter("message")!=null)
 this.message=new String(request.getParameter("message").getBytes("ISO8859_1"),"gb2312");
return true;
}

void init(javax.servlet.http.HttpServletRequest request,javax.servlet.jsp.JspWriter out) throws Exception {
if(!getField(request)) {
 out.println("error");
 return;
}
if(action.equals("add"))addTreeNode(request);
else if(action.equals("delete"))deleteTreeNode(request);
}
//增加节点
private void addTreeNode(javax.servlet.http.HttpServletRequest request) throws Exception {
  int maxid=0;
  javax.xml.parsers.DocumentBuilderFactory dbf=javax.xml.parsers.DocumentBuilderFactory.newInstance();
  javax.xml.parsers.DocumentBuilder db=dbf.newDocumentBuilder();
  org.w3c.dom.Document document=db.parse(request.getRealPath("tree\\tree2.xml"));
  org.w3c.dom.Element element=document.getDocumentElement();
  org.w3c.dom.NodeList nl=element.getElementsByTagName("xiruo");
  for(int i=0;i<nl.getLength();i++) {//这个循环为了得到最大的ID号,让增加的节点ID在这个最大ID号基础上加1
    int curid=0;
    org.w3c.dom.Element ele = (org.w3c.dom.Element) nl.item(i);
    org.w3c.dom.NodeList nl1=ele.getElementsByTagName("id");
    if(nl1.getLength()==1) {
      org.w3c.dom.Element e=(org.w3c.dom.Element)nl1.item(0);
      org.w3c.dom.Text text=(org.w3c.dom.Text)e.getFirstChild();
              curid=Integer.parseInt(text.getNodeValue());
      maxid=maxid>curid?maxid:curid;
    }
    nl1=ele.getElementsByTagName("childcount");
    if(nl1.getLength()==1&&curid==Integer.parseInt(parentid)) {//所要增加节点的根节点childcount加1
      org.w3c.dom.Element e=(org.w3c.dom.Element)nl1.item(0);
      org.w3c.dom.Text text=(org.w3c.dom.Text)e.getFirstChild();
      text.setNodeValue(String.valueOf(Integer.parseInt(text.getNodeValue())+1));
    }
  }
  org.w3c.dom.Element newElement=document.createElement("xiruo");
  element.appendChild(newElement);
  newElement.setAttribute("parentid",parentid);
  org.w3c.dom.Element e=document.createElement("id");
  e.appendChild(document.createTextNode(String.valueOf(maxid+1)));
  newElement.appendChild(e);
  e=document.createElement("message");
  e.appendChild(document.createTextNode(message));
  newElement.appendChild(e);
  e=document.createElement("childcount");
  e.appendChild(document.createTextNode("0"));
  newElement.appendChild(e);
  javax.xml.transform.dom.DOMSource domsource=new javax.xml.transform.dom.DOMSource(document);
  javax.xml.transform.TransformerFactory tf=javax.xml.transform.TransformerFactory.newInstance();
  javax.xml.transform.Transformer t=tf.newTransformer();
  javax.xml.transform.stream.StreamResult streamresult=new javax.xml.transform.stream.StreamResult(request.getRealPath("tree\\tree2.xml"));
  Properties properties=t.getOutputProperties();
  properties.setProperty(javax.xml.transform.OutputKeys.ENCODING,"gb2312");
  properties.setProperty(javax.xml.transform.OutputKeys.METHOD,"xml");
  properties.setProperty(javax.xml.transform.OutputKeys.VERSION,"1.0");
  properties.setProperty(javax.xml.transform.OutputKeys.INDENT,"no");
  t.setOutputProperties(properties);
  t.transform(domsource,streamresult);
}
//删除节点用递归
private void deleteTreeNode(javax.servlet.http.HttpServletRequest request) throws Exception {
      javax.xml.parsers.DocumentBuilderFactory dbf=javax.xml.parsers.DocumentBuilderFactory.newInstance();
      javax.xml.parsers.DocumentBuilder db=dbf.newDocumentBuilder();
      org.w3c.dom.Document document=db.parse(request.getRealPath("tree\\tree2.xml"));
      org.w3c.dom.Element element=document.getDocumentElement();
      org.w3c.dom.NodeList nl=element.getElementsByTagName("xiruo");
      java.util.ArrayList al=new java.util.ArrayList();
      getDeleteTreeNodeI(parentid,al,nl);
      java.util.Collections.sort(al);
      java.util.Collections.reverse(al);
      for(int i=0;i<al.size();i++)
        element.removeChild(nl.item(((Integer)al.get(i)).intValue()));
      javax.xml.transform.dom.DOMSource domsource=new javax.xml.transform.dom.DOMSource(document);
      javax.xml.transform.TransformerFactory tf=javax.xml.transform.TransformerFactory.newInstance();
      javax.xml.transform.Transformer t=tf.newTransformer();
      javax.xml.transform.stream.StreamResult streamresult=new javax.xml.transform.stream.StreamResult(request.getRealPath("tree\\tree2.xml"));
      Properties properties=t.getOutputProperties();
      properties.setProperty(javax.xml.transform.OutputKeys.ENCODING,"gb2312");
      properties.setProperty(javax.xml.transform.OutputKeys.METHOD,"xml");
      properties.setProperty(javax.xml.transform.OutputKeys.VERSION,"1.0");
      properties.setProperty(javax.xml.transform.OutputKeys.INDENT,"no");
      t.setOutputProperties(properties);
      t.transform(domsource,streamresult);
}

private void getDeleteTreeNodeI(String id,java.util.ArrayList al,org.w3c.dom.NodeList nl) throws Exception {
    int removeid=0,minusid=0;
    for(int i=0;i<nl.getLength();i++) {
      org.w3c.dom.Element ele = (org.w3c.dom.Element) nl.item(i);
      org.w3c.dom.NodeList nl1=ele.getElementsByTagName("id");
      if(nl1.getLength()==1) {
        org.w3c.dom.Element e=(org.w3c.dom.Element)nl1.item(0);
        org.w3c.dom.Text text=(org.w3c.dom.Text)e.getFirstChild();
        if(text.getNodeValue().equals(id)){al.add(new Integer(i));removeid=Integer.parseInt(id);minusid=Integer.parseInt(((org.w3c.dom.Element)nl.item(i)).getAttribute("parentid"));}
      }
    }
    for(int i=0;i<nl.getLength();i++) {
      int curid = 0;
      org.w3c.dom.Element ele = (org.w3c.dom.Element) nl.item(i);
      org.w3c.dom.NodeList nl1 = ele.getElementsByTagName("id");
      if (nl1.getLength() == 1) {
        org.w3c.dom.Element e = (org.w3c.dom.Element) nl1.item(0);
        org.w3c.dom.Text text = (org.w3c.dom.Text) e.getFirstChild();
        curid = Integer.parseInt(text.getNodeValue());
  if((Integer.parseInt(((org.w3c.dom.Element)nl.item(i)).getAttribute("parentid"))==removeid))
         getDeleteTreeNodeI(text.getNodeValue(),al,nl);
     }
      nl1 = ele.getElementsByTagName("childcount");
      if (nl1.getLength() == 1 && minusid == curid) {
        org.w3c.dom.Element e = (org.w3c.dom.Element) nl1.item(0);
        org.w3c.dom.Text text = (org.w3c.dom.Text) e.getFirstChild();
        text.setNodeValue(String.valueOf(Integer.parseInt(text.getNodeValue())-1));
      }
    }
  }
}
%>
<%
response.setHeader("Cache-Control","no-cache"); //HTTP 1.1
response.setHeader("Pragma","no-cache"); //HTTP 1.0
response.setDateHeader ("Expires", 0); //prevents caching at the proxy server
new buildXML().init(request,out);
%>

你可能感兴趣的:(数据结构,jsp,xml,servlet,cache)