jQuery: The Write Less, Do More JavaScript Library

XML Serializer

By Mark Gibson

Description

Serialize DOM elements as an XML fragment.

Usage

To serialize an element:

var xmlString = $('#something').toXML();

Returns a string containing the serialized XML representation of the element.

Source

jQuery.fn.toXML = function () {
    var out = '';
    if (this.length > 0) {
        if (typeof XMLSerializer == 'function' ||
            typeof XMLSerializer == 'object')
        {
            var xs = new XMLSerializer();
            this.each(function() {
                out += xs.serializeToString(this);
            });
        } else if (this[0].xml !== undefined) {
            this.each(function() {
                out += this.xml;
            });
        } else {
            // TODO: Manually serialize DOM here,
            // for browsers that support neither
            // of two methods above.
        }
    }
    return out;
};

Notes

If the jQuery object holds several elements, the output will NOT be a valid XML Document, as it will have multiple root nodes. If you must have a valid document ensure you limit to a single element in the chain before calling toXML(), eg:

$('.something').eq(0).toXML();

This plugin is not widely tested yet, and will not work at all in browsers that don't support XMLSerializer, or the .xml property. (I think these need to be identified before implementing the fallback serialization routine).

Several suggestions were made on the mailing list for alternative ways to implement this. One was to partially implement XMLSerializer if it doesn't exist - I've decided against this - as I believe if we were to follow that route, then any implementation of XMLSerializer should be feature complete - but we don't really need things like serializeToStream() in this situation.

Tested In

  • Firefox 1.5.0.7 / 2.0
  • Opera 9.02

Note: Doesn't work in IE(6)

Extended for IE

Added the missing code for generating xml code with IE. Just handling attributes, elements and text. The nodetypes 4-12 are just added as nodeValue. Tested with IE7.

jQuery.fn.toXML = function ()
{
  var toXML = function(node)
  {
    var out = '';
    var attributes = '';
    var content = '';
    out += '<' + node.nodeName;
    if (node.childNodes)
    {
      for (var i = 0; i < node.childNodes.length; i++)
      {
        switch(node.childNodes[i].nodeType)
        {
          case 1:     // ELEMENT_NODE
            content += toXML(node.childNodes[i]);
            break;
          case 2:     // ATTRIBUTE_NODE
            attributes += ' ' + node.childNodes[i].nodeName  + '="'
                              + node.childNodes[i].nodeValue + '"';
            break;
          case 3:     // TEXT_NODE
          case 4:     // CDATA_SECTION_NODE
          case 5:     // ENTITY_REFERENCE_NODE
          case 6:     // ENTITY_NODE
          case 7:     // PROCESSING_INSTRUCTION_NODE
          case 8:     // COMMENT_NODE
          case 9:     // DOCUMENT_NODE
          case 10:    // DOCUMENT_TYPE_NODE
          case 11:    // DOCUMENT_FRAGMENT_NODE
          case 12:    // NOTATION_NODE
            content += node.childNodes[i].nodeValue;
            break;
        }
      }
    }
    out += attributes;
    if (content.length > 0)
    {
      out += '>' + content;
      out += '</' + node.tagName + '>';
    }
    else
    {
      out += '/>';
    }
    return out;
  }
  var out = '';
  if (this.length > 0) {
    if (typeof XMLSerializer == 'function' ||
        typeof XMLSerializer == 'object')
    {
      var xs = new XMLSerializer();
      this.each(function() { out += xs.serializeToString(this); });
    }
    else if (this[0].xml !== undefined)
    {
      this.each(function() { out += this.xml; });
    }
    else
    {
      if (this.length > 0)
      {
        this.each( function() { out += toXML(this); } );
      }
    }
  }
  return out;
};