Firefox 1.5 中的 XML,第 3 部分: 利用 JavaScript 处理 Firefox 中的 XML

了解了 XML 在 Firefox 浏览器中的基本显示和样式后,下一个要关注的功能就是脚本。本文中,我将展示利用 JavaScript 代码处理 XML 这一基本概念。本文包含的所有代码示例和屏幕截图都是在 Ubuntu Linux® 系统中使用 Firefox 1.5.0.4 创建和测试的,配置文件没有修改过(即没有扩展,保留了安装时的默认选项)。如果要编写用于 XML 处理的跨浏览器代码,可能必须使用其他的浏览器嗅探技术,但是,我没有在本文介绍这些技术。

加载 XML 文件

您可以使用 Web 页面内嵌的 JavaScript 代码加载 XML 文档。我将从一个 HTML Web 页面示例入手,该页面加载一个简单的 XML 邮件列表格式用于动态更新,要加载的 XML 文档如 清单 1 所示(labels.xml)。


清单 1.(labels.xml)地址标签 XML
				<?xml version="1.0" encoding="iso-8859-1"?>
        <labels>
        <label id='ep' added="2003-06-10">
        <name>Ezra Pound</name>
        <address>
        <street>45 Usura Place</street>
        <city>Hailey</city>
        <province>ID</province>
        </address>
        </label>
        <label id='tse' added="2003-06-20">
        <name>Thomas Eliot</name>
        <address>
        <street>3 Prufrock Lane</street>
        <city>Stamford</city>
        <province>CT</province>
        </address>
        </label>
        <label id="lh" added="2004-11-01">
        <name>Langston Hughes</name>
        <address>
        <street>10 Bridge Tunnel</street>
        <city>Harlem</city>
        <province>NY</province>
        </address>
        </label>
        <label id="co" added="2004-11-15">
        <name>Christopher Okigbo</name>
        <address>
        <street>7 Heaven's Gate</street>
        <city>Idoto</city>
        <province>Anambra</province>
        </address>
        </label>
        </labels>
        

清单 2 是仅包括一个链接的 HTML 页面,链接显示 “Click here to load addresses”。单击链接,地址标签的信息被添加到页面中。


清单 2. HTML 页面利用 JavaScript 加载 XML 用于动态更新
				<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
        "http://www.w3.org/TR/html4/strict.dtd">
        <html>
        <head>
        <meta content="text/html; charset=iso-8859-1" http-equiv="Content-Type">
        <title>Address book</title>
        <script type="application/javascript">
        var ELEMENT_NODE = 1
        //TEXT_NODE
        function loadAddresses()
        {
        xmlDoc = document.implementation.createDocument("", "", null);
        xmlDoc.onload = writeList;
        xmlDoc.load("labels.xml");
        }
        function writeList()
        {
        var labels = xmlDoc.getElementsByTagName('label');
        var ol = document.createElement('OL');
        for (i=0; i < labels.length; i++)
        {
        var li = document.createElement('LI');
        for (j=0; j < labels[i].childNodes.length; j++)
        {
        if (labels[i].childNodes[j].nodeType != ELEMENT_NODE) continue;
        var cdata = document.createTextNode(
        labels[i].childNodes[j].firstChild.nodeValue);
        li.appendChild(cdata);
        }
        var labelId = document.createTextNode('(' +
        labels[i].getAttribute('id') + ')');
        li.appendChild(labelId);
        ol.appendChild(li);
        }
        document.getElementById('updateTarget').appendChild(ol);
        }
        </script>
        </head>
        <body id='updateTarget'>
        <p>
        <a href="javascript:loadAddresses()">Click here to load addresses</a>
        </p>
        </body>
        </html>
        

script 元素体现动态特性,定义一个 JavaScript 函数 loadAddresses,这个函数将被 HTML 中的链接调用。该函数创建一个空文档实例,然后使用 load 函数读入 清单 1(labels.xml)。load 函数是异步执行的,因此,在 XML 文档读入的同时,脚本可跳到下一行执行,使您能够在 XML 加载开始后就使用一个触发函数开始运行。因此,我为一个独立的函数 writeList 设置 onload 属性。该函数使用方便的文档对象模型(Document Object Model, DOM)的 getElementsByTagName 方法遍历标签。如果 XML 文档使用名称空间,那么要使用 getElementsByTagNameNS 表单而不是上面的方法,并将名称空间指定为第一个参数。在下一节中,您将会看到一个这样的例子。在 清单 2 中,只使用 DOM 的基本层(叫做 DOM Level 1)进行 XML 处理。对于支持名称空间的应用程序,需要使用 DOM Level 2,它扩展了许多 Level 1 方法,可以支持名称空间。清单 2 创建了一个表示有序列表的子树,将 HTML 主文档作为工厂(factory)来创建节点。这样,生成的子树可以插入到 HTML 主文档中。清单 2 使用普通模式读取源 XML 树,然后将相应的节点添加到输出 HTML 子树中。

