Фильтрация E4X в Spidermonkey

Я использую E4X в SpiderMonkey, и большая часть языка кажется довольно надежной, но я не могу заставить работать фильтрацию:

var xml = <root>
    <person id="dave">Dave</person>
    <person id="ian">Ian</person>
    <person>John</person>
</root>

trace( xml.*.(name() == 'person') );
trace( xml.*.(attribute('@id')) );

Ожидал:

<person id="dave">Dave</person>
<person id="ian">Ian</person>
<person>John</person>

<person id="dave">Dave</person>
<person id="ian">Ian</person>

Результаты:

ReferenceError: name is not defined
ReferenceError: attribute is not defined

Я даже не могу заставить hasOwnProperty() работать:

xml.*.(trace( hasOwnProperty('@id') ));

false
false
false

В частности, я использую JSFL во Flash, в котором используется движок SpiderMonkey.

Судя по моим базовым знаниям об E4X, это довольно неожиданно / с ошибками, верно? Поскольку я могу заставить эти выражения отлично работать в ActionScript/FlashPlayer!

Спасибо, Дэйв


person Dave Stewart    schedule 11.06.2011    source источник


Ответы (2)


Итак, я перепробовал кучу вещей, и я все еще не могу заставить работать исходный синтаксис, поэтому лучшее, что я могу предложить (это довольно хороший обходной путь, учитывая), это расширить прототип XMLList и добавить метод фильтра():

XMLList.prototype.function::filter = function(callback)
{
    var output  = new XMLList();
    var length  = input.length();
    for(var i = 0; i < length; i++)
    {
        if(callback(input[i], i, input))
        {
            output += input[i];
        }
    }
    return output;
}

Итак, со следующим XML...

var xml = <root>
    <person id="dave">Dave</person>
    <person id="ian">Ian</person>
    <person>John</person>
    <group>
        <person id="jane">Jane</person>
        <person>Sarah</person>
    </group>
</root>

Захватывать и фильтровать узлы довольно интуитивно:

// old
var nodes = xml..person.( hasOwnProperty('@id') );

// new
var nodes = xml..person.filter( function(node){ return node.hasOwnProperty('@id'); } );

<person id="dave">Dave</person>
<person id="ian">Ian</person>
<person id="jane">Jane</person>

Если кто-нибудь может исправить меня в этом, я был бы очень рад, если нет, я просто хотел бы знать, почему моя первоначальная фильтрация просто не сработала.

Дэйв

person Dave Stewart    schedule 12.06.2011
comment
Я ищу точно такое же решение. Я попробовал ваш пример кода, но он не работает. Я получаю сообщение об ошибке. - person tarekahf; 05.02.2018

Просто небольшая поправка к ответу, опубликованному здесь, относительно функции filter:

XMLList.prototype.function::filter = function(callback)
{
    var output  = new XMLList();
    var input = this;
    var length  = input.length();
    for(var i = 0; i < length; i++) {
        //console.println(i + ", " + input[i]);
        if(callback(input[i], i, input))
        {
            //console.println("Yes");
            output += input[i];
        }
    }
    //console.println('output = ' + output);
    return output;
}

Оригинальное решение - лучшее, и это было именно то, что я искал!

person tarekahf    schedule 05.02.2018