I'm trying to figure out how to do a selection using an AND operator with sibling nodes. I have the following XML :
<PRODUCT>
<TYPE>CAR</TYPE>
<PRICE>23.42</PRICE>
<COLOR>BLUE</COLOR>
<DOORS>5</DOORS>
<CATEGORY>
<ITEM>23</ITEM>
</CATEGORY>
</PRODUCT>
<PRODUCT>
<TYPE>VAN</TYPE>
<PRICE>23.42</PRICE>
<COLOR>YELLOW</COLOR>
<DOORS>4</DOORS>
<CATEGORY>
<ITEM>23</ITEM>
</CATEGORY>
</PRODUCT>
<PRODUCT>
<TYPE>CAR</TYPE>
<PRICE>23.42</PRICE>
<COLOR>GREEN</COLOR>
<DOORS>4</DOORS>
<CATEGORY>
<ITEM>24</ITEM>
</CATEGORY>
</PRODUCT>
<PRODUCT>
<TYPE>CAR</TYPE>
<PRICE>80.00</PRICE>
<COLOR>BLUE</COLOR>
<DOORS>5</DOORS>
<CATEGORY>
<ITEM>26</ITEM>
</CATEGORY>
</PRODUCT>
I want to select all the products that have Type of Car, doors as 5 and Category.Item as 23. I'm trying to do this without having to manually run a foreach loop, is there a selector that can achieve this ?
There is no solution with only jQuery selectors, mainly because the jQuery :contains selector also matches substrings. If that is not an issue for you then this will do what you want:
var match = $(xml).has('>type:contains("CAR")')
.has('>doors:contains("5")')
.has('>category>item:contains("23")');
var xml = `<PRODUCT>
<TYPE>CAR</TYPE>
<PRICE>23.42</PRICE>
<COLOR>BLUE</COLOR>
<DOORS>5</DOORS>
<CATEGORY>
<ITEM>23</ITEM>
</CATEGORY>
</PRODUCT>
<PRODUCT>
<TYPE>VAN</TYPE>
<PRICE>23.42</PRICE>
<COLOR>YELLOW</COLOR>
<DOORS>4</DOORS>
<CATEGORY>
<ITEM>23</ITEM>
</CATEGORY>
</PRODUCT>
<PRODUCT>
<TYPE>CAR</TYPE>
<PRICE>23.42</PRICE>
<COLOR>GREEN</COLOR>
<DOORS>4</DOORS>
<CATEGORY>
<ITEM>24</ITEM>
</CATEGORY>
</PRODUCT>
<PRODUCT>
<TYPE>CAR</TYPE>
<PRICE>80.00</PRICE>
<COLOR>BLUE</COLOR>
<DOORS>5</DOORS>
<CATEGORY>
<ITEM>26</ITEM>
</CATEGORY>
</PRODUCT>`;
var match = $(xml).has('>type:contains("CAR")')
.has('>doors:contains("5")')
.has('>category>item:contains("23")');
xmlResult = $('<div>').append(match).html();
console.log(xmlResult);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
To deal with the limitations of the above solution, and only accept exact text matches, you'll need to iterate, for instance using filter:
var match = $(xml).filter(function () {
return $(this).find('>type').text() == 'CAR' &&
$(this).find('>doors').text() == '5' &&
$(this).find('>category>item').filter(function () {
return $(this).text() == '23';
}).length > 0;
});
var xml = `<PRODUCT>
<TYPE>CAR</TYPE>
<PRICE>23.42</PRICE>
<COLOR>BLUE</COLOR>
<DOORS>5</DOORS>
<CATEGORY>
<ITEM>23</ITEM>
</CATEGORY>
</PRODUCT>
<PRODUCT>
<TYPE>VAN</TYPE>
<PRICE>23.42</PRICE>
<COLOR>YELLOW</COLOR>
<DOORS>4</DOORS>
<CATEGORY>
<ITEM>23</ITEM>
</CATEGORY>
</PRODUCT>
<PRODUCT>
<TYPE>CAR</TYPE>
<PRICE>23.42</PRICE>
<COLOR>GREEN</COLOR>
<DOORS>4</DOORS>
<CATEGORY>
<ITEM>24</ITEM>
</CATEGORY>
</PRODUCT>
<PRODUCT>
<TYPE>CAR</TYPE>
<PRICE>80.00</PRICE>
<COLOR>BLUE</COLOR>
<DOORS>5</DOORS>
<CATEGORY>
<ITEM>26</ITEM>
</CATEGORY>
</PRODUCT>`;
var match = $(xml).filter(function () {
return $(this).find('>type').text() == 'CAR' &&
$(this).find('>doors').text() == '5' &&
$(this).find('>category>item').filter(function () {
return $(this).text() == '23';
}).length > 0;
});
xmlResult = $('<div>').append(match).html();
console.log(xmlResult);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Note the inner filter: all category items need to be inspected, not only the first.
Remark: the sample XML is not really valid XML as it does not have a single root node. It would be better to call it an XML fragment. To be valid you would need to wrap it in a tag, like <PRODUCTS>...</PRODUCTS>. Then of course the above solutions would look slightly different.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With