Saturday, December 22, 2007

TinyMCE, ASP.NET AJAX, and Auto-Save

I'm working on a ASP.NET web app that will allow administration of a new product feature and some of that content can be several paragraphs long. I'm using TinyMCE for those longer pieces and the ASP.NET AJAX Timer control to auto-save the form.

What I noticed is that any field connected to TinyMCE wouldn't be saved on auto-save, but would be saved just fine with a full Save button click and PostBack -- even though the same method was being used.

The details are a little hazy, but there's a layer in TinyMCE that disconnects what you see in your browser as you're typing from the actual textarea. On PostBack, the two were reconnected, but only then. After some searching I found references to TinyMCE's triggerSave() method. So, my hack to deal with this was to add the following immediately after tinyMCE.init():
setInterval("tinyMCE.triggerSave()", 30000);
This will call triggerSave() every 30 seconds. If I find a better way to handle this with the Timer control I'll update this post.

Friday, December 21, 2007

Textml vs. MarkLogic, Part 2

I had a very good conversation yesterday with John Kreisa the Director of Product Marketing for Mark Logic where we talked about the differences between Textml and MarkLogic Server -- the issues I raised in a previous post, plus a few others. One of the other topics that I forgot to mention there and is a huge plus for MarkLogic is the ability to influence relevancy ranking.

The best part of this conversation was that John initiated it. Now, I know it's a minor detail, and maybe even a little silly, but it's nice to know that they're being so proactive. None of the features we talked about may ever be added to the product, but at least I know my voice was heard.

I'm most hopeful that they add a document-focused admin console to the product. So far, it's the one thing I really miss (well, at least since I was able to build my own query parser).

UPDATE: MarkLogic recently released a new, very powerful search library. If you're reading this, you have to check out lib-search.

Thursday, December 20, 2007

ASP.NET TreeNode, Parent of the Selected Node, and RenderPreText

I bumped into something interesting today while working on a TreeView control to be used to represent a book's table of contents on a website. The control had 3 levels: the root, the chapter level, and each major section within each chapter, which we call the "a-head level."

If the user is viewing a piece of content from the a-head level, I was asked to NOT expand the chapter level TreeNode, to apply a different background color to the selected node (the a-head leaf TreeNode), and to apply the same background color to the parent chapter level TreeNode. "Should be fine," I said.

Right. In a Windows form, a TreeNode has a property called BackColor that can be set, but in a Web form, this property is not available. I'm sure there's a good reason for this, but it caught me a bit off-guard ... and much swearing ensued when I realized it.

Long story short, check out Danny Chen's great post on customizing TreeNode controls. This was the first case where I really need to mess with how the .NET framework was rendering HTML.

His post goes into much more detail on what you can do, but my needs were fairly simple. I did take advantage of the lesson to actually set a CSS class rather than just change the background color. Here's the custom TreeNode class I created to set the CSS class for the parent node of the selected node (documentation comments removed for brevity):
public class TreeNodeCustom : TreeNode
private string _CssClass = "";

public string CssClass
get { return _CssClass; }
set { _CssClass = value; }

public TreeNodeCustom() { }

public TreeNodeCustom(string cssClass)
_CssClass = cssClass;

protected override void RenderPreText(HtmlTextWriter writer)
foreach (TreeNode tn in this.ChildNodes)
if (tn.Selected)
writer.WriteFullBeginTag("div class=\"" + CssClass + "\"");

protected override void RenderPostText(HtmlTextWriter writer)
foreach (TreeNode tn in this.ChildNodes)
if (tn.Selected)
And here's how I call it in code when I need it:

TreeNodeCustom chapter = new TreeNodeCustom("customNode");

Visual Studio 2005 Spell Check Now Available

I've been waiting for this for awhile now. There's finally a good spell check tool for Visual Studio 2005 (and 2008) available.

Saturday, December 15, 2007

Fennel and Pepper Biscuits

I love these things.

Proof some yeast for 5-10 minutes.
  • 1 cup warm water
  • 2 tablespoons olive oil
  • 1/4 teaspoon sugar
  • 1 packet of yeast

Put together in a large bowl:

  • 5 cups of all-purpose flour
  • 1 1/4 tablespoons salt
  • 1 tablespoon fennel
  • 1 tablespoon black pepper (or to taste)
  • 1/2 cup olive oil
  • proofed yeast from above

Knead/mix together with a little warm water as needed. When done, let the dough rest for 20-30 minutes. I usually cover it with the same mixing bowl. If it's cold out, give this more time.

Preheat the oven to 425. Bring a large pot of water 3/4 of the way full to a gentle boil.

Cut off pieces of the dough and roll it out like a bread stick. Then connect the ends to form a circle. Be sure this connection is tight. Drop a group of the biscuits into the boiling water. Don't let them stick to the bottom. When they float to the top (this will take only a few seconds), remove them and place them in the oven. I normally place them directly on the racks. As you grab them out of the boiling water, aim for either the connection point or 1/3 of the way passed it because they fall apart easily.

Bake until light brown.

This recipe makes a fair number. I usually place half in a freezer bag in the freezer.

There are some interesting variations of this recipe I've seen over the years.

Tuesday, December 11, 2007

Set an ASP.NET TreeView Node to Expand and not PostBack

A classic small snippet of code that I use infrequently and takes me too long to find when I need it. Here's how to set an ASP.NET TreeView Node to expand and not PostBack when clicked.
tvNode.SelectAction = TreeNodeSelectAction.Expand;

URL Rewriting in ASP.NET with No Code provides a great little tool for URL rewriting in ASP.NET. I used this on a site where SEO was of particular concern. The best part was that it required no code.

Instead of I could enable links like

Here's how I enabled this using Web.config:
<!-- For URLRewriter -->
Intelligencia.UrlRewriter" />


to="~/reader/Default.aspx?id=$1&type=$2" />
to="~/reader/Default.aspx?id=$1&type=$2" />


Validation Controls for Part of a Page in ASP.NET

If there's a set of controls on the page that requires validation, but some other action that may happen that does not require validation (perhaps there's a search box that's part of a MasterPage, but that exists on a page with an email form that should have some validation), set the ValidationGroup property on the validation controls and the button that should fire them to the same value.

