powerwind 发表于 2006-7-31 12:40

JS+XML打造QQ个性通信录

一接触XML就喜欢上它,当时还在本版发了叫JS+XML+HTML=?的帖,大概介绍用JS操纵XML实现查询功能做通信录。现在重写,把它嵌入到QQ面板,成为这样的效果:

iptton 发表于 2006-7-31 12:42

共享共享……

powerwind 发表于 2006-7-31 13:06

整个程序包括 Communication.htm,Communication.css,Communication.xml 三个主要文件和一些图片文件。
先介绍存放数据的文件 Communication.xml
XML全名是:eXtensible Markup Language(可扩展标识语言),它和网页超文本标记语言HTML有点相似。(不作详细介绍,有兴趣的可以搜索相关文章)

假设你的朋友分为三类,分别是:同学,同事,其它朋友

所以XML数据文件可以为这样:
Communication.xml

<?xml version="1.0" encoding="gb2312"?>
<通信录>
        <同学>
                <个人信息>
                        <姓名 性别="男">陈一</姓名>
                        <出生日期>1983-8</出生日期>
                        <住址>湛江</住址>
                        <家里电话>0729-3201928</家里电话>
                        <手机号码>13756875467</手机号码>
                        <电子邮箱>chengone@21cn.com</电子邮箱>
                        <QQ号码>82521492</QQ号码>
                </个人信息>
                <个人信息>
                        <姓名 性别="男">李二</姓名>
                        <出生日期>1983-1-12</出生日期>
                        <住址>汕头</住址>
                        <家里电话>0750-2596329</家里电话>
                        <手机号码>13637896451</手机号码>
                        <电子邮箱>litwo@163.com</电子邮箱>
                        <QQ号码>260117983</QQ号码>
                </个人信息>
        </同学>
        <同事>
                <个人信息>
                        <姓名 性别="女">王三</姓名>
                        <出生日期>1986-5-6</出生日期>
                        <住址>广州市</住址>
                        <家里电话>020-88158546</家里电话>
                        <手机号码>1392585676</手机号码>
                        <电子邮箱>wangthree@hotmail.com</电子邮箱>
                        <QQ号码>7454652657</QQ号码>
                </个人信息>
                <个人信息>
                        <姓名 性别="女">何四</姓名>
                        <出生日期> 1985-2-5</出生日期>
                        <住址>北京</住址>
                        <家里电话>010-88816594</家里电话>
                        <手机号码>13512586555</手机号码>
                        <电子邮箱>hefour@263.net</电子邮箱>
                        <QQ号码>764354985</QQ号码>
                </个人信息>
        </同事>
        <其它朋友>
                <个人信息>
                        <姓名 性别="男">陈四</姓名>
                        <出生日期>1983-5-23</出生日期>
                        <住址>电白</住址>
                        <家里电话>0714-85654685</家里电话>
                        <手机号码>13929634673</手机号码>
                        <电子邮箱>chengfour@263.net</电子邮箱>
                        <QQ号码>2824368488</QQ号码>
                </个人信息>
                <个人信息>
                        <姓名 性别="男">何时</姓名>
                        <出生日期>1986-6-3</出生日期>
                        <住址>广州</住址>
                        <家里电话>020-87685456</家里电话>
                        <手机号码>13752856285</手机号码>
                        <电子邮箱>heshi@263.com</电子邮箱>
                        <QQ号码>423719510</QQ号码>
                </个人信息>
        </其它朋友>
</通信录>

上面的XML文档可以理解成这样的树形结构:

其中元素个人信息的子元素没有画出,其子元素分别是:姓名,出生日期,住址,家里电话,手机号码,电子邮箱,QQ号码。这几个元素都没有子元素,而只是有值(其中姓名还有一个属性—性别)。

因为用JS操纵XML时是采用DOM文档对象模型,所以要先知道这个文档的结构。

[ 本帖最后由 powerwind 于 2006-8-6 13:17 编辑 ]

powerwind 发表于 2006-7-31 16:22

限于篇幅,略去外观的设计,也就是略去CSS样式文件 Communication.css 现在就只剩下 Communication.htm和 Communication.js 两个文件了。

