4

Consider this XML snippet with "nodes" which can have unlimited child levels of "subnode" elements.

I want to find @type attribute of the node for any given subnode, based on its @id attribute. For example, if I have an id of 9 then I want to return the type="foo" from above.

<xml>
    <node type="bar">
        <subnode id="4">
            <subnode id="5"/>
        </subnode>  
        <subnode id="6"/>
    </node>
    <node type="foo">
        <subnode id="7">
            <subnode id="8">
                <subnode id="9"/>
            </subnode>
        </subnode>
        <subnode id="10"/>
    </node>
</xml>

The E4X I have come up with, but which fails is:

xml.node.(subnode.(@id == '8')).@type 

I can kind of see why it doesn't work. What would make more sense is the following but the syntax fails (in AS3):

xml.node.(..subnode.(@id == '8')).@type

How can this be done?

p.campbell
  • 98,673
  • 67
  • 256
  • 322
Jake Howlett
  • 169
  • 3
  • 14

3 Answers3

5

You should be able to get the type value using this E4X:

xml.node.(descendants("subnode").@id.contains("8")).@type;
Niko Nyman
  • 1,916
  • 2
  • 16
  • 26
  • Looks promising Nico, but it tells me that "value is not a function" when I add that line of code. Any idea? – Jake Howlett Sep 18 '09 at 08:45
  • Further to that it seems to be the descendants() part which is causing the error. – Jake Howlett Sep 18 '09 at 09:49
  • 1
    I tested this line of code by copy pasting your XML in my test document, and it worked. Can you post the exact error message you're getting? – Niko Nyman Sep 18 '09 at 12:02
  • You're right. I tested it with the XML I posted and it *did* work. Must be something weird about my actual XML. Will look in to it. Thanks for the answer!! I knew there was a way to do it... – Jake Howlett Sep 18 '09 at 13:19
  • Got it to work with my real XML now. No idea what I did wrong first time. – Jake Howlett Sep 18 '09 at 13:27
  • Great! I've noticed it helps to think that when doing such conditional access stuff using E4X, the code inside the parentheses must return a Boolean. My usual mistake is trying to put something inside the parentheses that would return an XMLList. – Niko Nyman Sep 20 '09 at 20:09
  • Aha, that explains it Niko. Thanks - you're a star. – Jake Howlett Sep 21 '09 at 12:30
  • @Niko Why doesn't `xml.node.(descendants("subnode").@id == "8").@type;` work in this case? It seems to be doing the same thing, isn't it? – Amarghosh Oct 20 '09 at 10:23
  • It's a good question. I tried that first and also noticed that it needs `contains()` for some reason. – Niko Nyman Oct 26 '09 at 08:34
0

Having given up on E4X I used a "hack" and did it in ActionScript instead. Here's how:

var p:XML = xml..subnode.(attribute('id').toLowerCase() === "8")[0];

//Traverse back up to the parent "node"           
while ( p.name().toString() === "subnode" ) {
    p = p.parent();
}

Alert.show(p.@type); //Should say "foo"

Seems a mess though. Would still be interested in any plain E4X solution.

p.campbell
  • 98,673
  • 67
  • 256
  • 322
Jake Howlett
  • 169
  • 3
  • 14
0

Try this

for each(var node:XML in xml.node)
{
    var subnodes:XMLList = node..subnode;
    if(subnodes.(@id == '9').length() != 0)
        return node.@type;
}

EDIT: Even this should work:

if(node..subnode.(@id == '9').length() != 0)
Amarghosh
  • 58,710
  • 11
  • 92
  • 121