第5章 XSLT格式化XML输出且排序交互内嵌表格

5.1 设计需求

给定如下XML文档:

<?xml version="1.0" encoding="utf-8"?>
<books>
    <book>
        <ISBN>8475484848</ISBN>
        <title>XML技术</title>
        <price>80</price>
    </book>
    <book>
        <ISBN>35235348</ISBN>
        <title>Python programming</title>
        <price>65</price>
    </book>
    <book>
        <ISBN>67676348</ISBN>
        <title>Java development</title>
        <price>76</price>
    </book>
    <book>
        <ISBN>27974348</ISBN>
        <title>NodeJS development</title>
        <price>90</price>
    </book>
</books>

提出如下设计需求:

  1. 排序交互按钮内嵌在表格中。
  2. 设计合适的XSLT文件并格式化以上XML数据实现按"price"降序输出。
  3. 设计合适的XSLT文件并格式化以上XML数据实现按"price"升序输出。
  4. 内嵌式排序效果如图5.1所示。
内嵌式排序效果图
图5.1 内嵌式排序

5.2 设计分析

测试用户期望功能描述如下:

  1. 表格内嵌式交互降序浏览XML文档数据。
  2. 表格内嵌式交互升序浏览XML文档数据。
测试用户期望功能用例
图5.2 测试用户期望功能用例

5.2.2 数据流分析

数据流核心环节描述如下:

  1. 文件处理框架读取XML源文件或XSLT文件并生成文档对象。
  2. 文件处理框架读取XSLT源文件并生成XSLT文档文本数据。
  3. XSLT文档文本数据经模板处理生成XSL降序对象及XSL升序对象。
  4. 对象绑定模块将XML文档对象与XSL排序对象绑定并并输出格式化结果。
数据流核心环节
图5.3 数据流核心环节

5.2.3 文件包及文件设计分析

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

表5.1 文件包及文件设计
序号 包设计 文件设计
1 设计表示层包(包名:UI),相当表示层文件容器。
  1. 设计界面主页文件main.js。
  2. 设计包含排序逻辑的XSLT文件X.xslt。
  3. 设计自定义JS框架文件XSLT.js,包含格式化XML逻辑。
  4. 引入jquery框架(jquery.js)。
2 设计数据层包(包名:data),相当数据层文件容器。 设计XML数据测试文件books.xml。
文件包建模
图5.4 文件包建模

5.3 文件架构

文件架构
图5.5 文件架构
表5.2 文件功能说明
序号 文件名 作用
1 books.xml 用于测试的XML基础数据
2 jquery-1.11.1.js 加载JQuery函数库
3 XSLT.js 自定义框架,可实现将XSL与XML绑定并输出格式化数据
4 X.xslt 格式化XML的XSLT文件
5 main.html 实现人机交互的用户界面主页
6 UI 界面处理逻辑文件所在文件夹
7 data 数据文件所在文件夹

说明:实际应用中,考虑到$.get()不能跳出当前文件夹读取文件,主页文件暂时放在UI外围。

5.3 代码实现

5.3.1 主页代码

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

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <h3>XSLT格式化XML输出测试</h3>
    <hr />
    <input class="op_but" disabled="disabled" type="button" 
           value="浏览全部图书信息" onclick="displayXML(xmldom, gg_xsldom, 'result')" />
    <hr />
    <div id="result">
    </div>
</body>
</html>

<script type="text/javascript" src="./UI/jquery-1.11.1.js"></script>
<script type="text/javascript" src="./UI/XSLT.js"></script>
<script type="text/javascript">
//初始化
var xmldom; var gg_xsldom, dd_xsldom,aa_xsldom;
$.get("./data/books.xml", function (data) {
    xmldom = data;
    $.get("./UI/X.xslt", function (data) {
        gg_xsldom = $.parseXML(data.replace("~+", "gg_fun"));
        dd_xsldom = $.parseXML(data.replace("~+","dd_fun"));
        aa_xsldom = $.parseXML(data.replace("~+", "aa_fun"));
        $(".op_but").attr("disabled", false);
    }, "text");
}, "xml");
</script>

5.3.2 XSLT文件代码