因此,只给出重要代码

Communication.htm

这里应该是htm(已改了,PPT应该没意见吧……)
                                                      ---MODIFYBYiptton

<html>
<head>
    <link href="Communication.css" type="text/css" rel="stylesheet" />
    <script language="javascript" src="Communication.js"></script>
</head>
<body>
        <table><tr><td>
        <input id="inputText" type="text" onmouseover="this.focus()" onfocus="this.select()" value="请输入关键字查询" />
        </td></tr>

        <tr><td width="174">
                <select id="styles">
                        <option value="Name" selected>姓名
                        <option value="FamilyName">姓氏
                        <option value="Cellphone">手机号码
                        <option value="QQ">QQ号码
      </select>
                        &nbsp;
        <input type="image" src="search_btn.gif" style="cursor:hand" onclick="find(styles.value,inputText.value)" />
        </td></tr>
               
        <tr><td>
                <select id="classes">
            <option value="all" selected>全部
            <option value="classmate">同学
            <option value="workmate">同事
            <option value="others">其它朋友
      </select>
                        &nbsp;
      <a href="javascript:seeAll(classes.value)">查看</a>
        </td></tr>
</table>
</body>
</html>


[ 本帖最后由 iptton 于 2006-8-17 19:38 编辑 ]

powerwind 发表于 2006-7-31 16:36

Communication.js 文件是操纵XML的 javascript 程序代码,有两个重要函数。

Communication.js

var XDoc = null;        //xmldom文档对象
var xmlFile="Communication.xml";//XML文件
var tableHead="<table align='center' style='border-collapse:collapse' bordercolor='#ffe366' border='2'><tr style='font-size:16pt;color:#f90000;'><th>姓名</th><th>性别</th><th>出生日期</th><th>住址</th><th>家里电话</th><th>手机号码</th><th>电子邮箱</th><th>QQ号码</th></tr><tr>";
//指定关键字查找
function find(classes,keyWords)        //classes:查找类别,keyWords:查找关键字
{
        if(XDoc==null)
        {
                XDoc=new ActiveXObject("Microsoft.xmldom");
                XDoc.load(xmlFile);
        }

        if(keyWords==null||(keyWords=Trim(keyWords)).length>11||keyWords.length<1){
                window.alert("输入有误,请重新输入");
                return false;
        }
        var XML_root=XDoc.documentElement;          //根元素(通信录)       
                     var Level1nodes=XML_root.childNodes;          //根以下的所有子集(同学,同事,其它朋友)
        var rootLen=Level1nodes.length;        //子元素个数
        var Level1node,Level1nodes,Level2node,Level2nodes,Level3node,Level3nodes;
        var tableStr=tableHead,familyname="",mystring=""
        var count=1;        //以第几个元素的值来查找
        for(var c=0;c<rootLen;c++)        //根目录下的子目录循环查找
                  {                               
                Level2node=Level1nodes.nextNode();        //根下的(同学或同事或其它朋友)
                Level2nodes=Level2node.childNodes;        //(同学或同事或其它朋友)下的所有个人信息
                var NodeLen=Level2nodes.length;        //个人信息的个数

                for(var i=0;i<NodeLen;i++)
                {
                        //第i个个人信息,currentNode保存当前结点       
                                               currentNode=Level3node=Level2nodes.nextNode();       
                        Level3nodes=Level3node.childNodes;        //个人信息下的所有子集
                        if(classes=="QQ")count=7;
                        else if(classes=="Cellphone")count=5;
                        for(var j=0;j<count;j++)
                          Level3node=Level3nodes.nextNode();
                        familyname=Level3node.text;
                        if(classes=="FamilyName") //按姓氏查找
                        {
                                familyname=Trim(familyname).charAt(0);
                                keyWords=keyWords.charAt(0);
                        }
               
                        if(familyname==keyWords)
                        {                                               
                                Level3nodes=currentNode.childNodes;
                                for(var        j=0;j<Level3nodes.length;j++)
                                {               
                                        Level3node=Level3nodes.nextNode();
                                        if(j==0)mystring+="<td>"+Level3node.text+"</td><td>"+ Level3node.attributes.value+"</td>";
                                        else mystring+="<td>"+Level3node.text+"</td>";
                                }
                                mystring+="</tr>";
                        }
                }
        }
        //输出结果
        if(mystring.length<10)
        {
                window.alert("对不起,以"+classes+"来查找,没有找到'"+keyWords+"'的相关信息\n");
                return false;
        }

        mystring=tableStr+mystring+"</table>";
        var newWin=window.showModelessDialog("a","","dialogWidth=55;dialogHeight=20")
        newWin.document.write("<style type='text/css'>td{font-size:16pt;color:#2235f8}</style>");
        newWin.document.write("<body background='communication.jpg'>");
        newWin.document.write("<br><h2 align='center' style='color:blue'>查询结果</h2>");
        newWin.document.write(mystring);

        return false;
}

