第4章 动态调用XSLT模板格式化XML

4.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. 设计合适的XSLT文件,应用程序可调用XSLT文件中的降序模板实现格式化以上XML数据并按"price"降序输出。
  2. 设计合适的XSLT文件,应用程序可调用XSLT文件中的升序模板实现格式化以上XML数据并按"price"升序输出。

4.2 设计分析

4.2.1 功能分析

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

  1. 表格形式降序浏览XML文档数据。
  2. 表格形式升序浏览XML文档数据。
  3. 当前XML与动态XSL模板绑定(隐性功能)。
测试用户期望功能用例
图4.1 测试用户期望功能用例

4.2.2 数据流分析

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

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

4.2.3 文件包及文件设计分析

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

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

4.3 文件架构

文件架构
图4.4 文件架构

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

表4.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外围。

4.3 代码实现

4.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,dd_xsldom,'result')" />
    <input class="op_but" disabled="disabled" type="button" 
           value="按价格升序输出图书" 
           onclick="displayXML(xmldom,aa_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 dd_xsldom,aa_xsldom;
$.get("./data/books.xml", function (data) {
    xmldom = data;
    $.get("./UI/X.xslt", function (data) {
        dd_xsldom = $.parseXML(data.replace("~+","dd_fun"));
        aa_xsldom = $.parseXML(data.replace("~+", "aa_fun"));
        $(".op_but").attr("disabled", false);
    }, "text");
}, "xml");
</script>

4.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="dd_fun" match="books">
    <table border="1">
        <tr>
            <th>书号</th>
            <th>书名</th>
            <th>价格</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>价格</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>

4.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);
    }
}

4.3.4 实现效果

按降序排序实现效果如图4.5所示。

按降序排序实现效果
图4.5 按降序排序实现效果

4.4 问题思考

问题:通过以上实例演示,动态调用XSLT模板格式化XML数据的技术要点是什么?

思考(知识归纳):

  1. 首先,应根据设计需求设计合适的XSLT文件。
  2. 在XSLT文件中设计代表不同功能的模板(如:M1、M2、......)。
  3. 将主模板中mode属性设定为:mode="~+"。
  4. 应用程序读取XSLT文件并将文件内容以文本形式返回到前端(假定文本内容住在在变量xsl_string中)。
  5. 对变量进行字符替换操作:xsl_string.replace("~+",自定义模板的mode属性值)并产生新的字符串(假定为new_xsl)。
  6. 将XML文档转化为对象xmldom,将new_xsl转化为对象xsldom。
  7. 调用绑定函数,将对象xmldom,与对象xsldom绑定并格式化输出。

4.5 仿真实训

给定如下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. 设计合适的XSLT文件,应用程序可调用XSLT文件中的降序模板实现格式化以上XML数据并按"price"降序输出。
  2. 设计合适的XSLT文件,应用程序可调用XSLT文件中的升序模板实现格式化以上XML数据并按"price"升序输出。
  3. 仿真本意案例功能实现以上设计。