对每个 label 元素执行循环语句 labels[i].childNodes,查找 name 和 address 子节点。为避免对文本节点的子节点执行操作,使用 nodeType 测试。使用 firstChild.nodeValue 方法进行访问获得 name 元素的子文本。对 address 元素来说,第一个子节点是空格。您不能访问 address 的子节点的任何文本内容。使用 getAttribute 方法可以访问 ID。将收集到的所有文本添加到列表项中。编译完所有的列表项元素之后,使用 appendChild 方法更新包含子树的 HTML 文档。可以使用 updateTarget ID 标记将添加该子树的元素(body)。当第一次在 Firefox 中加载该 HTML 时,只能看到如 图 1 所示的链接。


图 1. 加载清单 2 之后的浏览器显示
清单 2 的初始浏览器显示 

单击链接,就立刻获得最新的显示,如 图 2 所示。


图2. 加载清单 2 并单击链接之后的浏览器显示
清单 2 的更新后的浏览器显示 

对 XML 主文档使用脚本

在本系列的第一部分中,我介绍了如何在 Firefox 中浏览 XML 文件。要在这种情况下使用 JavaScript,需要在脚本文件中嵌套一个引用。清单 3(designers.xml)显示的示例 XML 文件是一个设计师列表。XML 引用独立的 CSS 文件来显示 XML,引用独立的 JavaScript 文件来创建链接元素。


清单 3.(designers.xml)表示时装设计师链接的 XML 格式 
				<?xml version='1.0' encoding='utf-8'?>
        <?xml-stylesheet type="text/css" href="designers.css"?>
        <designers>
        <blurb>
        <designer  homepage="http://doria.co.uk">Doria Ltd.</designer>
        of London
        </blurb>
        <blurb>
        <designer homepage="http://samsara.biz">Samsara Saris</designer>
        of Mumbai
        </blurb>
        <blurb>
        <designer homepage="http://pcp.co.uk">Pikeman Camouflage, Plc.</designer>
        of London
        </blurb>
        <blurb>
        <designer homepage="http://mandalay.co.jp">Mandalay</designer>
        of Tokyo
        </blurb>
        <xhtml:script xmlns:xhtml="http://www.w3.org/1999/xhtml"
        src="designers.js"
        type="application/javascript"/>
        </designers>
        

样式表处理指令提供显示 XML 的基本指令。清单 4(designers.css)显示 CSS。


清单 4.(designers.css)修饰清单 3 中 XML 格式基本显示的 CSS
				* { display: inherit; }
        designers { display: block; }
        blurb {
        margin: 1em;
         20em;
        }
        a {
        display: inline;
        text-decoration: none;
        color: green;
        border: thin blue solid;
        }
        script { display: none; }
        

样式表通知浏览器把 designers 和 blurb 作为块区域,而忽略用于显示的 script 元素。通过将链接(a 元素)和可见的提示一同显示,可以更容易识别出链接。您将注意到在 XML 源文件中不存在 a 元素。因此,这里要用到脚本。JavaScript 代码使用 XHTML 链接元素代替 designer 元素。XHTML 链接元素通过一个 XHTML 脚本元素提供,因此只要使用到 Firefox,就可以嵌入任何 XML(当然,您可能会遇到模式兼容性的问题)。Firefox 在载入的文档中遇到脚本后就运行它们,因此要把脚本放在所有待处理的元素之后。清单 5(designers.js)显示了 JavaScript 代码。


清单 5.(designers.js)将 XML 元素从清单 3 转换为 XHTML 链接的脚本
				//Save the XHTML namespace for when you need it
        var xhtmlns = "http://www.w3.org/1999/xhtml";
        //get all elements named "blurb" in the document
        //The first "" indicates no namespace for the element we're seeking
        var blurbs = document.getElementsByTagNameNS("", "blurb");
        //Loop over each element we found
        for (var i=0; i < blurbs.length; i++)
        {
        //retrieve the blurb element from the collection
        var blurb = blurbs[i];
        //Get the designer element within the blurb
        //Assumes only one designer element per blurb
        var designer = blurb.getElementsByTagNameNS("", "designer").item(0);
        //In DOM the text in designer is actually a text node object child
        //of blurb. The link title is the value of this text node
        //Assumes the text node is normalized
        var link_title = designer.firstChild.nodeValue;
        //Link URL is the homepage attribute of designer, in no namespace
        var link_url = designer.getAttributeNS("", "homepage");
        //Create a new XHTML namespace link element
        var xhtml_link = document.createElementNS(xhtmlns, "a");
        //Create a new text node with the link title
        var new_text_node = document.createTextNode(link_title);
        //Set the href attribute to the link URL
        xhtml_link.setAttributeNS("", "href", link_url);
        //Attach the text node with the link title to the XHTML link
        xhtml_link.appendChild(new_text_node);
        //Replace the designer element with the new XHTML link element
        blurb.replaceChild(xhtml_link, designer);
        }
        

