views:

337

answers:

3

Hi!

I'm working on Rhino (Mirth), and I've got to process / parse an XML with the following structure:

<root>
<row>
<foo-1 />
<foo-2 />
<foo-3 />
<foo-4 />
...
<bar-1 />
<bar-2 />
<bar-3 />
<bar-4 />
...
<something-else-1 />
<something-else-2 />
</row>
</root>

I want to get all the "foo" nodes only, avoiding the use of loops if possible. I've been trying somenthing like:

xml.row.(new RegExp("foo[1-4]").test()))

and a few variations of the same line, but it does not seem to work. Is there any E4X syntax / method to get this done?? I've been googling for a while, and i've read the ECMAS documentation, but i can't get this done.

Thanks in advance!

A: 

This is how you should be able to do it, but it doesn't work in Rhino:

xml.row.*.( /foo-[1-4]/.test(name()) ) // or localName()

For now, as far as I know, you will need to use a loop.

If you don't mind getting an array instead of an XMLList, and your version of Rhino supports array comprehensions, you could use this:

[foo for each (foo in xml.row.*) if (/foo-[1-4]/.test(foo.name()))]

It still uses a loop, but it's a little more declarative at least.

Edit: Like Elijah Grey mentioned in the comments, if you are using namespaces you would need to either call localName() or name().localName. Of course, to be completely correct, you would need to compare the namespace URI as well.

Also, apparently, SpiderMonkey (Firefox) requires you to prefix function calls with function:: in filter predicates, so the filter would look like this:

/foo-[1-4]/.test(function::name()) // or function::localName()

Typically, Rhino follows what SpiderMonkey does, so when it supports function calls in predicates, you may need the function:: prefix.

Matthew Crumley
That might not always work as intended if namespaces are involved so you should use `name().localName`.
Eli Grey
Also, that's not how it _should_ work, you have to prefix `function::` before methods in XML filters, otherwise it looks up the scope instead.
Eli Grey
As I commented, it seems that I cannot use the function:: namespace in Mirth. I'm currently asking at the Mirth forums. However, this is the solution I was looking for, so thanks a lot!
Psychocandy
A: 
xml.row.*.( /foo-[1-4]/.test(function::localName()) )
Eli Grey
That works in the Firebug console, but not in Mirth, the environment I'm working with. It seems that the <code>function::</code> namespace it's not allowed, because the script validator throws a syntax error when I use it. Also, as you said, I get reference errors when I try to use <code>name()</code> or <code>localName()</code> in the filter, so I guess it's a scope problem. It's a shame, because I really really liked this solution and it was exactly what I was looking for :(
Psychocandy
Well then you can just put your JavaScript that uses E4X in another file that isn't checked by Mirth or (I know this sounds bad, but it's the only other options) use `eval`.
Eli Grey
Also, can I at least have an update for answering your question, "Is there any E4X syntax / method to get this done?"
Eli Grey
I already tried using eval, but I doesn't work either. It passes the first script validation, but it seems it does a second one afterwards, and it throws the same syntax error. Sorry about the update, first time on Stack Overflow. Now I've updated you, I guess :) Thanks!
Psychocandy
A: 

Btw, you can do it without regex too.

var foo = xml.row.*.(String(localName()).indexOf("foo-") == 0);
alert(foo.length() + "\n" + foo.toXMLString());
Amarghosh