2

Given some sample data.xml file:

<?xml version="1.0" encoding="utf-8"?>
<data>
    <categories>
        <category id="google">
            <name>Google</name>
        </category>
    <categories>
    <display>
        <categories>
            <category idref="google"/>
        </categories>
    </display>
</data>

And some jquery code to fetch the data.xml file:

$.ajax( {
    url: '/data.xml',
    dataType: 'xml',
    success: function( data )
    {
        $data = $( data );
        // fetch categories to display
        $categories = $data.find( 'display > categories > category' );
    }
} );

What is a efficient and compact method to resolve the category elements to which the fetched elements in $categories refer to by their idref attribute?

I've come up with something like the following:

$categories.each( function() {
    var $category = $data.find( 'categories > category[id=' + $( this ).attr( 'idref' ) + ']' );
} );

But I thought there might be a more compact way of collecting the elements.

Decent Dabbler
  • 22,532
  • 8
  • 74
  • 106

2 Answers2

2

You can create id selectors from the idref attributes:

var referenced = $.unique($categories.map(function() {
    var $found = $data.find("#" + $(this).attr("idref"));
    return ($found.length ? $found[0] : null);
}).get());

The code above uses map() and $.unique() to build an array containing unique instances of all the referenced <category> elements.

Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
  • @Tomalak, I'm pretty sure it works with all well-formed XML documents, yes. I created a simple test fiddle [here](http://jsfiddle.net/fhamidi/f7v2J/) and the id selector works for me. – Frédéric Hamidi Aug 28 '11 at 11:57
  • This is very nice also. And of course you can simply create id selectors as well. Why didn't I think of that? ;-) – Decent Dabbler Aug 28 '11 at 12:18
  • @fireeyedboy This is nicer than mine, if it is faster remains a matter of testing. Probably not, in the long run, but depending on your file sizes the difference may be insignificant. – Tomalak Aug 28 '11 at 12:21
  • @Tomalak: Speed is not really an issue for me in this case anyway. But yeah this is a bit cleaner. Although I liked your generic approach. What I want to do now (only just occurred to me) is merge both your ideas in a method to extend jQuery, so I can do something like `$categories.resolveIdRefs()`. Because of this, I don't think I can use `map()` and `unique()`. Maybe I'll start a new question on that, if I don't manage to get it to work. Thank you to the both of you so far! – Decent Dabbler Aug 28 '11 at 12:30
1
var $data = $( data );
var $byId = {};

$("*[id]", $data).each(function () {
  var $this = $(this);
  $byId[ $this.attr("id") ] = $this;
});

// later...
$byId["google"].find("name");  //  <name>Google</name>
Tomalak
  • 332,285
  • 67
  • 532
  • 628