Parsing XML with CDATA with JQuery
Asked Answered
S

2

6

Edit: I was missing two things here. The lack of "Content-Type:text/xml" in the header returned by the AJAX call was preventing JQuery from treating the returned data as a document. Once that was handled correctly, this code parsed correctly and output just the index and project name.

$("a.getprojects").click(function(d){
  d.preventDefault();
  var api_token = $("#token").val();
  var form_fbod = $("#fbod").val();
  $.post("fbinfo.php", {fbod: form_fbod, token: api_token, cmd : 'listProjects', extra:''}, function(returned_xml) {
    var output = '';
    $(returned_xml).find("project").each(function(){
      var project = $(this);
      output += project.find("ixProject").text();
      output += " ";
      output += project.find("sProject").text();
      output += "\n";
    });
    $("#output").val(output);
  });
});

Original: I'm having fun using the FogBugz API and JQuery to put together what I think will be a cool little tool, but I'm running into a JQuery limitation. CDATA tags seem to confuse it.

Here's the code I'm using:

  $("a.getprojects").click(function(d){
    d.preventDefault();
    var api_token = $("#token").val();
    var form_fbod = $("#fbod").val();
    $.post("fbinfo.php", {fbod: form_fbod, token: api_token, cmd : 'listProjects', extra:''}, function(xml) {
      var output = xml;
      $(xml).find("project").each(function(){
        var project = $(this);
        output += "\n\n";

        output += project.html();

      });
      $("#output").val(output);

    });
  });

And here 's the output I get:

<?xml version="1.0" encoding="UTF-8"?><response>
    <projects>
<project>
<ixProject>2</ixProject>
<sProject><![CDATA[Inbox]]></sProject>
<ixPersonOwner>2</ixPersonOwner>
<sPersonOwner><![CDATA[Rich]]></sPersonOwner>
<sEmail><![CDATA[[email protected]]]></sEmail>
<sPhone></sPhone>
<fInbox>true</fInbox>
<ixGroup>1</ixGroup>
<iType>1</iType>
<sGroup><![CDATA[Internal]]></sGroup>
</project>

<project>
<ixProject>1</ixProject>
<sProject><![CDATA[Sample Project]]></sProject>
<ixPersonOwner>2</ixPersonOwner>
<sPersonOwner><![CDATA[Rich]]></sPersonOwner>
<sEmail><![CDATA[[email protected]]]></sEmail>
<sPhone></sPhone>
<fInbox>false</fInbox>
<ixGroup>1</ixGroup>
<iType>1</iType>
<sGroup><![CDATA[Internal]]></sGroup>
</project>
</projects>
</response>

<ixproject>2</ixproject>
<sproject></sproject>
<ixpersonowner>2</ixpersonowner>
<spersonowner></spersonowner>
<semail></semail>
<sphone></sphone>
<finbox>true</finbox>
<ixgroup>1</ixgroup>
<itype>1</itype>
<sgroup></sgroup>

<ixproject>1</ixproject>
<sproject></sproject>
<ixpersonowner>2</ixpersonowner>
<spersonowner></spersonowner>
<semail></semail>
<sphone></sphone>
<finbox>false</finbox>
<ixgroup>1</ixgroup>
<itype>1</itype>
<sgroup></sgroup>

It would seem that the XML parsing that's native to JQuery discards the contents of CDATA elements. FogBugz puts most of our string data in CDATA tags because we allow special characters and punctuation in most places. Enclosing the output in CDATA tags allows us to rest relatively assured that we're sending back valid data via our API. PHP parsing of the XML works just fine. My research online yields a few people complaining about this, but not much work getting done. With JQuery's extensibility, I would think that there's something out there. Has anyone else accomplished this?

Snowshoe answered 16/3, 2009 at 21:8 Comment(0)
B
14

It would seem that the XML parsing that's native to JQuery

There is no XML parsing native to jQuery. It just uses the standard XMLHttpRequest.responseXML property to get an XML DOM for the response.

discards the contents of CDATA elements

What Content-Type are you sending the response with? Because I suspect it's not being parsed as XML at all. In this case jQuery will be passing you back a string of the document, instead of an XML DOM.

Then when you call “$(xml)”, it will be creating document content from that string(*) — parsed as HTML, not XML. In HTML there is no such thing as a CDATA section, so browsers might discard them, or treat them as comments.

I suspect this because “project.html()” shouldn't actually work when the document is XML. ‘html()’ just returns the same as the standard ‘innerHTML’ property(**), which only works for HTML documents; it is undefined on XML elements.

Enclosing the output in CDATA tags allows us to rest relatively assured that we're sending back valid data via our API.

Well, ‘relatively’: if your data happens to contain “]]>” you still lose. <![CDATA[ sections are intended as a crutch to improve writability for hand authoring; machine-generated XML should really just use entity-encoding in the normal fashion. Usually the server app should be using proper XML tools to generate the response in which case this will be done automatically.

(*: I have never understood when jQuery feels the need to squish document fragment creation and CSS selection into the same function. They're completely different operations which you don't want to get confused, as may have happened here.)

(**: Actually, it tries to filter out jQuery custom attributes first, using a regex. Unfortunately since regex cannot parse HTML, it will happily filter out valid parts of your text that happen to look like HTML attributes. Whoops. Not one of jQuery's prettier parts.)

Birecree answered 17/3, 2009 at 4:2 Comment(1)
Things have changed please update your answer. api.jquery.com/jQuery.parseXMLCheerly
C
6

jquery does in fact have an xml parser now that should solve your problem. $.parseXML(xml) http://api.jquery.com/jQuery.parseXML/

Cheerly answered 30/7, 2012 at 19:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.