Firefox hides the ?xml processing instruction

When I was testing the DOM handling of the XML processing instructions in various browsers, I've found an interesting inconsistency: Internet Explorer includes the <?xml ?> processing instruction in the DOM tree, while Firefox hides it.

For example, when the following XML document ...
<?xml version="1.0" encoding="windows-1250"?>

<?xml-stylesheet href="countryPage.xsl" type="text/xsl"?>

<Test />
... is transformed into a DOM tree and processed with this JavaScript function:
function testPI(dom) {

var topNodes = dom.childNodes;

for (var i = 0; i < topNodes.length; i++) {

var node = topNodes[i];

wr("nodeType="+node.nodeType);

if (node.nodeType == 7) {

wr("PI="+node.target+" ... "+node.data);

}

}
... Internet Explorer generates the following text:
nodeType=7
PI=xml ... version="1.0" encoding="windows-1250"
nodeType=7
PI=xml-stylesheet ... href="countryPage.xsl" type="text/xsl"
nodeType=1
... while Firefox skips the <?xml ?> processing instruction:
nodeType=7
PI=xml-stylesheet ... href="countryPage.xsl" type="text/xsl"
nodeType=1


IP address to physical location mapping

On every web site where I can configure the web server parameters (sadly not available in all hosting environments), I catch the ASP errors (500;100 error page), acknowledge them to the web user and report them in an e-mail to the webmaster (if you can't debug every possible code path, it makes sense to fix the bugs once the first visitor hits them).

Sometimes I would also like to figure out where the visitor causing the ASP error is coming from (more so if the errors are due to lack of resources, indicating unexpectedly high load). The usual tools (nslookup) fail if the ISPs don't enter their IP address space in reverse DNS lookup zones. In the past I've tried to use various Internet registries to figure out who the address is allocated to … and finally I've stumbled on the IP2Location web site, which does exactly what I was looking for: I enter the IP address and it tells me where the visitor is coming from (including a nice overview map for those who have no clue about geography).

Publish code samples in Blogger

Publishing the code samples in Blogger has always been a pain in the ***: the quoting of angle brackets doesn't work very well unless you do it manually, the leading whitespaces get lost (more so if you use spell checker), the line breaks are sometimes lost as well ... Finally I gave up and wrote a small PERL script that takes your code on standard input (usually supplied as a file name in the command line) and leaves the Blogger-ready markup on the clipboard, ready to be inserted in your post:
use strict;
use Win32::Clipboard;

our $lcnt = 0;
our $result = "" ;
our $CLIP = Win32::Clipboard();

while (<>) {
  if (/\n/) { chop; }
  $_ =~ s/\&/&amp;/gi;
  $_ =~ s/\</&lt;/gi;
  $_ =~ s/\>/&gt;/gi;
  while (/^\s/) { $_ =~ s/^(\s*)\s/$1&nbsp;/gi; }
  $result .= ($lcnt == 0 ? "<pre class='code'>" : "\n") ;
  $result .= $_;
  $lcnt ++;
}
$result .= "</pre>";
$CLIP -> Empty();
$CLIP -> Set($result);
print "Result is on the clipboard";

If you're not fluent in PERL, don't even try to understand what it does ... it works :)

Extract the default stylesheet from the DOM document

If you use XSLT transformations to change the XML data into HTML markup and use the xml-stylesheet processing instruction to specify the default XSLT stylesheet to use for the transform, you might need to fetch the default stylesheet value in JavaScript when developing AJAX applications.

You can find a good case study on using XML and XSLT in my Inform-IT article Optimized Presentation of XML Content.


The following JavaScript function extracts the default XSLT stylesheet from the XML document (passed to the function as DOM Document object). It relies on the fact that the DOM Document object extends the Node object and thus has the childNodes property that contains the root element as well as all processing instructions.

function getXMLStylesheet(dom) {

var topNodes = dom.childNodes;

for (var i = 0; i < topNodes.length; i++) {

var node = topNodes[i];

if (node.nodeType == 7) {

if (node.target == "xml-stylesheet") {

var match = /href="(.*?)"/gi.exec(node.data);

if (match.index >= 0) return match[1];

}

}

}

}


A typical usage of this function is illustrated below:
<script src="/sarissa.js"></script>

...

<script>

var xrq = new XMLHttpRequest();

xrq.open("GET","getPI.xml",false);

xrq.send(null);

if (xrq.status == 200) {

var dom = xrq.responseXML;

var xsl = getXMLStylesheet(dom);

alert("stylesheet="+xsl);

}


Constants of the DOM Node object are not implemented in Internet Explorer

The DOM Node object defines a set of constants that can be used to identify the node type. These constants are available in Firefox (and, I would assume, all other Gecko-based browsers), but not in the Internet Explorer. The expression ...

if (node.nodeType == node.TEXT_NODE) { ... }

... which would be largely self-documenting thus has to be written as ...

if (node.nodeType == 3) { ... }

... unless you define the same constants in your JavaScript.

Use JavaScript Progressive Enhancement to simplify HTML table formatting

In the Enrich Your HTML Tables with JavaScript Progressive Enhancement article I wrote for InformIT.com, I'm describing how you can use JavaScript progressive enhancement techniques to add last touches to your HTML table format after the web page has been loaded into the web browser ... and, no, I'm not talking about page layout with tables :), I'm talking about formatting data that deserve tabular format.

Should I encode data as XML attributes or child nodes