//去除首尾空格
function Trim(str)
{
        var ss=String(str);
        return ss.replace(/(^\s*)|(\s*$)/g, "");
}
//按类别查看(和 find 函数相似,不再注释)
function seeAll(classes){        //classes:查找类别
        if(XDoc==null)
        {
             XDoc=new ActiveXObject("Microsoft.xmldom");
          XDoc.load(xmlFile);
        }

        var result=tableHead;
        var currentNode;
        var Level1nodes,Level2node,Level3nodes;
        var count=0;       

        if(classes=="classmate")count=1;
        else if(classes=="workmate")count=2;
        else if(classes=="others")count=3;

        var XML_root=XDoc.documentElement;
        var Level1nodes=XML_root.childNodes;

        if(count!=0)
        {
                for(var i=0;i<count;i++)
                {
                        Level2node=Level1nodes.nextNode();
                }
                result+=parseNode(Level2node.childNodes,Level2node.childNodes.length);
        }else
        {
                for(var        i=0;i<Level1nodes.length;i++)
                {
                        Level2node=Level1nodes.nextNode();
                        result+=parseNode(Level2node.childNodes,Level2node.childNodes.length);
                }
        }
        outPut(result);
}
//输出
function outPut(result)
{
        result+="</table></body><br>";
        var w=screen.width-10,h=screen.height-10;
        var newWin=window.showModelessDialog("a","","dialogWidth="+w+";dialogHeight="+h)
        newWin.document.write("<style type='text/css'>td{font-size:16pt;color:#2235f8}h2{color:blue;text-align:center}</style>");
        newWin.document.write("<body background='communication.jpg'>");
        newWin.document.write("<br><h2>通信录</h2>");
        newWin.document.write(result);
        newWin.document.close();
}
//解析节点
function parseNode(nodes,nodesLen)
{
        var Level3nodes,len,result="";
        for(var j=0;j<nodesLen;j++)
        {
                Level3nodes=nodes.nextNode().childNodes;
                var len=Level3nodes.length;
                for(var k=0;k<len;k++)
                {
                        currentNode=Level3nodes.nextNode();
                        if(k==0)result+="<td>"+currentNode.text+"</td><td>"+currentNode.attributes.value+"</td>";
                        else result+="<td>"+currentNode.text+"</td>";
                }
                result+="</tr><tr>";
        }
        return result;
}

这样,就基本上完成了一个网页了。至于如何嵌入QQ面板,==

[ 本帖最后由 powerwind 于 2006-8-1 15:57 编辑 ]

wool王 发表于 2006-7-31 22:45

很有创意的原创内容.加精了...

PS...楼主别不好意思,别因为是自己的文章就不敢加精.写得好就要让大家都知道...

powerwind 发表于 2006-7-31 22:49

楼上的,我还没有写完呢!呵呵~
待续。。。

iptton 发表于 2006-8-1 00:37

说真的……
POWERWIND师兄的界面做得不怎么样……
跟偶的水平无甚差距……

当然,后面的代码实现……

powerwind 发表于 2006-8-1 00:51

原帖由 iptton 于 2006-8-1 00:37 发表
说真的……
POWERWIND师兄的界面做得不怎么样……
跟偶的水平无甚差距……

当然,后面的代码实现……

Wool 师兄说,会写程序的人很多都不会做界面的。呵呵~