Thanks to a co-worker for pointing this out to me before I had to think too hard about it!

Odd and Even Numbers in XSL 1.0

Here's a way to tell if a number is odd or even in XSL 1.0, in this case as part of a snippet of code to switch CSS styles between rows in a search results set.
<xsl:attribute name="class">
<!--returns true for odd counts-->
<xsl:when test="$number mod 2 = 1">highlight</xsl:when>
<!--returns true for even counts-->
<!--<xsl:when test="$number mod 2 = 0">nohighlight</xsl:when>-->

Tuesday, October 30, 2007

PHP Date Math with date() and mktime()

Normal date math in PHP does not account for leap years (or apparently Daylight Savings Time for that matter).

If the current month is January, 2008 and you run
$newMonthText = date("F", mktime(0, 0, 0, date("m")+1, date("d"), date("Y")));
you'll get "March" for the value instead of what you probably want, which is "February." The good people on have lots to say about this. (I think the other condition is that "skipping" Feburary happens only on the 30th or 31st of the current month.)

The way to deal with this is to use
$newMonthText = date("F", mktime(0, 0, 0, date("m")+1, 1, date("Y")));
which will return "February" as intended.

Friday, October 19, 2007

List of APIs

Here's a list of APIs that seems to be updated regularly.

I always feel like I should be doing more to make mashups with these as I work on new products.

Saturday, October 13, 2007

Another Great List of Development Tools

Scott Hanselman has a great list of development tools on his blog. It's so easy to forget about some of these.

Wednesday, October 10, 2007

Web Development Toolbox

Mashable has a very handy list of web devleopment tools. Check it out. They have several other lists on different topics that are equally interesting, too.

Handle All Application Errors, Log Them in Event Viewer, and Show a Friendly Message

I'm working on a simple way in an ASP.NET 2.0 website to 1) catch all application errors that are otherwise uncaught, 2) log these errors in the Event Viewer, and 3) display a friendly error message to the user when these errors occur, while trying to keep this code all in as few places as possible. Here's what I'm doing now. I'll modify this post if I change.

In global.asax I added:
void Application_Error(object sender, EventArgs e)
// Code that runs when an unhandled error occurs
/* Error information will be written to the Event Viewer logs and not displayed
* to the user. The error page will present a friendlier message. */
string fullError = "An error occurred. The page was: " + Request.Url.PathAndQuery + ". " +
"The message was: " + Server.GetLastError().Message + ". " +
"The stack trace was: " + Server.GetLastError().StackTrace + ". ";

/* We don't clear the error here so we can display it on the error page
* when tracing is enabled. The error is cleared there. */

System.Diagnostics.EventLog eLog = new System.Diagnostics.EventLog("Application", ".");
// Application is the log to use, . is the local machine.
eLog.Source = "MyApp";
eLog.WriteEntry(fullError, System.Diagnostics.EventLogEntryType.Error);


In error.aspx I added:
using System.Diagnostics;

public partial class error : System.Web.UI.Page
protected void Page_Load(object sender, EventArgs e)
Trace.Write("ERROR: " + Server.GetLastError().Message);
/* Clear error here, not in Global.asax because
* we want to put it in the trace messages. */

In testerror.aspx, a page that intentionally throws an error to test the setup, I added:

protected void Page_Load(object sender, EventArgs e)
// This throws an exception so we can test logging to the event viewer.
throw (new ArgumentNullException());

Run a VS.NET 2005 Site as a "Root" Site

If you want to run a Visual Studio.NET 2005 website as a root site when debugging or previewing, take a look at Scott Gutherie's post on this. Instead of having your site run as http://localhost:1234/myapp it will run as http://localhost:1234/. Makes life easier when doing relative paths.

By the way, if you're a .NET developer, you should be reading his blog regularly.

Errors with Page Trace Enabled and ASP.NET AJAX

If you have page level tracing enabled on your site and you begin adding ASP.NET AJAX controls, you may see errors that say something along the lines of "Sys.WebForms.PageRequestManagerParseErrorException The message received from the server can not be parsed" when you preview or debug those pages. The ones I experienced appeared in a JavaScript alert popup.

If you have Trace="true" on the page in question, remove it. If you have your web.config file set for tracing, change it to: <trace enabled="true" localOnly="true" pageOutput="false" />

Browse or debug the page and then go to the root of your application's trace.axd file (http://yourapp/trace.axd) to get to the trace information.

See for more.

Tuesday, August 28, 2007

Querying a MarkLogic Server Collection for a Title List, Plus Performance

The real theme of this post is, "Keep it simple, stupid."