This question pops up quite commonly: should I encode my AJAX data as XML attributes or as child tags with actual value in the text of the tag? The answer, as always, depends on your data structure:
  • If your data is simple and non-hierarchical (for example, results of SQL query), using XML attributes will reduce the response size (due to shorter markup)
  • If you have repeating values in your data set, you cannot use attributes, as XML allows only a single attribute with a certain name per tag. In this case, you have to use child tags to encode repeating values. However, you can still transfer the actual value as an attribute of the child tag, not as text in the tag.
  • If you're transfering large character fields, using child tags will increase the readability of the XML response when you're inspecting it with a browser (you know, sometimes we have to do a bit of debugging :)
  • You might hit platform-dependent limitations if you use long attribute values, so yet again you would be better off using child nodes in this case
  • Obviously, you cannot use CDATA section in an attribute, the attribute value has to be properly quoted.

This post is part of You've asked for it series of articles.

How do I use xsl:choose

The Google query strings bringing visitors to my blog are sometimes amazing, like the one in the title of this post. Let's start with a tangential remark: if you're serious about XSLT, you should invest into a good book (XSLT Programmer's Reference is one of the best technical books I've ever read). If, on the other hand, you're just looking for a quick fix, here's the whole story

XSLT does not have if-then-else or select-case constructs like most other languages. You can implement both functions with the xsl:choose element that can take as many xsl:when children as needed. These are evaluated sequentially, the first one that succeeds is executed. You can also use xsl:otherwise as the last child in the list to specify the default behavior.


This post is part of You've asked for it series of articles.

Find processing instructions in XSLT

To get the value of a processing instruction from the input XML document in an XSLT stylesheet, use the /processing-instruction(name) function. I use a username PI in my XML-formatted ASP responses to pass the logged-in user parameters to XSLT, for example ...
<?user Web admin (admin@something.net) {00000000-0000-0000-0000-000000000000}?>
To get this string into an XSLT parameter, I use the following XSLT instruction:
<xsl:param name="username" select="/processing-instruction('user')" />

A processing instruction can appear anywhere in the XML document. To find processing instructions that are not children of the root element, use the appropriate XPath syntax.

You have to use cells array, not DOM children to select table cells

Recently, I wanted to use DOM property firstChild to select the first cell in a TABLE row ... and got quite unexpected results, the firstChild in my case was a text node. Once I've warmed up my grey cells, it all became quite obvious. For example, in the following HTML markup ...
<table>
  <tr id='test'>
    <td>Cell #1</td>
    <td>Cell #2</td>
  </tr>
</table>
... the first child of the TR element is the whitespace between the TR tag and the first TD tag. As the whitespace is allowed in that position by the HTML standard, you cannot rely on the TR.firstChild property. You should use TR.cells[0] to select the first cell.

Introduction to HIJAX

In my Introduction to HIJAX article recently published by InformIT, you'll find a hands-on approach to HIJAX methodology explained step-by-step on a sample application.

How do you write utf-8 data from ASP?

Obviously this is too simple, so it's hard to find an explicit answer in the online documentation:

  • To select the output encoding you want to use in the ASP script, you have to set the response.codepage property or change the per-page default with the @Codepage directive. To use utf-8 encoding, set the response.codepage to 65001.
  • The HTTP Content-type header should match the encoding you're using. Set the response.charset (second part of the content-type header) to "utf-8".
  • If you use META tag in your HTML to set the content-type or encoding attribute in the xml pseudo-instruction, these have to match the HTTP encoding as well. You don't have to specify utf-8 encoding in XML, as it's the default XML encoding.
  • Instead of setting response.codepage in every response, you can set session.codepage at the start of the session.
  • Important: If you use HTML forms, you have to set the @Codepage in all ASP scripts processing the forms or change the AspCodepage metabase property, otherwise the script might misinterpret the input data.

This post is part of You've asked for it series of articles.

Which XML encoding should I use?

The short answer is utf-8. The long answer goes along these lines:

  • utf-8 is the default XML encoding specified by the XML standard. If you use it, you don't have to define the encoding manually, thus reducing the chances of introducing errors. For example, some browsers get confused if the encoding specified in the xml pseudo-instruction is not the same as the one specified in the HTTP header.
  • All XML parsers are required to recognize utf-8 encoding. By using it, you don't risk any future compatibility issues. For example, some of my applications break on some installations of Internet Explorer on Vista as they use windows-1250 encoding. They work fine within IE on Windows XP, Firefox on Vista (and sometimes even with IE on Vista).
  • By using utf-8 you'll never encounter a character you cannot encode.

This post is part of You've asked for it series of articles.

You cannot disable output escaping in Firefox

This is probably well known to all experienced XSLT users, but if this will save a few readers the headaches I've had, it's well worth writing :) In Internet Explorer you can disable output escaping when using XSLT in the browser, thus being able to generate HTML tags from the text content of XML nodes. You cannot do the same in Firefox, as Firefox (or any Gecko-based browser) uses XSLT to transform input tree directly into output (DOM) tree, whereas XSLT transformation in Internet Explorer generates an intermediate string which is later re-parsed into HTML DOM tree.

Firefox does not generate any error when encountering the disable-output-escaping attribute (it's allowed by the XSLT standard) but simply ignores it and inserts the quoted < and > characters into the output stream.

CSV format specifications

If you ever need to know specifics about Comma-Separated-Values (CSV) format, this is probably as good as you'll get. More about using XSLT to generate CSV files in an upcoming post :)