PM> Install-Package CsQueryUpdate 11/29/2011 - still more features, tests, and so on. The project is nearing release: see new post.
Update 8/2/2011 - more features added, read what's new.
Original Post Below - Contains Outdated Information!
Get CsQuery now on github.
I began this project some time ago as part of a CMS "plug-in" I had developed for an ASP.NET site. That is, the legacy site was in a custom (non-CMS framework) and I was sick of maintaining content, so I developed a quick and dirty CMS around CKEditor.
As a side note about that, in some fantasy world where I have any free time, I look forward to cleaning it up, adding some important security features, and creating a drop-in CMS for any web site - rather than having to use a CMS framework first and developing your site around it. That world is not here today unfortunately.
Anyway - as the content evolved and became more complex, I had to find a way to "activate" it so it could include form controls, postback links, and so on, that would all work within the context of an ASP.NET web site that knew nothing about those HTML content blocks. I had to search for certain tags, change attributes/values, and so on.
This was starting to sound a lot like client-side life with jQuery. I considered using the HTML Agility Pack to parse and deal with the HTML, which I am sure would have done the job just fine - but I had already written a simple HTML parser some time ago for another purpose, and I thought it would be fun to make something that acted like jQuery rather than learning a new, possibly complex piece of software. I am sure I didn't save any time by doing this, but having a good jQuery implementation in C# would open up a lot of possibilities for unifying server and client logic in a web site architecture. So I proceeded.
It's now stable and while certainly not complete, implements many of jQuery's most used features. What's great about it is that you already know how to use it. The syntax is identical with a few exceptions.
Creating a new DOM:
var csq = CsQuery.Create("<html> ... </html>")Selecting:
csq.Select("selector");Chaining:
// Select the 3rd div, and add markup before it csq.Select("div").Eq(2).Before("<span>Hello!</span>");Change something:
// Select the 3rd div, and add markup before it csq.Select("#error_message").Html("You haven't selected anything.");Replace an entire ASP.NET WebForms page with pure HTML and CSQuery:
// no other methods are needed in codebehind. There is no need to use server controls, // you can access and manipulate everything with CsQuery. protected override void Render(HtmlTextWriter writer) { Dom = new CsQuery(); // use included "server" plug-in to obtain HTML from the "render" method Dom.Server().CreateFromRender(base.Render,writer); // Updates dom with values from postback data if (Page.IsPostBack) { Dom.Server().RestorePost(); } // Now, manipulate "Dom" to your heart's content just as you would on the client with jQuery ... // // When done, output it Dom.Server().Render(); }Selectors:
tagname .class #id [attr] attribute exists [attr="value"] attribute equals [attr^="value"] attribute starts with [attr*="value"] attribute contains [attr~="value"] attribute contains word [attr!="value"] attribute not equal (nor does not exist) [attr$="value"] attribute ends with :button type="button" or <button> :checkbox type="checkbox" :text type="text" :file type="file" :checked checked :selected :contains :disabled :enabled :first :last :eq(n) nth matching result :gt(n) :lt(n) :even :odd :has(selector) returns elements that have descendants matching the subselector selectorA, selectorB cumulative selector selectorA selectorB descendant selector selecotrA > selectorB child selectorMethods:
jQuery (create new jQuery object from existing object, HTML, or DOM element(s)) Add AddClass Append AppendTo Attr Before Children Clone Closest Contents Css Data Each (uses delegates - can pass a function delegate or anonymous function) Eq Extend (see update 8/2 for details on how this works in C#) Find Filter First Get Height Hide Html Index (partial) InsertAfter InsertBefore Is Last Next Parent ParseJSON Prev Prop Remove RemoveAttr RemoveClass RemoveData ReplaceWith Show Text Val WidthThere's a growing test suite which is now part of the github project! It includes a bunch of new tests, plus a growing number migrated from the real jQuery test suite.
brilliant! I was wondering if this had been done yet. This is definitely an easy way of selecting/manipulating HTML on server side.. nice work!
ReplyDeleteBe sure to let me know if you use it and have comments! I've started migrating the full jQuery test suite which has resulted in a lot of tweaking (and adding features), and I will be adding some example projects soon. I think it should be possible to use it as a complete replacement for server controls (webforms) or HTML helpers in MVC and let you do really cool things like design entire web sites in clean, semantic HTML and then use this at the back end to manipulate before rendering. So far I've only been using it myself for parsing CMS content, and a few simple things like duplicating button groups on a form, but at this point it's complete & stable enough to be good for about anything. Not to mention web scraping.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteHi,
ReplyDeletefirst of all, congrats and thanks for your work.
I´m using CSQuery to get information of a web. The problem is that the charset for the webpage is in UTF-8 and don't show the char with '´' like é á etc. I changed the charset from the webpage to ISO-8859-1 to spanish and it still don't show. How can I do? Can I change the CSSharp charset?
Thanks,
Juan M Gómez
It should have no trouble with any UTF-8 characters, can you give me some example code that isn't doing what it should? Please contact me directly (jamie@outsharked.com) or post an issue on github. Thanks.
ReplyDeleteHello,
ReplyDeleteI've just used as I need to retrieve an information from an online page.
I works great except except for sub-selecting, example :
var td = cq.Select("#Table2 td:last");
if then you do something like td.Select("[any valid expression]"), it returns the dom elements from the root and not selecting subnodes of the td variable.
That is the correct behavior. Select (and its synonym […]) always works against the whole document like jquery $(...). Use Find() to select from the descendents of an existing selection.
ReplyDeletehey, this is a great library, i'm about to implement it in our project at work. I was wondering if you were planning on adding the $.hasClass() method to this library at any point? It's a small method but I use it so much!
ReplyDeleteThe jQuery API is now completely implemented - this post is pretty old :)
ReplyDelete