第14章 XML节点精确查询

14.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. 查询结果以表格形式在前端呈现。

14.2 设计分析

14.2.1 功能分析

测试用户期望功能如下:

  1. 测试用户可义输入"书号"并将"书号"提交到后端执行精确查询,后端将查询结果传送到前端。
  2. 测试用户可查看测试XML文档原始数据。
图14.1 功能用例建模

图14.1 功能用例建模

14.2.2 核心业务数据流分析

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

核心业务流程描述如下:

  1. 测试用户提交"书号"。
  2. 后台获取"书号"及XML文档对象。
  3. 后台对XML文档对象进行基于XPath的标记选取返回XML文档片断。
图14.2 核心业务数据流

图14.2 核心业务数据流

14.2.3 文件包及文件设计分析

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

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

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

14.3 文件架构

文件架构如图14.4所示。

图14.4 文件架构

图14.4 文件架构

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

表14.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_14.js 当前模块服务专用逻辑

14.4 代码实现

14.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="isbn_input" />
    <input type="button" value="精确查询图书" onclick="select_TagData()" />
    <input type="button" value="查看全部图书" onclick="view_all()" />
    <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_num = $("#isbn_input").val();
    var xhttp = new XMLHttpRequest();
    xhttp.open("post", "http://localhost:1017/exeXPath_14?param=" + encodeURIComponent(book_num), true);
    xhttp.onreadystatechange = function () {
        if (xhttp.status == 200 && xhttp.readyState == 4) {
            $("#outer_div").html("<table border='1'>"+xhttp.responseText+"</table>");
        }
    }
    xhttp.send();
}

//查看全部图书
function view_all() {
    var xhttp = new XMLHttpRequest();
    xhttp.open("post", "http://localhost:1017/viewAll_14", true);
    xhttp.onreadystatechange = function () {
        if (xhttp.status == 200 && xhttp.readyState == 4) {
            $("#outer_div").html( xhttp.responseText);
        }
    }
    xhttp.send();
}
</script>

14.4.2 后台服务实现

1、通用服务实现

// 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("./14/server/server_14.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_14.js代码:

function server_14(request, response, req_head, Q_obj, fs_obj) {
    //执行XPath
    if (req_head == "/exeXPath_14") {
        var b_isbn = Q_obj["param"];
        var b_xpath = "/table/tr[position()=1] | /table/tr[td[1]='" + b_isbn + "']";
        var select = require("./xpath");//获取查询函数
        var dom = require("./xmldom").DOMParser;//获取DOMParser类
        
        fs_obj.readFile("./14/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()); }
            }
        });
    }

    //查看全部图书
    if (req_head == "/viewAll_14") {
        fs_obj.readFile("./14/data/books.xml", "utf-8", function (err, data) {
            if (err) { response.end(err); }
            else {
                response.end(data);
            }
        });
    }
}

module.exports = server_14

14.4.3 实现效果

查看全部图书如图14.5所示。

图14.5 查看全部图书

图14.5 查看全部图书

精确查询如图14.6所示。

图14.6 精确查询示例

图14.6 精确查询示例

14.5 问题思考

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

问题思考:

  1. 为简化前端编程,XML基础数据可采用创新模式设计。
  2. 后端需事先引入xmldom及xpath模块。
  3. 注意应将xmldom模块、xpath模块、后台子服务程序应放置同一文件夹。
  4. 引入xmldom模块建议使用:require("./xmldom")。
  5. 引入xpath模块建议使用:require("./xpath")。
  6. 建议有"查看全部数据"功能,便于"精确查询"选定测试参数。

14.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. 仿真本章案例功能模块及效果实现相关设计。