所以界面做得不好就这样安慰自己了

powerwind 发表于 2006-8-1 01:13

前面是代码的实现,后面要做的只是把它放进QQ里而已。QQ是怎样的我不清楚,但基本上按照以下步骤可以把网页嵌进去。
首先,网页做好了,假设放在 C:\Communication 文件夹里。
接着,打开QQ的面板管理器(panel manager),如图:

点击添加面板(Add panel),这样就打开了一个网页,找到 QQ电台,如图:

点击上图的超链接,完成面板的添加。在QQ的安装目录下的找到你的Q号为目录名的目录(这里假设为123456),然后找到目录 PanelData ,打开文件 PanelData.ini,找到


userpanelver=7
iconName=radio.ico
iconUrl=http://portalinfo.qq.com/radio.ico
iconver=1
panelid=10003
userpanel=TRUE
url=http://fm.qq.com/player/index.shtml?clientuin=$uin$&clientkey=$key$
domainid=17000
PanelIndex=1005
type=0
tipsinfo=QQ电台
name=QQ电台
stream=1
bFlash=FALSE
bForbid=FALSE

修改成


userpanelver=7
iconName=radio.ico
iconUrl=http://portalinfo.qq.com/radio.ico
iconver=1
panelid=10003
userpanel=TRUE
url=file:///C:\Communication\Communication.htm
domainid=17000
PanelIndex=1005
type=0
tipsinfo=我的通信录
name=我的通信录
stream=0
bFlash=FALSE
bForbid=FALSE

重新登录QQ,看看QQ面板是否多了个图标,如果没有,面板管理器,把选项打上勾。

(完)

[ 本帖最后由 powerwind 于 2006-8-1 15:57 编辑 ]

MJOfPowerwind 发表于 2006-8-1 15:55

要显示全部信息时不用JS写函数吧?XSL就是专门用来控制 XML 的格式显示。

Communication.xsl

<?xml version="1.0" encoding="gb2312"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:template match="/">
                <html>
                <head><title>test</title></head>
                <body>
                <table align="center" border="1">
                <caption><strong>通信录</strong></caption>
                <thead>
                        <th>姓名</th>
                        <th>性别</th>
                        <th>出生日期</th>
                        <th>住址</th>
                        <th>家里电话</th>
                        <th>手机号码</th>
                        <th>电子邮箱</th>
                        <th>QQ号码</th>
                </thead>
                <tbody>
                <xsl:for-each select="//个人信息">
                <tr>
                        <td><xsl:value-of select="姓名" /></td>
                        <td><xsl:apply-templates select="姓名"/></td>
                        <td><xsl:value-of select="出生日期" /></td>
                        <td><xsl:value-of select="住址" /></td>
                        <td><xsl:value-of select="家里电话" /></td>
                        <td><xsl:value-of select="手机号码" /></td>
                        <td><xsl:value-of select="电子邮箱" /></td>
                        <td><xsl:value-of select="QQ号码" /></td>
                </tr>
                </xsl:for-each>
                </tbody>
                </table>
                </body>
                </html>
        </xsl:template>

        <xsl:template match="姓名">
        <xsl:value-of select="@性别" />
        </xsl:template>
</xsl:stylesheet>

然后修改 Communication.xml 文件一点点。
在 <?xml version="1.0" encoding="gb2312"?> 下一行加上 <?xml-stylesheet type="text/xsl" href="Communication.xsl"?>。用IE打开XML文件就可以看到格式化的输入了。

如果只想输入某类朋友的信息,比如只输出同学的信息。把 <xsl:for-each select="//个人信息">改成 <xsl:for-each select="通信录/同学/个人信息">即可。

iptton 发表于 2006-8-1 17:34

原来此MJ非彼MJ……

wool王 发表于 2006-8-2 00:03

原帖由 powerwind 于 2006/8/1 00:51 发表


Wool 师兄说,会写程序的人很多都不会做界面的。呵呵~

所以界面做得不好就这样安慰自己了


你的界面估计会比hjack做得好看...哈哈...

我们公司的那个架构师做出来的界面那才叫丑...

wool王 发表于 2006-8-2 00:05