X.xslt文件代码如下:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
    <xsl:template match="/">
        <xsl:apply-templates mode="~+"></xsl:apply-templates>
    </xsl:template>

    <xsl:template mode="gg_fun" match="books">
        <table border="1">
            <tr>
                <th>书号</th>
                <th>书名</th>
                <th>
                    价格
                    <input type="button" value="降序" onclick="displayXML(xmldom,dd_xsldom,'result')" />
                    <input type="button" value="升序" onclick="displayXML(xmldom,aa_xsldom,'result')" />
                </th>
            </tr>
            <xsl:for-each select="book">
                <tr>
                    <td>
                        <xsl:value-of select="ISBN"/>
                    </td>
                    <td>
                        <xsl:value-of select="title"/>
                    </td>
                    <td>
                        <xsl:value-of select="price"/>
                    </td>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>

    <xsl:template mode="dd_fun" match="books">
        <table border="1">
            <tr>
                <th>书号</th>
                <th>书名</th>
                <th>
                    价格
                    <input type="button" value="降序" onclick="displayXML(xmldom,dd_xsldom,'result')" />
                    <input type="button" value="升序" onclick="displayXML(xmldom,aa_xsldom,'result')" />
                </th>
            </tr>
            <xsl:for-each select="book">
                <xsl:sort select="price" data-type="number" order="descending"/>
                <tr>
                    <td>
                        <xsl:value-of select="ISBN"/>
                    </td>
                    <td>
                        <xsl:value-of select="title"/>
                    </td>
                    <td>
                        <xsl:value-of select="price"/>
                    </td>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>

    <xsl:template mode="aa_fun" match="books">
        <table border="1">
            <tr>
                <th>书号</th>
                <th>书名</th>
                <th>
                    价格
                    <input type="button" value="降序" onclick="displayXML(xmldom,dd_xsldom,'result')" />
                    <input type="button" value="升序" onclick="displayXML(xmldom,aa_xsldom,'result')" />
                </th>
            </tr>
            <xsl:for-each select="book">
                <xsl:sort select="price" data-type="number" order="ascending"/>
                <tr>
                    <td>
                        <xsl:value-of select="ISBN"/>
                    </td>
                    <td>
                        <xsl:value-of select="title"/>
                    </td>
                    <td>
                        <xsl:value-of select="price"/>
                    </td>
                </tr>
            </xsl:for-each>
        </table>
    </xsl:template>
</xsl:stylesheet>

5.3.3 XSLT.js文件代码

XSLT.js文件代码如下:

function displayXML(xml, xsl, div_id) {
    //xml、xsl均是XMLDocument对象,div_id是一个外部div的ID
    // code for IE
    if (window.ActiveXObject) {
        ex = xml.transformNode(xsl);
        document.getElementById(div_id).innerHTML = "";
        document.getElementById(div_id).innerHTML = ex;
    }
    // code for Chrome, Firefox, Opera, etc.
    else if (document.implementation && document.implementation.createDocument) {
        xsltProcessor = new XSLTProcessor();
        xsltProcessor.importStylesheet(xsl);
        resultDocument = xsltProcessor.transformToFragment(xml, document);
        document.getElementById(div_id).innerHTML = "";
        document.getElementById(div_id).appendChild(resultDocument);
    }
}

5.3.4 实现效果

按升序排序实现效果如图5.6所示。

升序排序效果
图5.6 升序排序效果

5.5 问题思考

问题提出:通过以上实例演示,在分页浏览XML数据时,动态调用XSLT模板格式化XML数据实现表格内嵌式排序的技术要点是什么?

问题思考:

  1. 首先,应根据设计需求设计合适的XSLT文件。
  2. 在XSLT文件中设计代表不同功能的模板(如:M1、M2、......)。
  3. 读取XSLT文件,动态改变将主模板中mode属性的值(字符串替换法)。
  4. 将XML文档转化为对象xmldom,将动态读取的XSLT文档转化为对象xsldom。
  5. 调用绑定函数,在分页浏览设计的基础上,将对象xmldom与对象xsldom绑定并格式化输出。

5.6 仿真实训

给定如下XML文档:

<?xml version="1.0" encoding="utf-8"?>
<students>
    <student category="new_student">
        <s_id>8475484848</s_id>
        <s_name>Max</s_name>
        <age>18</age>
    </student>
    <student>
        <s_id>35235348</s_id>
        <s_name>Jack</s_name>
        <age>20</age>
    </student>
    <student>
        <s_id>67676348</s_id>
        <s_name>Json</s_name>
        <age>21</age>
    </student>
    <student>
        <s_id>27974348</s_id>
        <s_name>Rose</s_name>
        <age>19</age>
    </student>
</students>

提出如下设计需求:

  1. 排序交互按钮内嵌在表格中。
  2. 设计合适的XSLT文件并格式化以上XML数据实现按"age"降序输出。
  3. 设计合适的XSLT文件并格式化以上XML数据实现按"age"升序输出。
  4. 内嵌式排序效果类似如图5.1所示。
  5. 功能性仿真本章案例实现以上设计。