tags:

views:

45

answers:

4

Hey there,

I have the following XML:

<?xml version="1.0" encoding="UTF-8" ?>
<text>
    Lorem <foo>ipsum</foo> dolor sit amet.
</text>

and am trying to parse this XML with JQuery and replace the <foo> tags inside the response with <b></b> tags. The resulting string should be "Lorem <b>ipsum</b> dolor sit amet."

I'm doing a GET request on the XML like this:

  $.ajax({
    type: "GET",
    url: "response.xml",
    dataType: "xml",
    success: function(xml){

    }
  });

I've already tried calling the replaceWith function like this:

$(xml).find("foo").replaceWith(function(){
    return "<b>" + $(this).text() + "</b>";
});

But this will remove the text from the xml response completely. Is there something I'm missing?

Edit: Firebug shows the following error:

this[0].innerHTML is undefined

A: 

Try using

return "<b>" + $(this).html() + "</b>";

Instead

Mech Software
+1  A: 

That seems to work for me using the XML string directly in the Firebug console:

var xml = $('<?xml version="1.0" encoding="UTF-8" ?><text>Lorem <foo>ipsum</foo> dolor sit amet.</text>');
xml.find('foo').replaceWith(function(){
  console.log(this);
  return '<b>'+$(this).text()+'</b>';
});
console.log(xml);

What else happens in your success function?

prodigitalson
I just checked it in firebug, it shows me the following error: this[0].innerHTML is undefined. I just do the replaceWith in the success function.
`innerHTML` doesnt work on XML DOMs, only HTML DOMs... If youre trying to do something with `innerHTML` thats your problem right there.
prodigitalson
this does work as string but not when you load the xml
mcgrailm
Ahh, I see... `replaceWith` must be implemented with `innerHTML` modification. Since XML DOM doesnt support `innerHTML` you wont be able to use that function.
prodigitalson
+2  A: 

I'd recommend you use the XML DOM of your web browser rather than abuse jQuery, which was made to handle HTML. Here's how you can parse XML into a DOM:

var xmlDoc;
if (window.DOMParser)
{
    var parser = new DOMParser();
    xmlDoc = parser.parseFromString(xml, "text/xml");
}
else // Internet Explorer
{
    xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
    xmlDoc.async = "false";
    xmlDoc.loadXML(xml); 
}

// Now do the tedious DOM manipulations on xmlDoc
var foos = xmlDoc.getElementsByTagName('foo');
for (var i = 0; i < foos.length; i++)
{
    var oldElem = foos[i];
    var replacement = xmlDoc.createElement("b");
    replacement.appendChild(xmlDoc.createTextNode(oldElem.childNodes[0].nodeValue));
    oldElem.parentNode.replaceChild(replacement, oldElem);
}

Edit

Another possibility is for you to use client-side XSLT to transform the XML into your desired HTML. With an XSLT document like this:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns="http://www.w3.org/1999/xhtml"&gt;

  <xsl:template match="*">
    <xsl:value-of select="."/>
  </xsl:template>

  <xsl:template match="text">
    <span>
      <xsl:apply-templates/>
    </span>
  </xsl:template>

  <xsl:template match="foo">
    <b>
      <xsl:apply-templates/>
    </b>
  </xsl:template>

</xsl:stylesheet>

You can transform your sample input into a span with b tags. If you have lots of transformation rules, XSLT may be more maintainable than a bunch of crummy DOM manipulation code.

Jacob
A: 

jQuery is an HTML-based library and has limited capabilities for dealing with XML (or cross-document scripting in general).

Some methods will work: find() and text() against XML are generally OK. But when you return a markup string like <b>foo</b> jQuery will use that as HTML content, and try to write it to an element's innerHTML. But an XML document isn't HTML, and accordingly doesn't support innerHTML, so jQuery fails.

In any case, you don't want to take an element's text() and use it verbatim as markup. What if that text contains < or & characters? That would break markup and potentially give you cross-site-scripting vulnerabilities. Don't prepare HTML using naïve string-slinging.

Instead, use DOM-style methods. jQuery methods like replace() would do it, however you can't use the simple replace('<b>') because, again, jQuery would take that '<b>' and turn it into an HTML bold element owned by the current HTML document, then try to insert that HTML element into the XML document, which won't work. Instead, you'll need to create the element manually using the XML DOM:

$(xml).find("foo").each(function() {
    var b= xml.createElement('b');
    this.parentNode.replaceChild(b, this);
    while (this.firstChild)
        b.appendChild(this.firstChild);
});

This changes the XML document. But this doesn't really seem to help you if what you're trying to do is convert an XML document into usable HTML. Using a serialiser (browser-dependent) to convert back to XML markup would give markup that isn't necessarily HTML-compatible (eg. empty tags might self-close).

To import XML elements reliably into HTML is probably best done manually. (There is importNode, but IE doesn't support it.) eg.:

function xmlToDocument(node, dest) {
    if (node.nodeType===1) {

        // Create HTML element from XML element. Change name if 'foo'.
        //
        var tag= node.tagName.toLowerCase()==='foo'? 'b' : node.tagName;
        var el= document.createElement(tag);
        dest.appendChild(el);

        // Copy attributes
        //
        for (var attri= node.attributes.length; attri-->0;) {
            var attr= node.attributes[attri];
            el.setAttribute(attr.name, attr.value);
        }

        // Copy element contents
        //
        for (var child= node.firstChild; child!==null; child= child.nextSibling)
            xmlToDocument(child, el);

    }
    else if (node.nodeType===3)
        dest.appendChild(document.createTextNode(node.));
}

You know... it might be easier to just return some HTML markup in a JSON object.

bobince