Bookmark this site!

2008-01-20

AJAX demystified: import xml

Here's the barebones of a javascript function that will request xml from a url configured to return xml (text/xhtml+xml or application/xml for example) and then asynchronously add a selected fragment of the returned xml as a child of some node on your page; this target node is selected by id.


function getXML(url, toGet, id){ 
  var request = new window.XMLHttpRequest();
   // for IE use ActiveXObject instead

  function load(){
      var content, node;
      if(request.readyState == 4 &&
         request.status == 200){
         content = document.adoptNode(
           request.responseXML.getElementById(toGet));
         node = document.getElementById(id);
         node.appendChild(content);
    } // should handle null response or failure
  }

  if(request){
      request.open("POST", url, true);
      request.setRequestHeader("Accept","application/xml");
      request.onreadystatechange=load;
      request.send(null);
  }// else ...
}

This will work on a gecko browser, if you have everything set up properly. You'll have to expand it to make it robust, as per the comments (and more).

Example xhtml to call this:

<div id="putInfoHere" />
<span class="button" 
  onmouseup='javascript:getXML(
    "http://my.site.net/contact.xhtml",
    "address",
    "putInfoHere");'>Get Info</span>

The file contact.xhtml should have an element such as <div id="address">...</div> with the matching id. This will be harvested. The clever part is that the harvested code still lives in the correct namespace. So imported markup is correctly interpreted as xhtml.

Make sure files are served with an appropriate mime-type. With apache you can do this using .htaccess :

AddType application/xhtml+xml .xhtml

A future post will have more, on how to send text or xml data to a script using httpRequest with POST instead of GET.

AJAX demystified: import text; async cgi

Here's the barebones of a javascript function that will request text from a url configured to return text (text/plain or text/plain for example) and then asynchronously put the returned text into a textarea element (or any other element with a value field) on your page; this target element is selected by id.

function getText(url, id){ 
  var request = new window.XMLHttpRequest();
  // for IE use ActiveXObject instead

  function load(){
    if(request.readyState == 4 &&
         request.status == 200){
      document.getElementById(id).value
        = request.responseText;
  // should handle null response or failure
  }}

  if(request){
      request.open("GET", url, true);
      request.setRequestHeader("Accept","text/*");
      request.onreadystatechange=load;
      request.send(null);
  } // else ...
}

This will work on a gecko browser, if you have everything set up properly. You'll have to expand it to make it robust, as per the comments (and more).

Example html and javascript to call this (note how the call uses the id of the textarea):

<textarea id="putInfoHere" />
<span class="button" 
  onmouseup='javascript:getText(
    "http://my.site.net/info.txt",
    "putInfoHere");'>Get Info</span>

Make sure text files are served with an appropriate mime-type. With apache you can do this using .htaccess :

AddType text/plain .txt

You can replace info.txt with a cgi script that produces a header and info on stdout. For example (with otherwise pointless sleep to demonstrate asynchrony), put the following mydate.cgi in a cgi-enabled directory:

#!/bin/sh
echo "Content-type: text/plain\n"
date
sleep 2
date

Change the URL in your html accordingly, and make sure your script is executable chmod +x mydate.cgi

A future post will have more, on how to receive xml instead of text and how to send text or xml data to a script using httpRequest with POST instead of GET.

2008-01-15

Mac OS X 10.5: Web Sharing - "Forbidden 403"

In what follows, substitute your short username for myshortname

Create the file
/etc/apache2/users/myshortname.conf
containing the following text:

<Directory "/Users/myshortname/Sites/">
Options Indexes MultiViews
AllowOverride None
Order allow,deny
Allow from all
</Directory>
Set the group and owner as follows:
sudo chown root:wheel /etc/apache2/users/myshortname.conf

Restart apache by switching Web Sharing off then on in System Preferences.