2

我有一个定义任务的 XML 文档,该任务是要对某些数据执行的操作的列表。我需要将此“任务列表”转换为可以在以后调用的 Javascript 方法,该方法又会调用一系列带有适当数据的预定义方法。您将如何实现这一目标?

重要说明:
我不担心 XML 解析。我对如何实际构建任务方法更感兴趣,包括将基本数据绑定到预定义的操作方法。这就是我正在努力的部分。

编辑:我已经修改了我的示例,使其更有趣,并希望更清晰一些。

XML:

<task id="enter-castle">
    <if holding="castle-key">
        <print message="You unlock the castle door and enter." />
        <destroy item="castle-key" />
        <goto location="castle" />

        <else>
            <print message="The castle door is locked." />
        </else>
    </if>
</task>

Javascript:

Game = {

    print: function(message) {
        // display message
    },

    destroy: function(item) {
        // destroy the object
    },

    goto: function(location) {
        // change player location
    },

    ifHolding: function(item) {
        // return true if player has item
    }
};

parseTask(taskNode) {

    var taskId = taskNode.getAttribute('id');

    // What goes here??

    Game.tasks[taskId] = /* ??? */;
}

当我parseTask()<task id="enter-castle">节点上调用时,这应该创建一个函数,实际上,调用时会执行以下操作:

Game.tasks.enterCastle = function() {
    if (Game.ifHolding('castle-key')) {
        Game.print("You unlock the castle door and enter.");
        Game.destroy('castle-key');
        Game.goto('castle');
    } else {
        Game.print("The castle door is locked.");
    }
}
4

3 回答 3

3

你想要的是闭包

function createMethod(arguments) {
    var task = doSomethingWithYour(arguments);
    return function(xmlData) { // <- this is the fundamental part
        // do the task with your data
        // the "task" vars are still available
        // even if the returned function is executed in a different context
    }
}

这允许您为每个任务创建自己的方法。不要使用 Function 构造函数或 eval。

于 2012-03-03T18:46:10.003 回答
2

在这种情况下,JavaScript 的eval()功能将使您的生活更轻松。您可以轻松构建与所需字符串匹配的 JavaScript 源字符串,并对其进行评估以将函数分配给 Game 对象的所需属性。

当然,使用“eval”也有缺点,我不会在这个答案中探讨它,因为您可以找到无数理由说明为什么不在网络上使用它。然而,在短期内构建和评估一个简单的 JS 源字符串将比基于闭包的解决方案容易得多,尽管存在任何潜在的性能和安全性缺陷。此外,基于“eval”的解决方案将很容易测试,因为您可以在评估源字符串之前简单地检查它。

所以尝试这样的事情:

function buildTaskFunction(taskXml) {
  var source='', depth=0, node /*a visitor to each DOM node*/;
  // foreach (node in traverseInOrder(taskXml)) {
    switch (node.nodeName) {
      case 'TASK':
        source += 'Game.tasks.' + makeFunctionName(node.id) + '= function(){';
        depth++;
        break;
      case 'IF':
        source += 'if(' + getConditionalAttribute(node) + '){'
        depth++;
        break;
      case 'ELSE':
        source += '}else{';
        break;
      case 'DESTROY':
        source += 'Game.destroy("' + node.getAttribute('item') + '");'
        break;
      case 'PRINT':
        source += 'Game.print("' + node.getAttribute('message') + '");'
        break;
      // case etc...
      default: throw new Error('unhandled node type "' + node.nodeName + '"');
    }
  // end "foreach node".
  while (depth-- > 0) { // You'll need to account for nested "if"s somehow...
    source += '}';
  }
  eval(source);
}

再一次,使用“eval”有很多潜在的问题(不是确定的问题),所以请阅读并尝试在您的解决方案的上下文中理解它们。在决定您自己的程序中的缺点是否值得好处时,请使用您自己的判断——仅仅因为一个工具可能很危险并不意味着您不应该使用它。

于 2012-03-03T19:05:29.343 回答
0

使用dojo的示例:

dojo.require("dojox.xml.parser");

dojo.ready(function(){
  // Parse text and generate an XML DOM
  var xml = "<tnode><node>Some Text</node><node>Some Other Text</node></tnode>";
  var dom = dojox.xml.parser.parse(xml);

  var docNode = dom.documentElement();
  // ...
}

该函数的其余部分并不重要,但主要包括使用属性查找['<attribute-name>']和使用子节点迭代dojo.forEach(<node>.childNodes, function(childNode) { /* do stuff */ });

于 2012-03-01T20:57:03.557 回答