第15章 XML节点模糊查询

15.1 设计需求

给定如下XML文档:

<?xml version="1.0" encoding="utf-8"?>
<table border="1" id="books">
    <tr bgcolor="green">
        <th id="ISBN">书号</th>
        <th id="title">书名</th>
        <th id="price">价格</th>
    </tr>
    <tr>
        <td>5744885</td>
        <td>Java programming</td>
        <td>80</td>
    </tr>
    <tr>
        <td>2323885</td>
        <td>C# programming</td>
        <td>87</td>
    </tr>
    <tr>
        <td>8888</td>
        <td>Python programming</td>
        <td>68</td>
    </tr>
    <tr>
        <td>8767885</td>
        <td>NodeJS</td>
        <td>90</td>
    </tr>
    <tr>
        <td>r64547565647689</td>
        <td>C++ programming</td>
        <td>68</td>
    </tr>
    <tr>
        <td>45634748758478</td>
        <td>MongoDB</td>
        <td>90</td>
    </tr>
    <tr>
        <td>675665647689</td>
        <td>operation system</td>
        <td>68</td>
    </tr>
    <tr>
        <td>2342353758478</td>
        <td>XML技术</td>
        <td>90</td>
    </tr>
</table>

现提出如下设计需求:

  1. 基于三层架构,调用NodeJS服务,以"书名"为输入参数,实现对图书模糊查询。
  2. 后台需基于xmldom模型借助xpath技术实现。
  3. 查询结果以表格形式在前端呈现。

15.2 设计分析

15.2.1 功能分析

测试用户期望功能如下:

  1. 测试用户可义输入"书名局部字符串"并将"书名局部字符串"提交到后端执行精确查询,后端将查询结果传送到前端。
  2. 测试用户可查看测试XML文档原始数据。

用户测试功能用例建模如图15.1所示。

功能用例建模

图15.1 功能用例建模

15.2.2 核心业务数据流分析

功能模块中的核心业务是:以"书名局部字符串"作为搜索关键字,执行模糊查询并返回XML文档片断。

核心业务流程描述如下:

  1. 测试用户提交"书名局部字符串"。
  2. 后台获取"书名局部字符串"及XML文档对象。
  3. 后台对XML文档对象进行基于XPath的标记选取查询并返回XML文档片断。

核心业务数据流建模如图15.2所示。

核心业务数据流

图15.2 核心业务数据流

15.2.3 文件包及文件设计分析

基于三层架构视角的文件包及文件设计如表15.1所述。

序号 包设计 文件设计
1 设计表示层包(包名:UI),抽象表示层文件容器。 (1) 设计界面主页文件main.js。
(2) 主页引入jquery框架(jquery.js),辅助表示层处理。
2 设计业务逻辑层包(包名:server),抽象业务层文件容器。 (1) 设计通用业务逻辑服务文件server.js。
(2) 设计当前模块专用业务逻辑服务文件server_15.js。
(3) 引入xmldom模块(xmldom.js,外部安装获得)。
(4) 引入xpath模块(xpath.js,外部安装获得)。
3 设计数据层包(包名:data),抽象数据层文件容器。 (1) 设计XML数据存储文件books.xml。

文件包设计及文件关系如图15.3所示。

文件包设计及文件关系

图15.3 文件包设计及文件关系

15.3 文件架构

文件架构如图15.4所示。

文件架构

图15.4 文件架构

文件功能说明见表15.1所述。

序号 文件(夹)名 作用
1 books.xml 用于测试的XML基础数据
2 Server.js NodeJS后台服务通用逻辑
3 jquery-1.11.1.js 加载JQuery函数库
4 main.html 用户界面主页
5 Data 存放XML数据文件的文件夹
6 server 存放业务逻辑层文件的文件夹
7 UI 存放表示层文件的文件夹
8 xmldom 安装xmldom模块产生的文件夹
9 xpath 安装xpath模块产生的文件夹
10 _doc 存放辅助文档,不参与项目运行
11 Server_15.js 当前模块后台服务专用逻辑

15.4 代码实现

15.4.1 主页实现

主页文件main.html实现代码如下:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <h2>基于XPath的标记数据模糊查询测试</h2>
    <hr />
    请输入书名(注:不输入,可查全部)<input type="text" id="title_input" />
    <input type="button" value="模糊查询图书" onclick="select_TagData()" />
    <hr />
    <div id="outer_div">
    </div>
</body>
</html>

