65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 JScript 创建 XML 查看器 - Exsead XML 脚本

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.71/5 (4投票s)

2007年2月2日

CPOL

6分钟阅读

viewsIcon

87937

downloadIcon

943

如何从文件或 AJAX 读取 XML 数据源,然后在 Internet Explorer 中将其表示为 GUI

引言

本文基于 Exsead 构建了一个 JScript DOM 解析器和一个 XML 查看 GUI。

关于 Exsead 等的一些背景

Exsead 的核心概念 在此 进行了介绍。另外,为了从本文中获得最大的收益,如果您已经看过关于使用 Internet Explorer 作为脚本 GUI 的帖子,那将非常有帮助,该帖子 在此。本文中的代码还利用了我用于在 JScript 中读取二进制文件的系统,该系统 在此 进行了详细描述。关于本文中使用的 AJAX 的更多背景信息 在此

代码示例中包含 XMLViewer.js。该脚本使用模型-视图-控制器(MVC)概念来构建一个简单但有效的 XML 数据查看器。还包含了一个更简单的 MVC 示例(来自上一篇关于使用 Internet Explorer 作为 GUI 的帖子),名为 MVCExample.js(一点想象力都没有……)。任何像这样解析 XML 的脚本的目的都是将 XML 中存储的原始数据转换为可用的知识。XML 本身是完全静态的数据,毫无用处;它必须先被解析到程序中,然后才能“活过来”。这正是 XMLViewer.js 所做的。

XMLViewer.js 是一个相当长的脚本,因为它执行了几个不同的功能来实现其目标。但是,整体结构非常简单;各个部分如下:

  • ProcessArguments:此函数处理传递给脚本的参数,如果未传递任何参数,则执行默认操作。
  • DisplayXML:顾名思义,它将 XML 的可视化表示推送到 Internet Explorer GUI。
  • XMLClean:这只是一个简单的实用程序,用于转义文本中的 < 符号。
  • ProcessNode:正如我们稍后将看到的,XML 以节点树的形式存储,此函数由 DisplayXML 使用,用于遍历整个树,并在遍历过程中创建 XML 结构的 HTML 表示。
  • GUIWindow:这是一个对象函数,即创建一个对象的函数。它创建的对象是 Internet Explorer 实例的包装器。然后,该类可以作为 DisplayXML 用于将 XML 的可视化(HTML)表示发送到 Internet Explorer 的方法。
  • BinaryFile:作为另一个对象函数,它创建 BinaryFile 对象,允许 JScript 将文件作为二进制而不是文本进行读写。它用于读取 XML 文件。
  • ConcatStringArray:这是一个非常方便的实用程序,它接受一个 string 数组并返回通过将它们连接在一起创建的 string。这比简单地将大量 string 加在一起要快得多,因为当 string 开始变长时。

处理参数

如果您将参数传递给脚本(当您将 XML 文件拖放到脚本图标上时会发生这种情况),此函数将以二进制文件形式读取文件,然后将内容传递给 DisplayXML。如果没有参数,则 Process Arguments 使用 AJAX 从 Nerds-Central ATOM feed 获取 XML 数据流,并将返回的 XML 传递给 DisplayXML

This is the Arguments/File Read part:
=====================================
        for(var i=0;i<WScript.arguments.count();++i)
        {
            var chunks;
            var fn=WScript.arguments.item(i);
            var bf1=new BinaryFile(fn);
            var xml=bf1.ReadAll();
            DisplayXML(xml);
        }

