I have been trying the fantabulous CsQuery library, which is basically a .NET port for jQuery allowing the use os CSS selectors and most of jQuery’s functionalities.
I am using it to parse and edit a batch of HTML files (particularly, editing some attributes of different DOM elements).
The following C# snippet shows sort of what I’m doing, with the JavaScript/jQuery equivalent code in the comments.
FileStream doc = File.Open(/*some html file*/);
CQ dom = CQ.Create(doc); // $dom = $(document);
CQ images = dom.Select("img"); // $images = $('img');
images.Attr("src","#"); // $images.attr('src','#');
dom.Save(/*Output path*/); // No jQuery equivalent, this just saves the file.
This works perfectly: if I check the output file, all the image’s src values are now #.
Anyway, if I use the Each block (which seems to work nicely using C# lambda expressions to simulate javascript’s function passing) the changes won’t apply to the output file:
FileStream doc = File.Open(/*same html file*/);
CQ dom = CQ.Create(doc); // $dom = $(document);
CQ images = dom.Select("img"); // $images = $('img');
images.Each( (element) => { // $images.each( function(){
CQ cqElement = CQ.Create(element); // $element = $(this);
cqElement.Attr("src","#"); // $element.attr('src','#');
Messagebox.Show(cqElement.Attr("src")); // alert($element.attr('src'));
}); // });
dom.Save(/*Output path*/); // No jQuery equivalent, this just saves the file.
Despite the Messabox showing “#” for every image in my DOM (which means that the cqElement gets the change), the output file doesn’t get the changes.
I think the key line causing the problem is CQ cqElement = CQ.Create(element); since it creates a brand new CsQuery object. In fact, if just after the first Messagebox I pop up another one like the following one, it will not have the changes made to the cqElement
Messagebox.Show(dom.Html()); // alert($dom.html());
Any idea on how could I solve this issue?
You’re absolutely right:
CQ cqElement = CQ.Create(element)is the problem. This is at the core of the most siginficant difference between CsQuery and jQuery. With jQuery, there’s only one DOM. With CsQuery, there’s no browser, so there can be any number of distinct DOMs. Each time you useCreateit’s a brand new DOM; whereas jQuery methods/selectors return a newCQobject bound to the same DOM.The correct way to “wrap” a DOM element as a
CQobject like$(element)is withnewand notCreate, e.g.There’s also a shortcut that’s a method on
IDomObject:These keep the element in the same DOM. The
Createmethods always produce a new DOM, and when created from elements, actually clones them so the original DOM is not affected. (Elements can only belong to a single DOM; if you were to create two different DOMs and add elements from one to another using a method likeAppend, they would be removed from the source.Createautomatically clones them.).I am sure this could be made more clear in the documentation 🙂