<script type="text/javascript" src="jquery-1.11.1.js"></script>
<script type="text/javascript">
//基于XPath的标记数据模糊查询
function select_TagData() {
    var book_name = $("#title_input").val();
    var xhttp = new XMLHttpRequest();
    xhttp.open("post", "http://localhost:1017/exeXPath_15?param=" + encodeURIComponent(book_name), true);
    xhttp.onreadystatechange = function () {
        if (xhttp.status == 200 && xhttp.readyState == 4) {
            $("#outer_div").html("<table border='1'>"+xhttp.responseText+"</table>");
        }
    }
    xhttp.send();
}
</script>

15.4.2 后台服务实现

1、通用服务实现

后台服务程序server.js实现代码如下:

// JavaScript source code
//---------------请将这个文件保存为Unicode格式,否则麻烦大大的----------------

const http_obj = require("http");//用于产生服务对象
const fs_obj = require("fs");//读写后台文件
const url_tran_obj = require("url");//解释URL

const server = http_obj.createServer(function (request, response) {
    //请求路径处理
    var req_str = decodeURI(request.url);
    var req_head;
    var POS = req_str.indexOf("?");
    if (POS == -1) { req_head = req_str; }
    else { req_head = req_str.substring(0, POS); }
    
    //设置查询对象
    var url_obj = url_tran_obj.parse(req_str, true);
    var Q_obj = url_obj.query;
    
    //响应头设置
    response.setHeader("Content-Type", "text/plain;charset=utf-8");
    response.setHeader("Access-Control-Allow-Origin", "*");//实现跨域访问
    response.writeHead(200);
    
    //%%%%%%%%%%%%%---------------begin your code
    //初始化所有服务对象
    require("./15/server/server_15.js")(request, response, req_head, Q_obj, fs_obj);
    //%%%%%%%%%%%%%----------------end your code
});

server.listen(1017);
console.log("Server is running at port 1017...");

2、专用服务实现

文件server_15.js代码:

function server_15(request, response, req_head, Q_obj, fs_obj) {
    if (req_head == "/exeXPath_15") {
        //代码2
        var b_title = Q_obj["param"];
        var b_xpath = "/table/tr[position()=1] | /table/tr[contains(td[2],'" + b_title + "')]";
        var select = require("./xpath");//获取查询函数
        var dom = require("./xmldom").DOMParser;//获取DOMParser类
        
        fs_obj.readFile("./15/data/books.xml", "utf-8", function (err, data) {
            if (err) { response.end(err); }
            else {
                var xmldom = new dom().parseFromString(data);
                var nodes = select(xmldom, b_xpath);
                if (nodes.length == 1) { response.end("未找到相关数据!"); }
                else { response.end(nodes.toString()); }
            }
        });
    }
}

module.exports=server_15

15.4.3 实现效果

模糊查询典型案例如图15.5所示。

模糊查询典型案例

图15.5 模糊查询典型案例

15.5 问题思考

问题提出:实现基于XPath的标记数据模糊查询的主技术要点是什么?

问题思考:

  1. 为简化前端编程,XML基础数据可采用创新模式设计。
  2. 后端需事先引入xmldom及xpath模块。
  3. 引入xmldom模块建议使用:require("./xmldom");引入xpath模块建议使用:require("./xpath")。
  4. 建议有"查看全部数据"功能,便于"模糊查询"逐步缩小查询范围。

15.6 仿真实训

给定如下XML文档:

<?xml version="1.0" encoding="utf-8"?>
<table border="1" id="books">
    <tr style="background-color:greenyellow">
        <th id="s_id">学号</th>
        <th id="name">姓名</th>
        <th id="age">年龄</th>
    </tr>
    <tr>
        <td>5744885</td>
        <td>Max</td>
        <td>18</td>
    </tr>
    <tr>
        <td>2323885</td>
        <td>Jack</td>
        <td>17</td>
    </tr>
    <tr>
        <td>8888</td>
        <td>Roseg</td>
        <td>18</td>
    </tr>
    <tr>
        <td>8767885</td>
        <td>Json</td>
        <td>19</td>
    </tr>
    <tr>
        <td>64547565647689</td>
        <td>张三</td>
        <td>16</td>
    </tr>
    <tr>
        <td>45634748758478</td>
        <td>李四</td>
        <td>19</td>
    </tr>
    <tr>
        <td>675665647689</td>
        <td>王五</td>
        <td>18</td>
    </tr>
    <tr>
        <td>2342353758478</td>
        <td>刘六</td>
        <td>20</td>
    </tr>
</table>

现提出如下设计需求:

  1. 基于三层架构,调用NodeJS服务,以"姓名"为输入参数,实现对学生模糊查询。
  2. 后台需基于xmldom模型借助xpath技术实现。
  3. 查询结果以表格形式在前端呈现。
  4. 仿真本意案例功能模块及效果实现相关设计。