Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jquery Selector using AND multiple siblings

Tags:

jquery

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 ?

like image 318
user3836415 Avatar asked Feb 23 '26 08:02

user3836415


1 Answers

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>

Alternative with iteration

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.

like image 137
trincot Avatar answered Feb 25 '26 22:02

trincot