因为 清单 5 中的脚本可以支持名称空间(尤其是其中的 XHTML 名称空间),所以我使用支持名称空间的 DOM 方法。图 3 显示查看 清单 3 的结果。可以看到,浏览器立即应用 CSS 和脚本。


图 3. 加载清单 3 的浏览器显示
加载清单 3 的浏览器显示 




回页首


调用 XSLT

使用 JavaScript 可以访问大多数的浏览器功能,其中包括 XSLT 引擎。清单 6 是一个执行 XSLT 转换的脚本片段。


清单 6. 加载 XML 文档和 XSLT 转换并执行转换的 JavaScript 代码
        //Create an XSLT processor instance
        var processor = new XSLTProcessor();
        //Create an empty XML document for the XSLT transform
        var transform = document.implementation.createDocument("", "", null);
        //Load the XSLT
        transform.onload = loadTransform;
        transform.load("display.xslt");
        //Triggered once the XSLT document is loaded
        function loadTransform(){
        //Attach the transform to the processor
        processor.importStylesheet(transform);
        source = document.implementation.createDocument("", "", null);
        source.load("source.xml");
        source.onload = runTransform;
        }
        //Triggered once the source document is loaded
        function runTransform(){
        //Run the transform, creating a fragment output subtree that
        //can be inserted back into the main page document object (given
        //in the second argument)
        var frag = processor.transformToFragment(source, document);
        //insert the result subtree into the document, using the target element ID
        document.getElementById('updateTarget').appendChild(frag);
        }
        

如果想创建整个输出文档,而不是创建插入到其他文档的子树,使用 transformToDocument 方法代替 transformToFragment 方法。





回页首


结束语

首先是一份重要的免责声明:XML 的 Web 脚本语言还没有完全标准化。文中涉及的很多内容并不是跨浏览器标准化的。由于本系列主要关注 Firefox,文中没有介绍其他浏览器需要做的修改,但是您可以继续了解如何修改以适合各种用户界面。XML 甚至是 XSLT 的 JavaScript 操作都可使用跨浏览器库。如果不能专门针对基于 Mozila 的浏览器进行开发,那么可以使用跨浏览器库。处理 Web 脚本时,必须要考虑可访问性。同时,要注意内容、处理和显示的分离,避免在最后一刻才将引用嵌入到脚本中。另外,也可以保存和管理不包含这类引用的 XML,在将 XML 传送给浏览器之前,插入这些引用。

现在,您已经了解如何在 Web 脚本中加载和处理一个独立的 XML 文件,如何从 XML 主文档中调用脚本,以及如何从脚本中调用 XSLT 处理器。因为 JavaScript 支持所有浏览器特性,因此可以使用它进行更多 XML 处理。可以将学过的各种脚本编制技术,例如动态 HTML(DHTML),应用到 XML 处理中。ECMAScript for XML (E4X) 是一组对 JavaScript 的语言增强(从技术上讲,是 ECMAScript),使 JavaScript 的 XML 处理更容易。这个新标准为 XML 处理添加了专门的用法。Firefox 1.5 支持 E4X,我将在以后的文章中对它进行介绍。不用牺牲 XML 的强大的结构特性,适度和精心设计的脚本可以展现现代 Web 应用程序的全部魅力。



参考资料

学习

获得产品和技术
  • Firefox:获得基于 Mozilla 的 Web 浏览器,该浏览器提供标准遵从性、高性能和安全性,以及稳定的 XML 特性。当前版本为 1.5.0.4。


讨论


关于作者

Uche Ogbuji 是 Fourthought Inc. 的顾问和创立者之一,这是一家专门从事企业知识管理 XML 解决方案的软件供应商和咨询公司。Fourthought 开发了 4Suite,这是一个用于 XML、RDF 和知识管理应用程序的开放源码平台。Ogbuji 先生还是 Versa RDF 查询语言的主要开发人员。他是一位出生在尼日利亚的计算机工程师和作家,目前在美国科罗拉多州博耳得定居和工作。您可以通过他的 Weblog Copia 进一步了解 Ogbuji 先生。

原文地址:https://www.cnblogs.com/yuzhongwusan/p/1371552.html