I had a query I was using to generate a list of documents stored in a MarkLogic Server collection. The results were being passed to a web application for use as a title list. I was getting the results I wanted, but the query was taking about 20 seconds to complete and there were fewer than 200 book-length XML files to search. The key line in that query was:
for $i in cts:search(//book, cts:collection-query($myCollection))
I knew there had to be a better way to express this, but I couldn't find anything in the API that helped. Then someone suggested using the built-in XQuery function, collection(). I changed the query to...
for $i in collection($myCollection)/book
...and now the query runs in less than .05 seconds, including some trips down into the structure to grab metadata. That's what I was expecting.

Thanks to the people on the Mark Logic developer email list for helping with this.

TortoiseSVN Icon Overlays Disappearing in Windows Explorer

We're using TortoiseSVN as a Subversion client for Windows and it's been great, but the icon overlays that appear in Windows Explorer have suddenly started to disappear. What's really strange is that they may appear at the top-most directory, but disappear when you drill down.

I haven't found the root cause yet, but here's how to get them back.
  1. Open the Task Manager. Find TSVNCache.exe and click End Process.
  2. Shutdown and then restart Windows Explorer. Go to Start > Shutdown. Hold down the Shift+Alt keys and then click the Cancel button. To bring up the Task Manager, hold down the Ctrl+Shift keys and then click Esc. Now, in the Task Manager, go to File > New Task and type in explorer.exe. Supposedly, this is the "proper" way to kill and restart the Windows Explorer process.
Others have reported similar problems. See for one example.

UPDATE: In XP Pro, all I needed to do was end TSVNCache.exe and then I could refresh Windows Explorer and the overlays came back.

Saturday, August 4, 2007

ASP.NET Value of a Month as Text Instead of an Integer

To get the value of a month as text (it's name) instead of an integer use,
string myMonth = DateTime.Now.ToString("MMMM", 
For additional date formatting options, see

Sunday, July 29, 2007

Web Design Toolbox

Mashable had a pretty handy list of web design tools and I'm sure there are plenty more in the comments.

Saturday, June 30, 2007

Install an ASP.NET Assembly into the GAC

To add an assembly to the global assembly cache manually (specifically the ASP.NET AJAX assemply), go to Start > All Programs > Microsoft Visual Studio 2005 > Visual Studio Tools > Visual Studio 2005 Command Prompt. Type the following comman and insert the path/version you have:

>cd C:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX Extensions\[version number] gacutil -i System.Web.Extensions.dll

Declare ASP.NET Controls in web.config Instead of Individual Pages

Instead of declaring controls on individual ASPX pages, declare them once in web.config.

<add tagPrefix="myCompany" src="~/ctl/usercontrol.ascx" tagName="MyControl"/>
<add tagPrefix="otherCompany" assembly="OtherControlAssembly"/>

Monday, June 25, 2007

A$$hole Driven Development

Scott Berkun has a funny post all of the different development methodologies out there. I'd say where I'm working now is somewhere between...
Development By Denial (DBD): Everybody pretends there is a method for what’s being done, and that things are going ok, when in reality, things are a mess and the process is on the floor. The worse things get, the more people depend on their denial of what’s really happening, or their isolation in their own small part of the project, to survive.

Shovel-Driven Development: Get it out the door as quickly as possible, cut-n-paste from anything that you find that works on Google, if it works it’s ready. Closely related to “Duct-tape Driven Design”

…with a healthy smattering of…

Decapitated Chicken Process: A time honored micromanagement technique where each day managers identify a drastic emergency and require developers drop what they are doing (and whatever process they are using) and immediately attend to the latest conflagration. Since this does the double duty of creating new bugs and making other tasks fall behind, fires become easier and easier for managers to spot and then freak out about. Practically a standard in the games industry.

Sad, but true.

Sunday, June 17, 2007

ASP.NET Dynamic Array

This is one approach to creating a dynamic array in ASP.NET:

public string[] CreateArray()
ArrayList myArrayList = new ArrayList();
// Connect to the database and create a data reader (myReader)
while (myReader.Read())
// various lines commented out
myArrayList.Add((string) myReader["name"]);
return (string[])myArrayList.ToArray(typeof(string));

ASP.NET Custom Validator for a Comma Separated List of Email Addresses

In your ASPX page:

<asp:CustomValidator ID="txtToCustom" runat="server" ControlToValidate="txtTo"
Display="Dynamic" ErrorMessage="One of the &quot;To:&quot; email
addresses you provided is not in the proper format or is not separated by a comma."

In your code beside page:

protected void txtToCustom_ServerValidate(object source, ServerValidateEventArgs args)
args.IsValid = ValidateToAddresses(args.Value);

protected bool ValidateToAddresses(string addresses)
string[] myAddresses = Tokenize(addresses);
foreach (string address in myAddresses)
if (!IsEmail(address.Trim())) return false; // If it's not a valid address, return false.
return true; // If none of the addresses returned false, return true.

protected bool IsEmail(string address)
/* This regular expression is provided by the .NET Framework and is the same
* as the one used to check the from address. If that changes for any reason
* this should be updated to match. */
Regex emailRegEx = new Regex(@"\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",
if (emailRegEx.IsMatch(address)) return true;
return false;

protected string[] Tokenize(string addresses)
/* This is pulled out as a separate function because I expect it to mature
* and change over time, and it will probably to move into a class library
* at some point. */
Regex separatorRegEx = new Regex(",");
return separatorRegEx.Split(addresses);

There is at least one very big assumption here: the domains provided by the user are correct. If you'd like to check these, there is a bit of code at that offers an approach.

Also, to do this, you need some sort of approach to string tokenization. Unlike Java, C# does not have any helper classes for this. There are basic approaches to this problem at and

Friday, June 8, 2007

Quck and Dirty MySQL Database Backup

Here is a quick and dirty way to backup a database in MySQL, structure and data included. Run this from the command line, NOT the MySQL Client command line:
C:\Program Files\MySQL\MySQL Server 4.1\bin>mysqldump --user=root 
--password=mypassword --databases mydbname
Of course, this assumes a Windows environment and that the installation directory is the same.

Wednesday, June 6, 2007

Apache Xalan from the Command Line

Check your Xalan environment:

C:\>java org.apache.xalan.xslt.EnvironmentCheck

Set your environment for the proper JARs (check the Apache site for updates):
C:\>set classpath=.;C:\jdk1.2.2\jre\lib\ext\xalan.jar;
Run a basic XSL transformation:

C:\>java org.apache.xalan.xslt.Process -IN c:\tmp\intput.xml -XSL c:\tmp\transform.xsl -OUT c:\tmp\output.xml

Additional command line options:

Common Options

-XSLTC (use XSLTC for transformation)
-XSL XSLTransformationURL
-OUT outputFileName
-V (Version info)
-EDUMP [optional filename] (Do stackdump on error.)
-XML (Use XML formatter and add XML header.)
-TEXT (Use simple Text formatter.)
-HTML (Use HTML formatter.)
-PARAM name expression (Set a stylesheet parameter)
-MEDIA mediaType (use media attribute to find stylesheet associated with a document)
-FLAVOR flavorName (Explicitly use s2s=SAX or d2d=DOM to do transform)
-DIAG (Print overall milliseconds transform took)
-URIRESOLVER full class name (URIResolver to be used to resolve URIs)
-ENTITYRESOLVER full class name (EntityResolver to be used to resolve entities)
-CONTENTHANDLER full class name (ContentHandler to be used to serialize output)

Options for Xalan-Java Interpretive

-QC (Quiet Pattern Conflicts Warnings)
-TT (Trace the templates as they are being called)
-TG (Trace each generation event)
-TS (Trace each selection event)
-TTC (Trace the template children as they are being processed)
-TCLASS (TraceListener class for trace extensions)
-L (use line numbers for source document)
-INCREMENTAL (request incremental DTM construction by setting to true)
-NOOPTIMIMIZE (request no stylesheet optimization proccessing by setting to false)
-RL recursionlimit (assert numeric limit on stylesheet recursion depth)

For more information see

Basic Java Questions and Answers

This is a great list of Java Q & A from a JDJ article. I'm repeating it here because I can never find anything on their site after a month or so.

Q1. How could Java classes direct program messages to the system console, but error messages, say to a file?

A. The class System has a variable out that represents the standard output, and the variable err that represents the standard error device. By default, they both point at the system console. This how the standard output could be re-directed:

Stream st = new Stream(new FileOutputStream("output.txt")); System.setErr(st); System.setOut(st);

Q2. What's the difference between an interface and an abstract class?

A. An abstract class may contain code in method bodies, which is not allowed in an interface. With abstract classes, you have to inherit your class from it and Java does not allow multiple inheritance. On the other hand, you can implement multiple interfaces in your class.

Q3. Why would you use a synchronized block vs. synchronized method?

A. Synchronized blocks place locks for shorter periods than synchronized methods.

Q4. Explain the usage of the keyword transient?

A. This keyword indicates that the value of this member variable does not have to be serialized with the object. When the class will be de-serialized, this variable will be initialized with a default value of its data type (i.e. zero for integers).

Q5. How can you force garbage collection?

A. You can't force GC, but could request it by calling System.gc(). JVM does not guarantee that GC will be started immediately.

Q6. How do you know if an explicit object casting is needed?

A. If you assign a superclass object to a variable of a subclass's data type, you need to do explicit casting. For example:

Object a; Customer b; b = (Customer) a;

When you assign a subclass to a variable having a supeclass type, the casting is performed automatically.

Q7. What's the difference between the methods sleep() and wait()

A. The code sleep(1000); puts thread aside for exactly one second. The code wait(1000), causes a wait of up to one second. A thread could stop waiting earlier if it receives the notify() or notifyAll() call. The method wait() is defined in the class Object and the method sleep() is defined in the class Thread.

Q8. Can you write a Java class that could be used both as an applet as well as an application?

A. Yes. Add a main() method to the applet.

Q9. What's the difference between constructors and other methods?

A. Constructors must have the same name as the class and can not return a value. They are only called once while regular methods could be called many times.

Q10. Can you call one constructor from another if a class has multiple constructors

A. Yes. Use this() syntax.

Q11. Explain the usage of Java packages.

A. This is a way to organize files when a project consists of multiple modules. It also helps resolve naming conflicts when different packages have classes with the same names. Packages access level also allows you to protect data from being used by the non-authorized classes.

Q12. If a class is located in a package, what do you need to change in the OS environment to be able to use it?

A. You need to add a directory or a jar file that contains the package directories to the CLASSPATH environment variable. Let's say a class Employee belongs to a package; and is located in the file c:\dev\com\xyz\hr\ In this case, you'd need to add c:\dev to the variable CLASSPATH. If this class contains the method main(), you could test it from a command prompt window as follows:


Q13. What's the difference between J2SDK 1.5 and J2SDK 5.0?

A.There's no difference, Sun Microsystems just re-branded this version.

Q14. What would you use to compare two String variables - the operator == or the method equals()?

A. I'd use the method equals() to compare the values of the Strings and the == to check if two variables point at the same instance of a String object.

Q15. Does it matter in what order catch statements for FileNotFoundException and IOExceptipon are written?

A. Yes, it does. The FileNoFoundException is inherited from the IOException. Exception's subclasses have to be caught first.

Q16. Can an inner class declared inside of a method access local variables of this method?

A. It's possible if these variables are final.

Q17. What can go wrong if you replace && with & in the following code:

String a=null; if (a!=null && a.length()>10) {...}

A. A single ampersand here would lead to a NullPointerException.

Q18. What's the main difference between a Vector and an ArrayList

A. Java Vector class is internally synchronized and ArrayList is not.

Q19. When should the method invokeLater()be used?

A. This method is used to ensure that Swing components are updated through the event-dispatching thread.

Q20. How can a subclass call a method or a constructor defined in a superclass?

A. Use the following syntax: super.myMethod(); To call a constructor of the superclass, just write super(); in the first line of the subclass's constructor.

Q21. What's the difference between a queue and a stack?

A. Stacks works by last-in-first-out rule (LIFO), while queues use the FIFO rule

Q22. You can create an abstract class that contains only abstract methods. On the other hand, you can create an interface that declares the same methods. So can you use abstract classes instead of interfaces?

A. Sometimes. But your class may be a descendent of another class and in this case the interface is your only option.

Q23. What comes to mind when you hear about a young generation in Java?

A. Garbage collection.

Q24. What comes to mind when someone mentions a shallow copy in Java?

A. Object cloning.

Q25. If you're overriding the method equals() of an object, which other method you might also consider?

A. hashCode()

Q26. You are planning to do an indexed search in a list of objects. Which of the two Java collections should you use: ArrayList or LinkedList?

A. ArrayList

Q27. How would you make a copy of an entire Java object with its state?

A. Have this class implement Cloneable interface and call its method clone().

Q28. How can you minimize the need of garbage collection and make the memory use more effective?

A. Use object pooling and weak object references.

Q29. There are two classes: A and B. The class B need to inform a class A when some important event has happened. What Java technique would you use to implement it?

A. If these classes are threads I'd consider notify() or notifyAll(). For regular classes you can use the Observer interface.

Q30. What access level do you need to specify in the class declaration to ensure that only classes from the same directory can access it?

A. You do not need to specify any access level, and Java will use a default package access level.

Tuesday, June 5, 2007

Installing TortiseSVN after Installing and Configuring WordPress

If you have WordPress installed and running successfully on a Windows server, then you install the TortiseSVN client, and then you export a block of code from Subversion, you may notice that the WordPress admin UI can no longer save edited presentation files. I found that the TortiseSVN install removed the IIS guest user account I had allowed on the themes directory, changing the permissions on that directory back to what they were originally, so it had to be added back to allow access.


Monday, June 4, 2007

Getting a Count of Posts in The Loop in WordPress

I had a hard time finding this information. Here's how you can get a count of the number of posts in your current loop and the index of the current post you're accessing. post_count starts at zero and current_post starts at 1. In this example, I'm outputting a horizontal rule after all posts except the last one in the loop.

/* From */
if( ($wp_query->current_post + 1) < ($wp_query->post_count) )
echo("<hr />");

Thursday, May 31, 2007

Update a Table Based on Values from a Separate Table

Here's a script to update a table based on values from a separate table, where the two tables can be joined by an ID field.
UPDATE destinationtable
SET destinationtable.path = sourcetable.path
FROM sourcetable

Sunday, May 27, 2007

Web Services in PHP 4

I have a situation where I need to use a web service in PHP 4. I found a piece of free PHP code call nusoap and in this site created /lib/nusoap for all of its code. Here are some helpful snippets to access the web service methods and data.
$wsdl = "";
$client = new soapclient($wsdl, 'wsdl');
$proxy = $client->getProxy();
$authResponse = $proxy->authenticate_token(array('token_id'=>$cToken, 'site_code'=>$WS_SITE_CODE));
if($authResponse['authenticate_tokenResult'] == 'true')
setcookie("mytoken", $cToken, 0, "/", "");
// Modified to work on www and non-www usage of the domain.
$authInfoResponse = $proxy->authenticate_passive(array('ip'=>$cIP, 'referrer'=>$cRef));
$authArrayResponse = $authInfoResponse['authenticate_passiveResult'];
$token_id = $authArrayResponse['token_id'];
if ($token_id != "0" && $token_id != "")
setcookie("mytoken", $token_id, 0, "/", "");

Accessing an IxiaDocument Object from Textml in JSP

This is actually split across an application listener object and a JSP view page after a search result item is clicked on, which is why you'll see an Object being pulled from the session. You'll also see a reference to SearchUtilities, a search helper object.
String textmlRmiUrl = "rmi://servername:1099";
String textmlDomain = "DOMAIN";
String textmlUser = "username";
String textmlPassword = "password";
String textmlServer = "servername";
String textmlDocbase = "docbasename";
HashMap parms = new HashMap(1);
parms.put("ServerURL", textmlRmiUrl);
ClientServices cs = com.ixia.textmlserver.ClientServicesFactory.getInstance("RMI", parms); 
cs.Login(textmlDomain, textmlUser, textmlPassword);
// Note that there can be only one login per application
ByteArrayInputStream inputStream = null;
Object sessionResults = session.getAttribute( SearchUtilities.translateTab(tab));
IxiaServerServices ss = cs.ConnectServer(textmlServer); // Get the server Services
IxiaDocBaseServices docbase = ss.ConnectDocBase(textmlDocbase); // then, the DocbaseServices
IxiaSearchServices search = docbase.SearchServices(); // then, the SearchServices
IxiaResultSpace result = null; // then initialize the results space
result = (IxiaResultSpace)sessionResults;
IxiaDocument.Content ixiacontent = result.Item(searchDocId,"highlight").GetContent(); 
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
inputStream = new ByteArrayInputStream(outputStream.toByteArray());
File xslreader = new File(xslpath);
TransformerFactory tFactory = TransformerFactory.newInstance();
Transformer transformer = tFactory.newTransformer(new StreamSource(xslreader));
transformer.setParameter("book",x); // XSL parameter
transformer.transform(new StreamSource(inputStream), new StreamResult(out));

Accessing an IxiaDocument Object from Textml in ASP.NET

Here is just one way to access a Textml IxiaDocument object returned after doing a search.

Various parts of this are wrapped in try/catch blocks and defined in methods as is practical.
IxiaClientServices IxiaCS = new IxiaClientServices();
IxiaServerServices IxiaSS = IxiaCS.ConnectServer(textmlServer);
IxiaDocBaseServices IxiaDS = IxiaSS.ConnectDocBase(textmlDocbase);
IxiaSearchServices IxiaSearchS = IxiaDS.SearchServices;
IxiaQueryAnalyzer TextmlQueryAnalyzer = new IxiaQueryAnalyzer();
String queryEdited = TextmlQueryAnalyzer.GetXMLQueryString(queryWordsAll, "words");
String querySubmitted = textmlStandardHeader +
"<query VERSION=\"3.6\" RESULTSPACE=\"ALL\">" +
"<" + topLevelKey +">" +
textmlCollectionLae +
queryEdited +
"</" + topLevelKey + ">" +
textmlStandardSort +
// Several variables defined elsewhere.
IxiaResultSpace rs = IxiaSearchS.SearchDocuments(querySubmitted); 
// The query is parsed elsewhere
// This section would be part of a loop
IxiaDocument doc = rs.Item(i, "highlight");
// Hits marked with a span of the class "highlight"
MemoryStream xmlStream = new MemoryStream();
xmlStream.Position = 0;
XPathDocument textmlXmlDocument = new XPathDocument(xmlStream);
XslCompiledTransform textmlTransform = new XslCompiledTransform();
textmlTransform.Load(this.Server.MapPath("xsl/" + xslFile));
// xslFile defined elsewhere
StringWriter textmlWriter = new StringWriter();
XsltArgumentList textmlXslArg = new XsltArgumentList();
textmlXslArg.AddParam("documentLink", "", link); // XSL parameters
textmlTransform.Transform(textmlXmlDocument, textmlXslArg, textmlWriter);
divXml.InnerHtml = textmlWriter.ToString();

Friday, May 11, 2007

Building and Iterating Over a LinkedHashMap in Java

Building a Java LinkedHashMap and iterating over it always comes in handy. In a class you can have something like:
private Map myLinks = new LinkedHashMap();
public Map getLinks() {
return myLinks;
public void setMyLinks(String key, String value) {
this.myLinks.put(key, value);
for(int j=0; j<links.getLength(); j++)
setMyLinks( ((Element)links.item(j)).getAttribute("url"),
getText(links.item(j)) );
Then in a JSP you can do something like:
Map thisMyLinks = ThisState.getMyLinks();
for (Iterator it=thisStateLinks.keySet().iterator(); it.hasNext(); )
Object key =;
Object value = thisStateLinks.get(key);
out.println("<li><a href=\"" + key.toString() + "\">" +
value.toString() + "</a></li>");

Thursday, May 10, 2007

Textml vs. MarkLogic, Part 1

I've been working with Ixiasoft's Textml Server for several years now. Recently I've also started working with Mark Logic's MarkLogic Server and I'm starting to notice differences -- some in Textml's favor and some in Mark Logic's favor.

Some of my knocks on MarkLogic compared to Textml are:
  • MarkLogic lacks a query parser. A simple set of expressions should be defined and accepted by a parser -- AND, OR, NOT, a near operator, some sort of frequency and priority operators, would be fine. If you need something more complex then you have to build your own, but give me something. (Truth be told, the one in Textml is a little flaky.)
  • MarkLogic lacks a common way to not index or search stopwords. Add the ability to define a list of stop words on the forest or database level.
  • MarkLogic lacks a document-focused admin interface. Textml's version of this comes in quite handy.
  • MarkLogic lacks result set counts that are both fast and accurate. I should not need to worry about whether I should use xdmp:estimate(), cts:remainder(), or fn:count() to know how many items are in my cts:search(). Just tell me. A database can do it. Textml can do it. MarkLogic needs to as well.
Some of my knocks on Textml compared to MarkLogic are:
  • Textml lacks the ability to accept a large document and search/return only part of it as a result of a search. If I have a book to load, I have to figure out what my display unit in the application is going to be (an entire chapter, a smaller section of a chapter) and break up the file ahead of time. There are all sorts of reasons why that's a problem.
  • Textml lacks XQuery support. I'm just learning XQuery now, but it's pretty darn powerful. Where's the support for it?
  • Textml lacks improvements. Maybe it's just me, but the development of new features seems stagnant.
Bottom line so far: MarkLogic Server is significantly more powerful than Textml Server. MarkLogic is more complex, and therefore more demanding for development, but it has a huge upside.

I'll do another post on this as I learn more about MarkLogic, if necessary.

UPDATE: MarkLogic recently released a new, very powerful search library. If you're reading this, you have to check out lib-search.

Sunday, May 6, 2007

Get a Document's Properties by Attribute Value from MarkLogic Server

Here's a query to get a document's properties from MarkLogic Server using an attribute value. The attribute name is "id" and it is on the node named "document." I used the cts:element-attribute-value-query() function because I can set the case sensitivity and other options. The entire <prop:properties> node is returned.

define variable $myId as xs:string external
(:let $myId := 'ID1234':)

for $i in cts:search(//document,
return $i/property::node()/..

You can pass in a variable from an external app or you can define it in the query using let. You can also tack on some additional metadata, like the URI of the document and any collections it belongs to. Change the return block for this to something like:

{ $i/property::node()/.. }
<uri> { base-uri($i) } </uri>
<collections> { xdmp:document-get-collections(base-uri($i)) } </collections>

Thursday, May 3, 2007

Using cts:search to Search More Than One Node Level in MarkLogic Server

I had a relatively simple requirement for building a search application running against MarkLogic Server: search multiple levels of the XML hierarchy for all files in the repository and return each level as a document; the search must be case and diacritic insensitive. Here's beginnings of the query that did the trick:

define variable $ORIGINAL_QUERY as xs:string external

for $i in cts:search( //(chapter
("case-insensitive", "diacritic-insensitive")

<result id="{ $i/@local-id }">
$i/( content-metadata/title ),
$i/( content-metadata/subtitle ),
$i/( content-metadata/label ),
$i/( head ),
$i/( entry-head ),
$i/( content-metadata/contributor/display-name ),
$i/( content-metadata/copyright/display-date )

There's a lot more work to do on this -- tokenizing words, tokeninzing quoted strings as phrases, accepting Boolean terms, returning different values based on the node, etc., etc., etc.

Thanks to the people on the Mark Logic developer email list for helping with this.

Friday, April 27, 2007

Simple XML Parsing with PHP 4

Here's a very simple way to parse a small XML file with PHP 4 using the DOMXML module. This approach only makes sense since the file I'm working with is very small.
$qsOption = "";

// Make sure the file exists.
if ( !$dom = domxml_open_file("C:\path\to\file\file.xml") ) {
//echo "Error while parsing the document\n";
// We'll exit quietly instead.
$root = $dom->document_element();
$nodes = $dom->get_elements_by_tagname("topic");
$element = new DomElement();
foreach($nodes as $node)
$element = $node;
$qsOption = $qsOption . "<option value=\"" .
$element->get_attribute("tid") . "\">" .
$element->get_content() . "</option>";

PHP .ini File with IIS on Windows Server 2003

I had to install PHP 4 under IIS on Windows Server 2003. The manual installation went fine, but PHP was looking for the php.ini file in C:\WINDOWS. I already added my install directory, C:\php, to the PATH environment variable and rebooted the machine, but this didn't seem to matter.

Buried on one of the many posts on, I found a suggestion that worked. I had to add the following registry key (Start > Run > regedit)...
...with the string value name IniFilePath and the value c:\php. After I did this, I did a hard stop of IIS and restarted it and the change took fine and saw the proper php.ini file.
C:\>iisreset /stop
C:\>net start w3svc

Thursday, April 12, 2007

JavaScript Link to Nowhere

I am completely incapable of remembering this for the rare times I need it.

<a href="javascript:void(0);">my link to nowhere</a>

Wednesday, April 11, 2007

Updating the Noise Word File in SQL Server 2000

I was trying to update two noise word files in SQL Server 2000 today, but there was a file lock holding on tight. The files were:
  • C:\Program Files\Microsoft SQL Server\MSSQL\FTDATA\SQLServer\Config\noise.dat
  • C:\Program Files\Microsoft SQL Server\MSSQL\FTDATA\SQLServer\Config\noise.eng

I stopped all the SQL Server services and the Indexing Service, but the files were still locked. After a little Googling, I found Unlocker, a very handy tool. This told me that the Microsoft Search service had the lock. I used Unlocker to remove the locks, made my edits, and restared all the services (including Microsoft Search for good measure).

Monday, April 9, 2007

Turn Off DTD Validation When Processing an XML File

I've had two situtions recently where I needed to turn off DTD validation before processing an XML file in a .NET app. The ability to do so is in the class library, but there aren't a lot of examples. Here are two ways using two different objects:
XmlDocument doc = new XmlDocument();
doc.XmlResolver = null;
// or
XmlValidatingReader xmlReader =
new XmlValidatingReader(new XmlTextReader(openFileDialog1.FileName));
xmlReader.ValidationType = ValidationType.None;
In the second example, the user was browsing for an XML file on the network and they requested the ability to use a non-validating file for testing purposes.

Friday, March 30, 2007

Query Textml for Documents by Size and Collection

I wanted to search Textml for documents over a certain size and in a particular collection to help track down some problems we were having. Here's a query that does it:
<?xml version="1.0" encoding="UTF-16"?>
<query VERSION="3.6" RESULTSPACE="R1">
<property NAME="Collection">
<property NAME="Size">
<start INCLUSIVE="True">
Note that you can also set the upper limit for the interval by using the <end> element.

Wednesday, March 21, 2007

SELECT Using a Full Text Catalog in SQL Server

This is a pretty simple example. There's a heck of a lot more that you can do.
SELECT Distinct(i.imageFile), i.caption, i.fileID, i.fragmentID, i.path, c.title 
FROM metadata_image AS m JOIN image AS i ON
LEFT JOIN fragments AS c ON i.fragmentID=c.cid
WHERE Contains(i.*, '"some" or "word"') OR
Contains(c.*, '"some" or "word"') OR
Contains(m.*, '"some" or "word"')
ORDER BY c.title, i.caption

ALTER Full Text Catalogs in SQL Server 2005 for Diacritic Sensitivity

Pretty simple:
USE AdventureWorks;

Tuesday, March 20, 2007

SELECT Duplicate Records with Matching IDs

So painfully simple, but I can never remember this when I need it, so here it is!
SELECT l.fileid, l.title, a.title
FROM pub_books AS l
JOIN books AS a
ON l.fileid = a.fileid

Monday, March 12, 2007

"Index was outside the bounds of the array" Error and VS.NET 2005 SP1

After upgrading my Visual Studio.NET 2005 installation to SP1, none of my website applications would publish. Aggravating. I started getting the hideously vague error "Index was outside the bounds of the array." Here are some suggestions on how to handle this problem.

My solution was to go into my Projects/[project name]/ directory and rename the current directory, there from my last Publish run, and then to try and publish it again. This worked for all of my projects.

Monday, March 5, 2007

Set "Week of" Date in PHP

As of this writing, I'm very much a PHP newbie, but here's a snippet for setting a "Week of" date where Monday is zero day and the date format is along the lines of Monday March 5, 2007.

function getWeek()
$today = date("l"); // That's a lower case "L."
$shift = "0";

if($today == "Sunday") $shift = "-6 days";
elseif($today == "Monday") $shift = "0 days";
elseif($today == "Tuesday") $shift = "-1 day";
elseif($today == "Wednesday") $shift = "-2 days";
elseif($today == "Thursday") $shift = "-3 days";
elseif($today == "Friday") $shift = "-4 days";
elseif($today == "Saturday") $shift = "-5 days";

return date("l F j, Y", strtotime($shift, strtotime(date("l F j, Y")))); // "Ls"

echo getWeek();

Thursday, March 1, 2007

Running Apps with Vista

I bought a new machine with Vista but, of course, I have a fair number of apps that I want to install on it. Here's a log.
  • ActivePerl seems to run fine
  • Eclipse ...
  • Java 5 EE displayed a compatibility error before the installer really even began it's work, so I stuck with the Java 6 SE SDK
  • IIS seems fine after I followed the instructions in this article.
  • MarkLogic Server ...
  • Office 2003 seems to run fine, though I don't use Outlook
  • Sam Spade ...
  • Subversion and TortiseSVN seem to run fine
  • Visual Studio.NET 2005 needs to run in compatibility mode and as an administrator
  • UltraEdit 8.10 needs to run in compatibility mode and as an administrator
  • Windows Updates
    • After running a truck-load of updates and restarting, a driver compatibility warning comes up and even throws a blue screen of death for the Sonic Solutions DLA. Roxio says it's Dell's problem because it's a Dell machine with an OEM version. Dell says it's Roxio's problem. In any case, Roxio has a solution for it which seems to work.
  • XMLSpy 2006 Home Edition seems to run fine, although it did try to call home after registering and while I started it up the first time
To switch to a compatibility mode and/or run as an administrator, do the following.
  • After install, right-click on the app icon, switch to the Compatibility tab
  • Check the compat. mode checkbox and switch the drop-down to Windows 2000 (or whatever is appropriate for you)
  • Check the run as admin checkbox
  • After this, you should be able to enter your authorization info.

Monday, February 26, 2007

phpMyAdmin and the "Client does not support authentication" Error

When you see the following error...
#1251 - Client does not support authentication protocol requested by server; consider upgrading MySQL client
...there is a problem with the password you created for a user. You'll need to run...
mysql> SET PASSWORD FOR 'username'@'host' = OLD_PASSWORD('password');
See for more information.

Friday, February 23, 2007

Firefox and Internet Explorer Development Tools

I always lose this, so here's the list of Firefox extensions I'm using
  • DOM Inspector
  • Firebug
  • Flashblock
  • Header Monitor
  • Live HTTP Headers
  • Web Developer
  • XML Developer Toolbar

On Internet Explorer, I have the IE Developer Toolbar

Tuesday, February 20, 2007

View Results from the Textml QueryAnalyzer Object

I wasn't sure if I had an error in my code or if I uncovered a bug in Textml's QueryAnalyzer, so I wrote a little ASP.NET page where I could pass in a search string and see what QueryAnalyzer would do with it. This is how I found the bug with their .NET implementation of the choice operator.

Here are the ASPX and C# files
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="QueryAnalyzer.aspx.cs"
Inherits="QueryAnalyzer" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"

<html xmlns="" >
<head runat="server">
<title>QueryAnalyzer Test Page</title>
<form id="form1" runat="server">
<asp:TextBox ID="txtQuery" runat="server"></asp:TextBox>
<asp:Button ID="btnRun" runat="server" Text="Run" /><br />
<div id="divQuery" runat="server"></div>
<div id="divError" runat="server"></div>


using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using Ixiasoft.TextmlServer;
using Ixiasoft.TextmlServer.Tools;

public partial class QueryAnalyzer : System.Web.UI.Page
protected void Page_Load(object sender, EventArgs e)
if (Page.IsPostBack)
divError.InnerHtml = "";
divQuery.InnerHtml = "";
IxiaQueryAnalyzer TextmlQueryAnalyzer = new IxiaQueryAnalyzer();
string queryEdited =
TextmlQueryAnalyzer.GetXMLQueryString(txtQuery.Text, "words");
divQuery.InnerHtml = HttpUtility.HtmlEncode(queryEdited);
catch (Exception ex)
divError.InnerHtml += "<br />" + ex.ToString() +
"<br />" + ex.StackTrace.ToString() +
"<br />Passed to QueryAnalyzer: " +

Wednesday, February 14, 2007

Searching Textml for Words with Tildes

Document searches in Textml are insensitive to case and ... in most cases ... special characters. For example, searches for "José Martí" and "jose marti" should return the same results set in the same order. But there is at least one exception to this, ñ. A search for "quinceañera" will return a different set of results when compared to "quinceanera." Ixiasoft has reported this is a feature based on requests from their Spanish-speaking partners and customers, which make sense because the two are different characters in the Spanish alphabet.

One solution is to add a hidden element to the document that contains the alternate spelling.

Another solution is to use the <oneof> element. To do this you would intercept each word at the application level and modify words with "ñ" or "n." That part of the query might look something like this:
If you have to support this particular feature, neither solution is very palatable.

UPDATE 1: If you try and pass the choice operator to the Textml QueryAnalyzer object in .NET, it will throw an exception. quincea[n,ñ]era as a search string will fail. I've submitted this bug to Ixiasoft and I'm waiting for a response.

UPDATE 2: Ixiasoft has responded that this is a bug and is due to be released in their newest package,

Sunday, February 11, 2007

Determine the Encoding of an XML File: Method 1

In Visual Studio 2003, I needed a way to determine the encoding of an XML file. I found some information about reading the byte order mark (BOM) on a file, but I couldn't get it to work properly. The alternative approach below seems to be working. In this example, I needed the file to be UTF-8.
String encoding = DetectEncodingXml(); 
if(encoding.IndexOf("UTF-8") > -1)
/* This is what we want. Run the code. */
/* Display error message. */
private string DetectEncodingXml()
XmlTextReader xreader = new XmlTextReader(openFileDialog.FileName);
Encoding xreaderEnc = xreader.Encoding;
string xreaderEncString = xreaderEnc.EncodingName;
return xreaderEncString;
catch(Exception ex)
return " Encoding could not be detected. ";

Friday, February 9, 2007

Getting the ASPX File Name

I only used this once, and quickly changed my approach so I didn't need to rely on it, but here's how you can get the name of the ASPX file you're viewing.
string pageName = this.Page.GetType().Name.Replace("_", ".");
Of course, there's also

Transforming XML with XSL: Method 1

There are several ways to transform an XML document with XSL. This is one approach that includes passing parameters to the XSL and assumes the transformation is targeted for a <div> element. You'll need the following namespaces added, assuming this is an ASP.NET website: System.IO, System.Xml.Xsl, System.Xml.XPath. This should be wrapped in a try/catch block.
XPathDocument xpathDocument = new XPathDocument(this.Server.MapPath("/xml/test.xml"));
XslCompiledTransform xpathTransform = new XslCompiledTransform();
StringWriter xpathWriter = new StringWriter();
XsltArgumentList xslArg = new XsltArgumentList();
xslArg.AddParam("path", "", imgPath); /* imgPath defined elsewhere */
xslArg.AddParam("country", "", country); /* country defined elsewhere */
xpathTransform.Transform(xpathDocument, xslArg, xpathWriter);
divXml.InnerHtml = xpathWriter.ToString(); /* divXml is a control on the ASPX page */

UPDATE: Why would you need this approach versus using the Xml control? I ran into a situation where some legacy XSL used the document() function and called a file on the network. I needed to 1) use impersonation and 2) set XmlSetting when I called Load().

Tuesday, February 6, 2007

Set Selected DropDownList Item By Value

Given an ASP.NET DropDownList control and a value, you can set the selected item in that list if the value exists. There are a couple of ways to do this, but this approach takes into consideration that the value may not be found in the list.

This is an example of what you could have on an ASPX page:
<asp:DropDownList ID="ddlDb" runat="server">
<asp:ListItem Value="all" Selected="True">All</asp:ListItem>
<asp:ListItem Value="opt1">Option One</asp:ListItem>
<asp:ListItem Value="opt2">Option Two</asp:ListItem>
This is an example of how to set the selected item:
ListItem li = ddlDb.Items.FindByValue("opt1");
if (li != null) ddlDb.SelectedIndex = ddlDb.Items.IndexOf(li);
Another method is below, but it will throw System.ArgumentOutOfRangeException if the value is not found:
ddlDb.SelectedValue = "opt1";

Sunday, February 4, 2007

Random Table Background Image

This was a quick hack for a friend to get a random background image set for a table. You should be able to add this just about anywhere in the <body> tag. This would also work just for a table cell.

<script language="javascript">
onload = function() {
/* If you change the directory, make sure you update it here. */
var imageDirectory = "";
/* If you want to add more images on your own, put the the file name in the middle
of the list here. Make sure there are quotes around it and a comma at the end. */
var imageArray = new Array("image3.gif",
var imageArrayLength = imageArray.length; // Leave these next few lines alone
var pseudoRandomNumber = ( Math.round( Math.random() * (imageArrayLength - 1) ) );
document.getElementById("tableImage").style.backgroundImage="url('" +
"imageDirectory + imageArray[pseudoRandomNumber] + "')";
<style type="text/css">
#tableImage {

<table id="tableImage" height="431" width="465">
<tr><td> </td></tr>

UPDATE: This is OLD. You should look for a better solution.