E4X select Nodes where descendants can be either A OR B or A && B
-
11-06-2021 - |
Question
So I have this XML structure:
<Items>
<Item name="aaa">
<ProductRanges>
<ProductRange id="1" />
</ProductRanges>
</Item>
<Item name="bbb">
<ProductRanges>
<ProductRange id="2" />
</ProductRanges>
</Item>
<Item name="ccc">
<ProductRanges>
<ProductRange id="1" />
<ProductRange id="2" />
</ProductRanges>
</Item>
</Items>
Using the following E4X query I get only item "aaa" and item "bbb".
trace( Items.Item.(descendants("ProductRange").@id == "1" || descendants("ProductRange").@id == "2") );
However, I can kind of see why I'm not seeing item "ccc" because it is BOTH id="1" && "2"
So not really sure what the correct query should be here, and even if descendants is the correct technique.
I don't want to end up doing long additional id="1" && id="2" queries either because I have unlimited combinations of these values ("2" && "3", "1" && "2" && "3") etc..
Any thoughts would be most helpful..
Thanks
So Patrick solved this with this expression:
xml.Item.(descendants('ProductRange').(@id=="1" || @id=="2").length()>0);
However, taking this one step further, how would dynamically create the @id values, because this will be a changing query depending on user selections.
Something like this (but this, but this doesn't work):
var attributeValues:String = "@id==\"1\" || @id==\"2\" || @id==\"3\" || @id==\"4\"";
xml.Item.(descendants('ProductRange').(attributeValues).length()>0);
Any more thoughts Patrick.. anyone?
Thanks
Solution
For the Or search you can simply do :
xml.Item.(descendants('ProductRange').(@id=="1" || @id=="2").length()>0);
Using a custom filter function you can do your And search that is more complicated than an Or:
var xml:XML=<Items>
<Item name="aaa">
<ProductRanges>
<ProductRange id="1" />
</ProductRanges>
</Item>
<Item name="bbb">
<ProductRanges>
<ProductRange id="2" />
</ProductRanges>
</Item>
<Item name="ccc">
<ProductRanges>
<ProductRange id="1" />
<ProductRange id="3" />
<ProductRange id="2" />
</ProductRanges>
</Item>
</Items>;
function andSearch(node:XMLList, searchFor:Array) {
var mask:int = 0;
var match:int = (1 << searchFor.length ) - 1;
var fn:Function = function(id:String) {
var i:int = searchFor.indexOf(id);
if (i >= 0) {
mask = mask | (1<<i);
}
return mask==match;
}
node.(ProductRange.(fn(@id)));
return mask==match;
}
trace( xml.Item.( andSearch( ProductRanges, ["1", "2"] ) ) );
OTHER TIPS
This may be messy but bear with me:
Items.Item.(
( descendants("ProductRange").@id == "1" || descendants("ProductRange").@id == "2" ) ||
( descendants("ProductRange").@id == "1" && descendants("ProductRange").@id == "2" )
)