nephtes
nephtes

Reputation: 1319

With AS3's XML find/filter operators, how to find children of an XML node when a tag is repeated?

This is probably best illustrated by an example:

var xml1:XML = new XML("<root> <key>value1</key> </root>");
var xml2:XML = new XML("<root> <key>value1</key> <key>value2</key> </root>");
var xml3:XML = new XML("<root> <key>value1</key> <key2>value2</key2> </root>");
for each (var xml:XML in [ xml1, xml2, xml3 ])
{
    var result:XMLList = xml.(key == "value1").key;
}

In all three cases, I expect the filtered XMLList to have one node (result.length() == 1). This is the case when operating on xml1 and xml3. However, nothing is found when filtering xml2 (result.length() == 0). The crucial difference seems to be that in xml2, the "key" child tag is repeated.

Is this a bug (compiler? runtime?) or am I doing something wrong?

Upvotes: 0

Views: 228

Answers (3)

Zero
Zero

Reputation: 1

AS3's XML objects have some pretty cool tricks, Listing based on the tag name is super simple.

var xml:XML = new XML("<root> <key>value1</key> <key>value2</key> </root>");
var result:XMLList = xml.key;

That will create an XMLList of length 2 with every node with the tag 'key' you can also expand this for certain child nodes (i.e. xml.doors.locks.key).

You can also make lists based on a nodes attributes by using the prefix '@'.

var xml:XML = new XML("<root> <key name=\"k1\">value1</key> <key name=\"k2\">value2</key> <key name=\"k3\">value3</key> </root>");
var result:XMLList = xml.key.@name;

You can also concatenate if you have more than one list.

var xml1:XML = new XML("<root> <key>value1</key> <key>value2</key> <key>value3</key> </root>");
var xml2:XML = new XML("<root> <key>value4</key> <key>value5</key> <key>value6</key> </root>");
var list:XMLList = xml1.key;
list += xml2.key;

Hope this helps.

Upvotes: 0

nephtes
nephtes

Reputation: 1319

Ok, I think I've figured out how this works. I had misunderstood the syntax.

In my original example, xml.(key == "value1") selects a root node where the "key" property matches the string "value1".

In the case of xml1 and xml3, where there's only one "key" node, the value of xml.key is a single-element XMLList which string-casts to its text value, so the comparison with "value1" works.

In the case of xml2, where there are two "key" nodes, the value of xml.(key == "value1") is a two-element XMLList which string-casts two the full XML-encoded contents of the XML nodes, tags and all. So the comparison with "value1" fails and the value of the expression is empty.

No compiler or runtime bug, just a confused programmer.

Upvotes: 0

david.emilsson
david.emilsson

Reputation: 2331

Actually, I would have expected it to return an XMLList of length 2 in the case of xml2. It should select parent elements which contains a node named "key" with the value "value1", then filter all the nodes named "key".

Not sure why it doesn't, though. This is some E4X syntax that would do what I describe above:

var result:XMLList = xml.(descendants("key").text().contains("value1")).key;

result lengths:

  • xml1: 1
  • xml2: 2
  • xml3: 1

On the other hand, if what you're expecting is only the nodes named "key" and with the value "value1", you can try this:

var result:XMLList = xml..key.(text() == "value1");

result lengths:

  • xml1: 1
  • xml2: 1
  • xml3: 1

Upvotes: 1

Related Questions