Gotta love this error message I got when trying to set a password that was "too long" on Intense Debate:
Sep 16th, 2006 | Web
Nov 16th, 2005 | Marketing
Yesterday when I blogged about simplicity I forgot to mention Clayton Christensen’s take on simple technology. Clayton’s ground-breaking book was entitled "The Innovator’s Dilemma" and is a must-read for any developer who wants to understand the business dynamics between market incumbency and innovative uses of technology.
From his extensive research Christensen states in The Innovator’s Dilemma that disruptive innovations are almost never the result of technological breakthroughs but are instead recombinations of existing and often inexpensive technology in forms the former market leaders don’t pursue. He states the driving reason for the market leaders ignoring disruptive innovations the people in their sales organizations fight against pursuing them because they don’t see big enough market opportunities and/or they can’t make large enough margins compared to their incumbent business. That is, until it’s too late.
Christensen defines disruptive innovations as those "innovations1 that allow small companies to topple once strong, market leading companies and establish themselves as market leaders. His first example was 8" disk drives manufacturers who put out of business all 14" disk drive manufacturers. The latter sold to mainframe vendors at 60% margins, and their customers were interested in larger capacity and faster drives, not in more expensive slower smaller drives with less capacity (which had to be sold at only 40% margins!) But mini-computer manufacturers purchased the 8" disk drives and over time the 8" disk drive manufacturers improved their products to the point of being good enough (key phrase) that mainframe vendors decided to buy from them rather the pay for the increasingly feature rich and increasingly expensive 14" disk drives. At that point, with cost structures requiring 60% margins, the 14" disk drive manufacturers couldn’t maneuver and they all failed.
Examples of recent disruptive innovations with which you might be familiar are:
- Open-source ASP.NET apps and .NET developer tools such as DotNetNuke in the content management space, and NUnit and related for testing tools. Both of these started out much more simple than commercial alternatives, but are evolving.
- Simpler .NET components. Five years ago most components vendors were US-based. Today, the Internet has empowered many vendors outside the US to compete on price alone for the simpler components. One only need look at the number of the vast number of Internet Email Components for .NET to see this trend for what it is.
- Small-project Outsourcing. Another trend near and not-so-dear to many developer’s hearts - outsourcing - is all about being able to offer development services for less. Look at places like RentACoder where you can have small projects developed for literally a tiny fraction of what it would cost to hire a developer in the US to do the same work (smart and entrepreneurial developers should see this as an opportunity rather than a problem…) Today RentACoder’s projects are simple and inexpensive; tomorrow, who knows?
- RSS vs. incredibly fragmented and expensive alternatives to content syndication; RSS is simply XML, after all.
- Wikis, "The simplest thing that could possibly work" according to the Wiki’s inventor Ward Cummingham have edged out many commerical collaboration solutions, and most people say they do it better than what came before.
- MySQL started out as a simple and basic alternative to Oracle, SQL Server, and DB2. When you look at all the people who deployed early versions of MySQL because of its price (optionally free) instead of going with one of the big three, you realized that good enough really was an important concept at play. Now MySQL v5.0 is out and has stored procedures, triggers, views, and more. And if MySQL ever becomes good enough for everybody, Oracle, Microsoft, and IBM can’t compete at their margins.
I could go on, but those should be enough to help you understand the concept if my abstract description wasn’t enough.
Actually, if you think of another example, it would be cool if you would make a comment here and let me and my readers know about it!
1 - Also note that Christensen defined the term "innovation" to encompass a broader scope than just what we think of as technologies. He included business models as innovations too.
What’s the next big thing? AJAX? Ruby on Rails? PC Virtualization? Open-Source Software? Data Security? Open Office File Formats? Windows Vista? Windows Live? Apple’s iWhatever? Yeah, all those things will get lots of hype, but the next big thing is something we’ve had access to all along:
Are my thoughts revolutionary? Nah, I’ve been reading about it at places like Information Week and the other usual suspects. Even Bill Gates at Microsoft gets it, through Ozzie at least (though execution will be the key.) But unlike all that gets hyped, simplicity as a concept that is for real.
Let’s look at two of the best known examples:
- Simple Mail Transfer Protocol.
- Really Simple Syndication.
Over the years, the world’s Internet email infrastructure evolved from that simple little mail transfer protocol (spam and all!) And RSS exploded as a method to syndicate blog posts in a very short order instead of one of the many complex content syndication concepts most of us never even heard of.
To most people the Internet came out of nowhere ten (10) years ago yet it evolved for at least twenty (20) years prior. The Internet’s foundation protocol TCP/IP isn’t exactly simple, but once the simple protocols HTTP and HTML were layered on top, Internet use exploded because implementing websites was simple (by comparison.)
But it’s not just simple technologies, its also simple to install and simple to use applications: ASCII text editors (i.e. Notepad), web browsers, email clients (w/apps like Outlook Express), instant messenger clients, wikis, blogging apps, online forum apps, and QuickBooks (simple is relative; accounting is required yet QuickBooks doesn’t really require accounting expertise.)
And to many people this simplicity makes sense. Scott Cook (founder of Intuit) got it. The founders of the original Instant Messenger (ICQ) got it. Pierre Omidyar (founder of eBay) got it. Google gets it. The original author of PHP Ramus Lerdorf gets it. And a lesser known group also gets it; the developers of Basecamp (although 37 Signals could also be the poster child for when a group elevates a concept to an ideology, and like all ideologists, becomes blind and misinterprets the concept. But I digress…)
Okay this is all obvious, and well, it’s simple. So what’s the big deal? People recognize that simple is important but without a simple roadmap, most don’t know how (pun intended.) I don’t know that I can provide that roadmap, but at least I can get you started.
First, just for grins, let’s look at some counter examples:
- MS-Access – Have you ever tried to develop an app is MS-Access? Yeah right.Access it pretty easy in where it allows you as a user to point and click, but once you hit its brick wall of end user functionality, you’ve got to be an Access guru to do anything more with it.
- VB.NET – Thank god for the My namespace in VB 2005, albeit five years late, but VB.NET is still too damn difficult to use productively without weeks of learning.Don’t get me wrong, I love the power of VB.NET language, but it has very little transitionality.
- ASP.NET – I know its blasphemy, but let’s be real: VIEWSTATE, __doPostBack(), Server Controls, @Register, @Import, WebForms, DataGrid, etc. etc. There’s so much complexity there, where does one start? It’s no wonder so many people still use ASP & VBScript.
- Exchange Server – Oh my god! How complex a beast can you get? Most POP3/SMTP servers use files and directories; Exchange using some bastardization of an Access/Jet database that corrupts whenever the power fluctuates. And have you ever tried implementing server events?
- SharePoint – I can’t even figure out SharePoint as a user, let alone as a developer. What was Microsoft thinking?
- Active Directory – Need I say more?!?
I’ve bashed on Microsoft thus far, but let me not give them all the credit:
- XML, though itself simple, has been complicated with namespaces which I’ve studying for literally years I but still can’t figure out how to use.
- SOAP – Okay, Microsoft was heavily involved here. But why did they have to make web services so hard?I mean, what was wrong with HTTP POST?
- J2EE – There’s a reason J2EE developers get paid the really big bucks.
- Oracle – Have you ever tried to tune an Oracle database application?
- Content Management Systems – Is there anything out that can pass for simple? I’ve been using DotNetNuke on one of my sites for a while and I can tell you, it isn’t.
This brings me to my key point. Aside from being intuitively obvious, what’s so great about simple?
The Benefits of "simple" are, quite simply:
- For the User: Productivity
- For the Platform Provider: Rapid and Widespread Adoption
But you say that all of my counter examples have widespread adoption?
Do not underestimate the institutional will of large organizations to implement tremendously complex technology, because they can.
On the other hand, departmental users, users in small businesses, college students, home users and more can’t deal with complex technology. If it’s too difficult, they don’t or can’t use it. And there are many, many more of them than there are large organizations. What’s more, large organizations are effectively made up of these small groups and individuals. Simple technologies benefit all.
Microsoft, with its Windows monopoly has been able to get away with complexity and consequent low user productivity and low platform adoption with many of its products for a long time. But with the new challenges from Google, SalesForce, et. al. they better get pragmatic religion, and they better get it fast.
And that roadmap to which I referred? To quote Albert Einstein:
As simple as possible, but not simpler
Sep 26th, 2005 | Programming
Esther Schindler who is the editor of the email newsletter DevSource Update recently wrote about Visual C++ and Microsoft’s LINQ Project that adds the ability to use SQL code directly in VB and C# programs (emphasis mine):
Ever since the PDC, developers and the press have been talking about the LINQ technology that Microsoft showed off. The overwhelming response appears to be positive, and from all I can tell (I haven’t taken the time to read the tech docs) it seems to be justified. But I can’t help it if I see the plot holes in a movie, and it’s my job to ask the questions that everybody is trying not to ask. After all, what we saw at the PDC wasn’t a product. It wasn’t even a technology preview. We (rather gratefully) got a peek at what the Smart Folks at Microsoft are scribbling on their white boards. This is the time to point out any problems — when they can be incorporated into the final design documents.
For instance, I carefully noted that, in all the LINQ demos, nobody so much as mentioned C++. (A Microsoft PR person later told me that each language group sets its own priorities, and the Visual C++ team hasn’t decided yet where LINQ will fit.) Also, everybody has asked programmers about the wondrous capabilities of LINQ; what do the DBAs think? I realize that DBAs and programmers rarely drink at the same bars, but still…!
My response to her concerns about LINQ and Visual C++ is:
You should use the right tool for the right job. Anyone programming databases with C++ is almost certainly using the wrong tool. VB.NET and C# are much better tools for doing database development. Hopefully this is so obvious I don’t have to explain why.
She continued with (emphasis mine):
The larger question, though, is about the much-vaunted ability for a Visual Studio programmer to access databases without knowing SQL or XML particularly well. I’m wary of anything that promises “ease of use” by assuring someone that it’s okay to remain ignorant. I remember, far too well, how the computer industry promised to make computers “idiot-proof.” The result? We now have a lot of idiots using computers. Sometimes, making things simpler _isn’t_ a good idea.
I’m not saying that LINQ is a bad thing. Far from it: I suspect it’s an elegant solution of the “Duh, why didn’t we think of this before?” variety. However, this is the time to raise the uncomfortable questions, and I don’t see very many people doing so.
Uh, as far as I can see, LINQ doesn’t hide SQL or XML, it just gives a much cleaner syntax for accessing that can be syntax checked at compile time. A developer would still need to write SQL and to understand XML. For example, this looks like to me it requires knowing SQL:
Dim custs() As Customer = …
Dim waCusts = Select c.Name, c.City From c In custs Where c.State = “WA”
Did Esther really look at LINQ before writing this editorial? Maybe people aren’t asking the questions because the questions are not relevent?
Though my blog has been quiet for several days, it doesn’t mean I haven’t been working on online projects. Since I launched it over a week ago, http://www.dotnetinfluencers.org/ has taken a lot of my time, but it is coming along better than I had hoped for! If you not familiar with what I’m doing over at dotnetinfluencers.org, basically it is a Wiki, but with a twist. Instead of a normal wiki where everyone is encouraged just to write stuff, I’m encouraging people to help me define an XML schema about people, activities, events, and so forth related to .NET programming.
The idea is instead of a lot of writing define a list of properties for each item and then programatically we can generate lists based on those properties. I’m using FlexWiki and it has a language called WikiTalk which we’ll use to process the properties and provide the lists. Just to give you an idea of what I’m talking about, here is most of the actual text at this moment for a Wiki page about MSDN Magazine (the properties are the list of the colons, the values on the right; to understand the rest you’ll need to learn about WikiFormatting):
:Summary: About MSDN Magazine TopicType: DotNetPeriodical PeriodicalPublisher: [CMP] PeriodicalName: MSDN Magazine PeriodicalShortName: [MSDN] PeriodicalEditor: ??? PeriodicalFormerEditors: JoshuaTrupin PeriodicalLanguage: [English] PeriodicalFirstPublished: 2000Mar PeriodicalFormerNames: MicrosoftSystemsJournal, MicrosoftInteractiveDeveloper PeriodicalUrl: http://msdn.microsoft.com/msdnmag/ PeriodicalStatus: [Active]
From the above and numerous other wiki "topics", we can generate an automatic list of periodicals on dotNetInfluencers.org:, and/or many other lists. Now don’t those page properties look suspiciously like attributes or subelements of an XML element? I thought you’d think so… If you haven’t seen dotNetInfluencers.org, check it out. Browse around to get a feel for the site, and then add yourself and/or anything related to .NET. Better yet, if you’d like to help me build this site to the point we can define and public the XML Schema which is the purpose and goal of the site, send an email to mikes (at) xtras.net.
UPDATE: This project is no more and my email address has changed.
Jul 14th, 2004 | Programming
So I just blogged about how I find XSLT somewhat frustrating. Admittedly some of the frustration is based on my relative lack of experience with XSLT. One area ripe with potential frustration is the concept of the node-set data type for which learning has caused me a bit of hair loss recently!
A typical scenario using XSLT is to apply an XSL file as a transform to an XML file to produce output, often HTML. Of course never one to be satisfied with the typical scenario, I found myself compelled to use numerous data sources and even embed XML in my XSL file (For those not familiar with how to pull XML from another XML file, you use the document() function.)
Anywho, while embedding XML, and even when copying subsets of XML documents into variables in my XSL file, I kept running into the dreaded "Expression must evaluate to a node-set" error while trying to access subnodes. For a long time I could not figure out how to get past it.
(BTW, the following assumes MSXML 4.0)
I finally figured out the pattern (I think :). Basically if you "select" a subset from a node-set, you get a node-set, like this:
<xsl:variable name="month-as-node-set" select="$issue-date-as-node-set/IssueDate/Month"/>
However, if you select from a node-set but instead use </xsl:value-of> as a subelement, you get a string, and you can’t later select directly from a string.
<xsl:variable name="month-as-string"> <xsl:value-of select="$issue-date-as-node-set/IssueDate/Month"/> </xsl:variable>
Of course you can use the MSXML-specific node-set() function to convert back to a node-set from a string (As a side note: Why didn’t the XSLT standards committee include such a vital piece of functionality in the standard?!? And be sure to declare the namespace msxsl; for exactly how, see my last example at the bottom of this post):
<xsl:variable name="month-as-node-set" select="msxsl:node-set($month-as-string)"/>
Next, if you want to output the values contained in the XML elements but not any of the markup, any of these will do:
<xsl:value-of select="$month-as-node-set" /> <xsl:value-of select="$month-as-string" /> <xsl:copy-of select="$month-as-string" />
Of course it you actually want the markup output, you need to use <xsl:copy-of> like so (as example where you might want this is if you include HTML markup like < UL> and < LI> inside your XML elements and you want to copy it intact to your output):
<xsl:copy-of select="$month-as-node-set" />
Lastly, you can’t select sub-nodes using a string (which is the reason I was inspired to write this post.) If you try, you get "Expression must evaluate to a node-set.":
<!-- This CRASHES WITH: Expression must evaluate to a node-set. --> <xsl:value-of select="$month-as-string/Name" />
Here’s a complete example which will work with (and otherwise ignore) any XML input file. Note it crashes if the last <xsl:value-of> is not removed:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt"> <xsl:variable name="issue-date-as-string"> <IssueDate> <DayOfWeek> <Name>Wednesday</Name> <Number>4</Number> </DayOfWeek> <Month> <Name>July</Name> <Number>7</Number> </Month> <Day>14</Day> <Year>2004</Year> </IssueDate> </xsl:variable> <xsl:variable name="issue-date-as-node-set" select="msxsl:node-set($issue-date-as-string)"/> <xsl:variable name="month-as-string"> <xsl:value-of select="$issue-date-as-node-set/IssueDate/Month"/> </xsl:variable> <xsl:variable name="month-as-node-set" select="$issue-date-as-node-set/IssueDate/Month"/> <xsl:template match="/"> <html> <body> <table border="1"> <tr> <td> <!– This outputs just "July7" –> <xsl:value-of select="$month-as-node-set" /> </td> </tr><tr> <td> <!– This outputs just "July7" –> <xsl:value-of select="$month-as-string" /> </td> </tr><tr> <td> <!– This outputs just "<Month><Name>July</Name><Number>7</Number></Month>" –> <xsl:copy-of select="$month-as-node-set" /> </td> </tr><tr> <td> <!– This outputs just "July7" –> <xsl:copy-of select="$month-as-string" /> </td> </tr><tr> <td> <!– This outputs just "July" –> <xsl:value-of select="$month-as-node-set/Name" /> </td> </tr><tr> <td> <!– This CRASHES WITH: Expression must evaluate to a node-set. –> <xsl:value-of select="$month-as-string/Name" /> </td> </tr> </table> </body> </html> </xsl:template> </xsl:stylesheet>
If you need more info than I’ve provided here, you can check out Using msxsl:node-set() to Process Result-Tree Fragments on Microsoft’s MSDN website.
I hope those who are stumped as was I by the "Expression must evaluate to a node-set" error are able to locate this post when googling and hence greatly reduce the amount of hair loss they experience while solving this problem!
Jul 14th, 2004 | Programming
I’ve been trying to learn XSLT for a few projects, and I find it both a fascinating and extremely frustrating language! I read about the designers goals (from Michael Kay’s XSLT: Programmer’s Reference) and just shake my head, i.e. : "XSL stylesheets should be human-legible and reasonably clear" and in the next sentence "Terseness in XSL markup is of minimal importance." It seems to be because terseness wasn’t a goal, they decided to see just exactly how verbose they could make it! This IMO directly counters the goal of making it human-legible and reasonably clear!
For example, I wanted to be able to display days as "3rd" and "10th" without having to store the "rd" and the "th" in my data so I decided to write a function (template) called "suffix-day" to do so:
<xsl:template name="suffix-day"> <xsl:param name="day" /> <xsl:variable name="last-digit"> <xsl:value-of select="$day mod 10" /> </xsl:variable> <xsl:value-of select="$day" /> <sup> <xsl:choose> <xsl:when test="$last-digit=1">st</xsl:when> <xsl:when test="$last-digit=2">nd</xsl:when> <xsl:when test="$last-digit=3">rd</xsl:when> <xsl:otherwise>th</xsl:otherwise> </xsl:choose> </sup> </xsl:template>
Of course to call "suffix-day" the XSTL designers wouldn’t have been so forward thinking as to allow syntax such as this:
<xsl:call select="suffix-day($issue-day)" />
Or even this to allow expliticly specifying the parameter name:
<xsl:call select="suffix-day(day:$issue-day)" />
Noooooo, that will not do! It must be VERBOSE or it is not in keeping with the lofty aspirations of XSLT! Instead, we must call it like so!:
<xsl:call-template name="suffix-day"> <xsl:with-param name="day"> <xsl:value-of select="$issue-date" /> </xsl:with-param> </xsl:template>
Or even better, what if we have a template that needs five parameters? Oooh. So instead of:
<xsl:call select="this-little-piggy($market, $stayed-home,$roast-beef, $none,$wee-wee-wee)" />
We’ll get to bask in verbosity with this!:
<xsl:call-template name="this-little-piggy"> <xsl:with-param name="piggy1"> <xsl:value-of select="$market" /> </xsl:with-param> <xsl:with-param name="piggy2"> <xsl:value-of select="$stayed-home" /> </xsl:with-param> <xsl:with-param name="piggy3"> <xsl:value-of select="$roast-beef" /> </xsl:with-param> <xsl:with-param name="piggy4"> <xsl:value-of select="$none" /> </xsl:with-param> <xsl:with-param name="piggy5"> <xsl:value-of select="$wee-wee-wee" /> </xsl:with-param> </xsl:template>
Now now, doesn’t that feel more righteous? I’m just warm and fuzzy, and tingly all over right now. :-)
Okay, I’m probably dead wrong with my criticsm of XSLT. There’s probably many great reasons why it should be verbose and I’m just being ignorant and short-sighted. Normally I never want to come across ignorant or short-sighted and I normally want to be objective and willing to acknowledge when I’m in the wrong.
But not today. I just wanted to vent. No, actually I just want to rant! Rant, rant, rant! So I don’t want to hear it from you why I’m wrong. Go away and leave me alone. Sue me if you don’t like it. :)
Jul 5th, 2004 | Miscellaneous
I’m a categorization junkie. I have always been that way. If I’m interested in something I go out and research ad-nauseum, and then create exhaustive categorized and cross-referenced lists. I think that’s why I like databases and XML and data-driven websites. There’s something fundamentally satisfying about having data in a format that it can be easily sliced and diced, especially when you can be confident the list is incomplete.
Though I have frequently created lists of things and categorized them, with the exception of my business Xtras.Net where we list and categorize 3rd party components and tools for .NET, all of those lists are made at a point in time after which their accuracy fades.
Several years ago I wanted to purchase a loft condo and after several web searches I learned two things about real estate and the web. First agents for the most part don’t get the web, and/or second it is the goal of those in the real estate business to control access to information; too much money is at stake. All I wanted was a comprehesive list of loft condos in Atlanta so I could do my own research before going to see an agent, but such a list was nowhere to be found.
I spent an entire weekend researching the web and came up with a list that I later thought "What the heck, why not put on the web?" You can find that list here: Atlanta Loft Condos. It is now hopelessly out of date, and I keep thinking one day I’ll spend a weekend and update it, but that weekend will probably never come.
Anyway, one of the things that I’d love to have is a good comprehensive list of of what I call ".NET Influencers." That list would include all the activities in which they’ve been involved such as conferences, books, magazine articles, user groups, and so on. Why do I want this? Well, honestly, it just seems like it would be really beneficial to a lot of people, myself included.
For example, a company was were working on a Web Services project where security was extremely important. The project needed to integrate with SQL Server and ASP.NET. They want to develop inhouse, but don’t have time (or realize it would be foolish) for their staff to learn best practices on their own. They could send their staff to training classes, but as a former trainer I know training classes can be a blunt instrument when you need surgical precision. (Trainers don’t get all mad at me; training classes are great when someone needs to learn a broad base but not typically when they have highly specialize learning requirements.)
What if instead they could find someone who specialized in Web Services security, had experience with SQL Server and ASP.NET, who proved their expertise by writing books or magazine articles on the subject, and had their expertise acknowledged by giving sessions at conferences? They could hire that person for a 2-3 day crash-training/consulting project to teach their team best practices specifically for our project. They could pay that person a premium hourly rate, and it would likely be the best consulting money they had ever spent (I know this to be true; around 1997/98 we needed to learn SQL Server so we hired Mike Hotek for a two day consulting job and paid a handsome daily rate. It was definitely the best consulting money we ever spent.)
So who would benefit in the prior scenario? The client company would because they’d get their specific project addressed yet the cost of the consulting plus development would likely be much less than if they learning it on our own or even outsourced it. The expert consultant would also benefit because he would be paid handsomely for his time on a close-ended project without the need to be concern about a non-paying call-back.
In another scenario, imagine a conference promoter is sceduling a .NET-related conference and wants speakers for the hot topics dujour. Rather than just going with the same old people they already know and asking them to whip up something, they could find world-class experts. That would make the conference content tremendous. Who would benefit? Clearly the conference promoter, the newly discovered experts, and most of all, the conference attendees.
I could go on with similar scenarious, but I think you get the picture. I’ve wanted to, for quite a while actually, put together an XML Schema that would allow .NET Influencers to document their "influencial activities." I’ve worked on it on and off for months, but each time I’ve run into road blocks because I’ve not actually used XML enough to intuitively know how to best design a schemas. I’ve spoken with many XML "experts" and several said they were interested in helping, but nothing ever came of it (in one case, I never got around to emailing back…my bad!)
The XML Schema is perfect for this, I believe. Such an XML Schema would allow someone to create and publish what I’ll call an "Influencer Resume" containing a list of all their .NET-related activities (i.e. it should contain everything that would qualify them as an expert in some area of .NET, but not contain that they worked at MacDonalds until they were 18.) Once lots of .NET Influencers created and published their Influencer Resumes, it would give .NET-related websites all over the Internet something else to aggregate making the information searchable and sortable in a variety of ways. Practically everyone would benefit, don’t you think?
Over the holiday weekend I have finally it figured out. How do design the schema that is. I’ve prepared a proof-of-concept, and it is very close to fruition. It could be released to the world within days.
But first, I need some help. I need about ten (10) .NET Influencers to spend about an hour to create a subset (or complete version if possible) of their Influencer Resume and then review what I’ve done in context. A few hours work for you, no more, and when done you’ll have that which you’ve put off for years, that which you need to market yourself; the list of articles your written, conferences sessions you’ve delivered, other things related to .NET you’ve done.
Can you help me out, please? If you don’t think you are one to help with the above but you do have a blog, you can help by blogging a short blog about my need for this help? Or if you know someone who would be a great candidate, email him a link to this post, please. The sooner I can get past proof-of-concept, the sooner this think will see light of day and we’ll all benefit!
Jun 29th, 2004 | Programming
It’s always something!
At Xtras, we have a rather sophisticated email broadcast system that we developed internally. Our system uses a set of tables in our SQL Server database that models the type of email, who it should go to, the mailing lists, etc. It loads each newsletter subscriber’s name and email address using a FOR XML EXPLICIT query from our SQL Server. It uses .XSL files to contain the HTML and/or Text content for each email, and then it uses a System.Xml.Xsl.XslTransform object to generate each HTML/Text email using a transform of the subscriber’s .XML fragment and the current newsletter’s .XSL file. Once generated, it attempts to send using the SMTP component from /n software’s IP*Works!, and logs the success of failure into our database.
It is actually quite an elaborate and powerful system, and my hat’s off to Bill who developed it. However, it isn’t perfect. First, there is very little user interface; "the cobbler’s children go barefoot" as they say. The second is our infrastructure doesn’t contemplate organization of .XSL files; there are literally hundreds all in the same directory. But probably the biggest problem with it has been our approach to creating new email newsletters; we literally copy the XSL file from last newsletter issue and edit it, updating it for the current issue.
Data driven? Automated? Modularized? Yes it is, at least the parts that had to be are data-driven, automated, and modularized. Like inserting the recipient’s email address and sending the emails. But all other parts are manual! Maybe you’ve gotten emails from us in the past where we’ve made errors like having two different dates on the same email in different places? Now you know why…
Recently I grabbed a book on XSLT (Michael Kay’s XSLT: Programmer’s Reference; it’s actually quite good even though it’s four years old by now) and started learning how to write modular XSLT. Of course it has taken longer than I planned so our next newsletter is late (our June newsletter for XDN; anyone notice its really late? Sorry…) I managed to prepare a really elaborate stylesheet and pulled almost all of the content of the newsletter from data in our SQL Server database. I then got the newsletter ready to go and passed it on to Bill to have him send it, and guess what? It blew up his email system, giving code access security errors!
Now you have to know Bill. He is very focused on completing his current projects, so Bill was not happy that my new .XSL blew up his "working" system! But he understood that it would probaby take longer to rewrite than to solve the problem, and it is something we need to solve anyway.
The code access security error took us down the wrong path. What I had added to the XSL file was a call to the XSLT
So the moral of this long-winded story is, if you are using an XslTransform() and you add a reference to the document() function in your .XSL file, you’ll need to add an XmlUrlResolver for it to work. What follows is a self-contained simple example; copy into a class can call that class’ Exec method on a form click event to test (oh, and you’ll need to put an .XML and .XSL file at http://localhost/xslt/ for it to work):
Imports System.XmlImports System.Xml.XPathImports System.Xml.XslImports System.Text.EncodingPublic Class Test Private Const outFile As String = "XsltOutput.html" Public Sub Exec() Dim xslt As New XslTransform xslt.Load(FileUrl("XdnJun2004.xsl")) Dim data As New XPathDocument(FileUrl("Subscriber.xml")) Dim writer As New XmlTextWriter(outFile, UTF8) Dim xmlr As New XmlUrlResolver xslt.Transform(data, Nothing, writer, xmlr) End Sub Private Function FileUrl(ByVal filename As String) As String Dim baseUrl As String = "http://localhost/xslt/" Return CType(baseUrl & filename, String) End FunctionEnd Class
I hope this post finds its way into Google’s index in hopes others with the same problem don’t have to spend as much time as we did trying resolving this problem.