This is the AJAX Part:
======================
        var ajax=WScript.CreateObject('Microsoft.XMLHTTP');

        // Try to get the file 32 times then give up
        for(var i=0;i<32;++i)
        {
            try
            {
                // Set it to point to the Web service
                // Note the last argument being false forces the script to
                // wait for the response
                ajax.open
                   ('GET','http://nerds-central.blogspot.com/feeds/posts/default',false);

                // Set the request header so that the connection is closed right
                // away to avoid locking up server resource
                ajax.setRequestHeader
                (
                    'Connection',
                    'close'
                );

                // Send the request and wait
                ajax.send();

                // The server returned an error
                if(!ajax.status==200) throw('Got Wrong Status:'+ajax.status);
                break;
            }
            catch(e)
            {
                for(var a in e)
                {
                    WScript.Echo(a + '=' + e[a]);
                }
                // Note the use of the () around the maths makes the numeric calculation
                // occur and the result be turned into a string by the + operator
                WScript.echo('Failed to get atom feed from Nerds-Central:
                            tries left='+(32-i));
            }
        }

        // If the loop did not exit due to counting out
        // display the XML
        if(i!=32)DisplayXML(ajax.responseText);

显示 XML

给定一个作为 string 的 XML 片段,此函数使用 Microsoft DOM 解析器对其进行解析。然后,它定位 DOM 的 Document 部分(DOM - 文档对象模型 - 除了文档本身之外还有其他部分)。

var xmlDOM = new ActiveXObject("Microsoft.XMLDOM");
xmlDOM.loadXML(xml);
var doc=xmlDOM.documentElement;

一旦获取了文档元素,它就会创建一个 Array,用于存储所有输出的 HTML。采用此方法是因为新的 HTML 部分可以非常有效地“推”到数组的末尾,然后在最后一刻将整个数组转换为 string

要理解下一个环节,我们必须理解 DOM 概念如何建模 XML。与大多数现代软件概念一样,它实际上比许多人认为的要简单得多!在处理 XML 时,需要理解两个核心概念:

  1. 一切皆节点。
  2. 忽略所有您不需要担心的东西。

节点实际上只是简单的容器。它们可以包含其他节点,也可以包含文本。所以像这样的 XML 片段<tt><myParent><myChild>Hello World</myChild></myParent></tt>将在 DOM 中存储为 3 个节点。第一个节点将具有nodeNamemyParent。它将有一个子节点,该子节点将具有nodeNamemyChildmyChild 节点也将有一个子节点。但这个子节点没有名字。但是,它包含文本。它有一个nodeValueHello World

为了区分包含文本的节点和包含其他节点的节点(或可能包含其他节点但碰巧为空的节点),每个节点都有一个 nodeType。节点类型 3 和 4 包含文本。

我们快理解节点了!本文需要的最后一个概念是“属性”的概念。属性就是 XML 中的 key="value" 形式。例如<tt><myParent gender="female">Dorris</myParent></tt>可能是一个 XML 片段,表示某人的母亲名叫 Dorris。属性是使用更复杂的 XML 结构(如下所示)的替代方法<tt><myParent><tname>Dorris</name><gender>female</gender></myParent></tt>。如果您打印出关于何时应该或不应该使用属性的所有互联网讨论,您可能会砍掉亚马逊雨林。所以,现在我想我们应该只接受它们可以使用!

DOM 的文档元素本身就是一个节点。所有 XML 文档都必须有一个外部节点,所有其他节点都是该节点的后代。ProcessNode 接受一个节点并生成该节点及其所有后代的 HTML 表示。因此,DisplayXML 将文档元素(为什么它不称为文档节点 - 我不知道)传递给 ProcessNode

处理节点

想吓一跳吗?嗯,ProcessNode 是一个“递归后代处理器”。听起来非常复杂、令人费解和可怕……但同样,它实际上非常简单。推理如下:每个节点要么有一个值,要么有子节点。我们有一个函数来处理父节点。父节点与子节点完全相同。因此,我们使用相同的函数来处理父节点及其子节点。最简单的方法是让处理父节点的函数为每个子节点调用自身。调用自身的函数称为递归。使用递归来“遍历父/子关系”的函数称为递归后代。最后,它在遍历过程中处理节点,所以它是一个递归后代处理器。

// This version has all but the XML handling code stripped out
// See the zip file for the full version
function ProcessNode(node,outArr)
{
    // Is this a text node? Text nodes have type 3 or 4
    if(node.nodeType<3 || node.nodeType>4)
    {
        // !!! - NOT A TEXT NODE - !!!

        // Get the node name here
        ... node.nodeName ...

        // Get the attributes
        var atts=node.attributes;

        // Process attributes if there are any
        if(atts.length>0)
        {
            for(var i=0;i<atts.length;++i)
            {
                var aNode=atts.item(i);
                // Attributes are nodes as well! They have a name and value name=value
                ... aNode.nodeName ...
                ... aNode.nodeValue ...
            }
        }

        // Process and children, if there are any
        if(node.hasChildNodes())
        {
            var newNode=node.firstChild;
            while(newNode!=null)
            {
                // This is the recursion bit!
                ProcessNode(newNode,outArr);

                newNode=newNode.nextSibling;
            }
        }
    }
    else
    {
        // !!! - IS A TEXT NODE - !!!
        ... node.nodeValue ...
    }
}

最后,我们将 XML 的 HTML 可视化推送到 GUI

这是使用以下代码片段创建的

// Get the output
var out=ConcatStringArray(outArr);

// Create a GUI
var gui= new GUIWindow();

gui.SetHTML(out);
var doc=gui.GetDocument();
var styleSheet;
if(doc.styleSheets.length==0)
{
    styleSheet=doc.createStyleSheet();
}
else
{
    styleSheet=doc.styleSheets[0];
}
styleSheet.addRule('body','color: black;');
styleSheet.addRule('body','font-family: Arial, helvetic, sans-serif;');
styleSheet.addRule('span.nodeName','font-weight: 700;');
styleSheet.addRule('ul.attributeList','color: #008;');
styleSheet.addRule('li.nodeValue','color: #080;');
styleSheet.addRule('*.missing','color: #888;');

gui.SetVisible(true);

好的,这需要消化很多东西,但对于一个简单的脚本来说,结果却相当强大!

历史

  • 2007 年 2 月 2 日:首次发布
© . All rights reserved.