第3章 动态调用XSLT文件格式化XML

3.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文件并格式化以上XML数据实现基于Web的表格化数据输出。
  2. 设计合适的XSLT文件并格式化以上XML数据实现按"price"降序输出。
  3. 设计合适的XSLT文件并格式化以上XML数据实现按"price"升序输出。

3.2设计分析

3.2.1 功能分析

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

  1. 非排序方式查看XML格式化(表格形式)数据。
  2. 降序方式查看XML格式化(表格形式)数据。
  3. 升序方式查看XML格式化(表格形式)数据。

测试用户期望功能用例建模如图3.1所示。

测试用户期望功能用例

图3.1 测试用户期望功能用例

3.2.2 数据流分析

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

  1. 文件处理框架读取XML源文件或XSLT文件并生成文档对象。
  2. 对象绑定模块将XML文档对象与XSLT文档对象绑定并并输出格式化结果。

数据流核心环节建模如图3.2所示。

数据流核心环节

图3.2 数据流核心环节

3.2.3 文件包设计分析

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

表3.1 文件包及文件设计
序号 包设计 文件设计
1 设计表示层包(包名:UI),相当表示层文件容器。
  1. 设计界面主页文件main.js。
  2. 设计非排序XSLT文件X1.xslt。
  3. 设计降序XSLT文件X2.xslt。
  4. 设计升序XSLT文件X3.xslt。
  5. 设计自定义JS框架文件XSLT.js,包含格式化XML逻辑。
2 设计数据层包(包名:data),相当数据层文件容器。
  1. 设计XML数据测试文件books.xml。

文件包建模如图3.3所示。

文件包建模

图3.3 文件包建模

3.2文件架构

文件架构如图3.4所示。

文件架构

图3.4 文件架构

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

表3.2 文件功能说明
序号 文件名 作用
1 books.xml 用于测试的XML基础数据
2 main.html 实现人机交互的用户界面主页
3 XSLT.js 自定义框架,可实现将XSL与XML绑定并输出格式化数据
4 X1.xslt 格式化XML的XSLT文件,按原始数据顺序输出图书信息
5 X2.xslt 格式化XML的XSLT文件,按价格降序输出图书信息
6 X3.xslt 格式化XML的XSLT文件,按价格升序输出图书信息
7 UI 界面处理逻辑文件所在文件夹
8 data 数据文件所在文件夹

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

3.3代码实现

3.3.1主页代码

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

<!DOCTYPE html>
<html>
<head>
</head>
<body>
    <h2>XSL格式化XML测试</h2>
    <hr />
    <input type="button" value="查看原始图书信息" onclick="displayXML('./data/books.xml','./UI/X1.xslt','result_div')" />
    <input type="button" value="查看图书(按价格降序)" onclick="displayXML('./data/books.xml','./UI/X2.xslt','result_div')" />
    <input type="button" value="查看图书(按价格升序)" onclick="displayXML('./data/books.xml','./UI/X3.xslt','result_div')" />
    <hr />
    <div id="result_div">
    </div>
</body>
</html>
<script type="text/javascript" src="./UI/XSLT.js"></script>

3.3.2 XSLT文件代码

1、非排序输出

X1.xslt文件代码:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
            <body>
                <h2>My books Collection</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th>书号</th>
                        <th>书名</th>
                        <th>价格</th>
                    </tr>
                    <xsl:for-each select="books/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>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

2、降序输出

X2.xslt文件代码:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
            <body>
                <h2>My books Collection</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th>书号</th>
                        <th>书名</th>
                        <th>价格</th>
                    </tr>
                    <xsl:for-each select="books/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>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

3、升序输出

X3.xslt文件代码:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
            <body>
                <h2>My books Collection</h2>
                <table border="1">
                    <tr bgcolor="#9acd32">
                        <th>书号</th>
                        <th>书名</th>
                        <th>价格</th>
                    </tr>
                    <xsl:for-each select="books/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>
            </body>
        </html>
    </xsl:template>
</xsl:stylesheet>

3.3.3 自定义框架XSLT.js文件代码

// JavaScript source code
var xhttp;

function loadXMLDoc(filename) {
    if (window.ActiveXObject) {
        xhttp = new ActiveXObject("Msxml3.XMLHTTP");
    } else {
        xhttp = new XMLHttpRequest();
    }
    xhttp.open("GET", filename, false);
    xhttp.send();
    return xhttp.responseXML;
}

function displayXML(xmlFile, xsltFile, div_id) {
    xml = loadXMLDoc(xmlFile);
    xsl = loadXMLDoc(xsltFile);
    
    // 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);
    }
}

3.3.3 实现效果

非排序情况下实现效果如图3.5所示。

降序情况下实现效果如图3.6所示。

升序情况下实现效果如图3.7所示。

非排序情况下实现效果

图3.5 非排序情况下实现效果

降序情况下实现效果

图3.6 降序情况下实现效果

升序情况下实现效果

图3.7 升序情况下实现效果

3.4 问题思考

问题提出:通过以上实例演示,XSLT文件格式化XML数据的技术要点是什么?

问题思考(知识归纳):

  1. 首先,应根据设计需求设计合适的XSLT文件。
  2. 在XSLT文件中设计合适的模板(一般来说,模板起始标记应为:<xsl:template match="/">;数据的循环输出应使用<xsl:for-each>实现;数据排序应使用<xsl:sort>实现且放于循环结构内部)。
  3. 设计XML文件与XSLT文件绑定函数。
  4. 调用绑定函数实现具体应用。

3.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文件并格式化以上XML数据实现基于Web的表格化数据输出。
  2. 设计合适的XSLT文件并格式化以上XML数据实现按"age"降序输出。
  3. 设计合适的XSLT文件并格式化以上XML数据实现按"age"升序输出。