Use this function to output the contents of any object in either text or HTML format, depending on the delimiters you pass it, to a nesting depth level you specify.

i.e. document.getElementById("debugP").innerHTML = dump(oWhatever,"Whatever","<br>","&nbsp;",5);

Be warned (as you will if you run this as I paste it in) that a nest level deeper than 5 can take a long time, error out, or crash your browser.

Using HTML as recDelim and aNester is recommended for Gecko browsers, with the innerHTML attribute of a paragraph/div/whatever, but with IE, it likes text ("\n"," ") and the innerText attribute. Not sure why.

On with the code! Enjoy!
Code:
function dump(theItem,theItemName,recDelim,aNester,
      howDeep,begString,endString) {
   dumpDepthCount = 0;
   maxDumpDepth = 5;
   newline = "";
   nester = "";
   debugString = "";
   if (howDeep) {
      if (howDeep > maxDumpDepth) {
         keepItUp = confirm("The debugging function 
         dump() is being called with a greater nest 
         level than is recommended.\nThis may take a 
       while, and it may error out or crash your 
         browser.\nContinue?");
         if (!keepItUp) { 
            return;
         }
      }
      maxDumpDepth = howDeep;
   }
   recDelim ? newline = recDelim : newline = '\n';
   aNester ? nester = aNester : nester = '\t';

   function indent() {
      var retVal = "";
      for (var i=dumpDepthCount; i>1; i--) {
         retVal += nester;
      }
      return retVal;
   }

   function asdlkasf(theItem,theItemName) {
      dumpDepthCount++;
      if (dumpDepthCount >= maxDumpDepth) {
         dumpDepthCount--;
         return;
      }
      var itemType = typeof theItem;
      switch(itemType) {
         case "number":
         case "boolean":
            debugString += indent() + theItemName + 
            ', a ' + itemType + ': ' + 
            theItem.toString().toLowerCase() + newline;
            break;
         case "string":
            debugString += indent() + theItemName + 
            ", a string: '" + theItem + "'" + newline;
            break;
         case "function":
            if (theItem.toString().indexOf(
            'native code]') == -1) {
               indentStr = newline+indent();
               debugString += indent() + theItemName + 
                  ', a function: ' + 
                  theItem.toString().replace(
                     /(\\n|\<br\>)/g, indentStr) + 
                  newline;
            }
            break;
         case "object":
            try {
               debugString += indent() + theItemName + 
                  ', an object' + newline;
               for (att in theItem) {
                  if (att && att != "undefined" && 
                     theItem[att] && 
                     theItem[att] != "undefined" && 
                     att != 'parentNode' && 
                     att != 'offsetParent' && 
                     att != 'ownerDocument' && 
                     att != 'nextSibling' && 
                     att != 'previousSibling') {
                        asdlkasf(theItem[att],att) + 
                           newline;
                  }
               }
            } catch (ex) {
               debugString += indent() + "(" + att + 
                  " inaccessible as object attribute)" 
                  + newline;
            }
            try {
               if (theItem[0]) {
                  debugString += indent() + theItemName 
                     + ', an array' + newline;
                  dumpDepthCount++;
                  for (var i=0;i<theItem.length;i++) { 
                     if (theItem[i]) {
                        if (theItem[i] && 
                           theItem[i] != "undefined") {
                           debugString += indent() + 
                              "Index " + i + newline;
                           asdlkasf(theItem[i],i) + 
                              newline;
                        }
                     }
                  }
                  dumpDepthCount--;
               }
            } catch (ex) {
               debugString += indent() + "(Index " + i 
                  + " inaccessible as array element)" 
                  + newline;
            }
            break;
         case "undefined":
            debugString += indent() + 
               "(type undefined)";
            break;
      }
      dumpDepthCount--;
   }

   if (begString && begString.length > 0) {
      debugString += begString;
   }
   asdlkasf(theItem,theItemName,recDelim,aNester);
   if (endString && endString.length > 0)  {
      debugString += endString;
   }
   return debugString;
}
If anybody can figure out what about this makes IE (6,win2k at least) balk on innerHTML, I'd be much obliged. Thanks!