ps...楼主,,,是不是hjack给了你什么好处,,,你帮他们东家这么打广告...我现在每天上班都是免费在帮他们公司做产品测试...

powerwind 发表于 2006-8-2 11:20

原帖由 wool王 于 2006-8-2 00:03 发表
你的界面估计会比hjack做得好看...哈哈...
我们公司的那个架构师做出来的界面那才叫丑...

当然啦,根据你的理论(会写程序的不会做界面),我做的界面应该比hjack的好看。呵呵~



原帖由 wool王 于 2006-8-2 00:05 发表

ps...楼主,,,是不是hjack给了你什么好处,,,你帮他们东家这么打广告...我现在每天上班都是免费在帮他们公司做产品测试...


大家都在免费为他们公司测试,可这么久了,还是觉得QQ的反应很慢,输入法切换会出现假死现象。现在正式向hjack投诉。

发现对XML的验证方面没有说到,现在加上。
XML对格式有严格的要求,除了本身要求的每个元素以<>,要以</>(如果空元素可以这样: <Name/>),还可能定义验证文档,要求XML以指定格式设计。还是以 Communication.xml 为例,如果数据<姓名> 没有性别这个属性,而程序却去读取该属性,结果可想而知,又或者其中的个人信息的第一个子元素不是姓名,总之无顺序。这样会带来些不必要的麻烦。所以应该自定义它的格式。

Communication.dtd

<?xml version="1.0" encoding="GB2312"?>
<!ELEMENT 通信录 (同学,同事,其它朋友)>
<!ELEMENT 同学 (个人信息+)>
<!ELEMENT 同事 (个人信息+)>
<!ELEMENT 其它朋友 (个人信息+)>
<!ELEMENT 个人信息 (姓名,出生日期,住址,家里电话,手机号码,电子邮箱,QQ号码)>
<!ELEMENT 姓名 (#PCDATA)>
<!ELEMENT 出生日期 (#PCDATA)>
<!ELEMENT 住址 (#PCDATA)>
<!ELEMENT 家里电话 (#PCDATA)>
<!ELEMENT 手机号码 (#PCDATA)>
<!ELEMENT 电子邮箱 (#PCDATA)>
<!ELEMENT QQ号码 (#PCDATA)>
<!ATTLIST 姓名 性别 (男|女) "男" >

只要在 Communication.dtd文件中的 <?xml version="1.0" encoding="gb2312"?> 下一行加上<!DOCTYPE 通信录 SYSTEM "Communication.dtd">

<!ATTLIST 姓名 性别 (男|女) "男" >指定了 姓名 元素的属性 性别 默认值为男,可以删除Communication.dtd文件中所有 性别="男",而输出结果不变。

源码附件


[ 本帖最后由 powerwind 于 2006-8-6 16:02 编辑 ]

wool王 发表于 2006-8-2 14:06

细看了楼主的文章。这个东西不错,能做出来骗MM,哈哈。。。我准备学这招。

powerwind 发表于 2006-8-2 15:17

原帖由 wool王 于 2006-8-2 14:06 发表
细看了楼主的文章。这个东西不错,能做出来骗MM,哈哈。。。我准备学这招。

楼上学习态度不端正,学习动机不良!

其实XML到处都在用,特别是JAVA的部署文件。很多程序的配置文件也是XML格式,千千静听的歌曲列表就是XML文件来的。很久前就接触过XML,可就是停在初级阶段。。。

powerwind 发表于 2006-8-6 13:21

上传了全部源码在15F

hjack 发表于 2006-8-8 22:18

原帖由 wool王 于 2006-8-2 14:06 发表
细看了楼主的文章。这个东西不错,能做出来骗MM,哈哈。。。我准备学这招。

一齐学.哈哈:hug::victory:

PS:个附件好像有问题:time:

对不起,请不要从外部链接下载本论坛的附件。

PPT再看看吧.

powerwind 发表于 2006-8-8 22:25

有时候可以有时又不行,试试这个吧?
http://blog.gdutbbs.com/batch.download.php?aid=1977
如果不行,请到回收站下载吧,呵呵。
页: [1] 2
查看完整版本: JS+XML打造QQ个性通信录