user717236
user717236

Reputation: 5039

Need help forming jquery selector with find and contains, with two conditions

I looked at some other articles here and elsewhere but nothing was exactly what I'm trying to implement.

Please take a look at this xpath query (using mozxpath.js file to clone IE functionality)

var XMLObj.selectSingleNode("/Catalog/Albums/Album/Tracks/Track[../../AlbumNo='" + AlbumNo + "' and ./TrackNo = '" + TrackNo + "']");

How can I convert this expression to jquery?

I tried the following to get me started and it only selects the AlbumNo node:

$(XMLObj).find("AlbumNo:contains(" + AlbumNo + ")", "TrackNo:contains(" + TrackNo + ")");

The xpath expression is looking for the Track node where both conditions are met. How can I rewrite the xpath expression to something jQuery friendly?

Thank you.

Edit

Here is the dumbed-down version of the XML structure:

<Catalog>
  <Albums>
    <Album>
      <AlbumNo>1</AlbumNo>
      <Tracks>
        <Track>
          <TrackNo>1</TrackNo>
        <Track>
          <TrackNo>2</TrackNo>
        <Track>
          <TrackNo>3</TrackNo>
        <Track>
          <TrackNo>4</TrackNo>
        <Track>
          <TrackNo>5</TrackNo>
        <Track>
          <TrackNo>6</TrackNo>
        <Track>
          <TrackNo>7</TrackNo>
        <Track>
          <TrackNo>8</TrackNo>
        <Track>
          <TrackNo>9</TrackNo>
        <Track>
          <TrackNo>10</TrackNo>
        <Track>
          <TrackNo>11</TrackNo>
        <Track>
          <TrackNo>12</TrackNo>
      </Tracks>
    </Album>
  </Album>
</Catalog>

Upvotes: 1

Views: 540

Answers (3)

Felix Kling
Felix Kling

Reputation: 816790

An example of the XML structure would be helpful.

I don't think you can achieve the same with a single selector, you have to use a more complex structure:

$(XMLObj).find('Album').filter(function() { // filter albums by album number
    return !!$(this).find('AlbumNo').filter(function() { 
        return $(this).text() == AlbumNo;
    }).length;
}).find('Track').filter(function() { // filter tracks by track number
    return !!$(this).find('TrackNo').filter(function() { 
        return $(this).text() == TrackNo;
    }).length;
});

It would definitely be easier if the numbers were attributes of the elements and not descendants.

The reason why I use another filter function instead of :contains is that it is the only way you can search for an exact match. :contains will also match if the text you search is only a substring. That is, if you search for track number 1, :contains would also match track number 10, 11, 12, etc.


If you have to do similar things quite often, it might be useful to extend jQuery with a function which filters elements with certain subelements with certain content.

For example:

(function($) {
    $.fn.whichContains = function(element, content) {
        return this.filter(function() {
            return !!$(this).find(element).filter(function() { 
                return $(this).text() == content;
            }).length;
        });
    };
}(jQuery));

which can be used as

$(XMLObj)
  .find('Album').whichContains('AlbumNo', AlbumNo)
  .find('Track').whichContains('TrackNo', TrackNo)

Upvotes: 1

Jasper
Jasper

Reputation: 76003

I've setup a jsfiddle that selects the requested TrackNo element within the requested AlbumNo element: http://jsfiddle.net/jasper/tDhLF/.

Here is the selector I used:

$(xml_string).find('AlbumNo:contains(' + AlbumNo + ')').next('tracks').find('TrackNo:contains(' + TrackNo + ')');

Upvotes: 1

Joseph Marikle
Joseph Marikle

Reputation: 78550

comma deliminators as a means of including other elements requires the comma to be in the quotes:

$(XMLObj).find("AlbumNo:contains(" + AlbumNo + "),TrackNo:contains(" + TrackNo + ")");

Upvotes: 1

Related Questions