[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 947
  • Last Modified:

Using JQuery to parse XML

OK - so I've got $(identifier).load working and now I want to manipulate some XML instead using $.ajax

Console is giving me no clues what is wrong with this code:


function getGroups() 
{
	{
		$.ajax(
			{
                type: "GET",
                url: "/client-getSubGroupsOfType.php",
                data: "'ParentGroupID'=26,'TypeID'=25",
                dataType: "xml",
                success: function(xml) {
                	alert('Success!');
                    $(xml).find('Groups').each(function() 
                    {
                        $(this).find('item').each(function() {
                            $('#Groups').append($('<p>' + $(this).attr('Id') + ' - ' + $(this).attr('Name') + '</p>'));
                    });
                });
             },
             error: function() 
             	{
                	 alert('error Groups');
				}
			});
	}
}

$(document).ready(function(){
  getGroups();
  });
;

Open in new window

0
markremms
Asked:
markremms
  • 15
  • 12
1 Solution
 
markremmsAuthor Commented:
Example of the XML returned insode the SOAP envelope

<Groups xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="tns:Group[13]">
	<item xsi:type="tns:Group">
		<GroupId xsi:type="xsd:int">7165</GroupId>
		<ParentGroupId xsi:type="xsd:int">26</ParentGroupId>
		<Name xsi:type="xsd:string">Some Name</Name>
		<Type xsi:type="xsd:string">Some type</Type>
		<TypeID xsi:type="xsd:int">10</TypeID>
	</item>
	<item xsi:type="tns:Group">
		<GroupId xsi:type="xsd:int">7165</GroupId>
		<ParentGroupId xsi:type="xsd:int">29</ParentGroupId>
		<Name xsi:type="xsd:string">Some Other Name</Name>
		<Type xsi:type="xsd:string">Some Other type</Type>
		<TypeID xsi:type="xsd:int">10</TypeID>
	</item>
</Groups>

Open in new window

0
 
markremmsAuthor Commented:
OK - datatype should be "text" not "xml" but that's only part of the story.
0
 
leakim971PluritechnicianCommented:
Test page : http://jsfiddle.net/r70dcaok/

code to use on your side (not "#xml") :
$(xml).find('Groups').each(function() {
    $(this).find('item').each(function() {
        $('#Groups').append($('<p>' + $("groupid", this).text() + ' - ' + $(this).find("name").text() + '</p>'));
    });
});

Open in new window

0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Ray PaseurCommented:
Please see: http://iconoun.com/demo/temp_markremms.php

I think the original SOAP XML document was not valid - it lacked the namespace information.  So I modified it, to remove the attributes.  Here is the server-side script.
<?php // demo/temp_markremms_server.php
error_reporting(E_ALL);

$xml = <<<EOD
<?xml version="1.0"?>
<Groups>
	<item>
		<GroupId>7165</GroupId>
		<ParentGroupId>26</ParentGroupId>
		<Name>Some Name</Name>
		<Type>Some type</Type>
		<TypeID>10</TypeID>
	</item>
	<item>
		<GroupId>7165</GroupId>
		<ParentGroupId>29</ParentGroupId>
		<Name>Some Other Name</Name>
		<Type>Some Other type</Type>
		<TypeID>10</TypeID>
	</item>
</Groups>
EOD;
echo $xml;

// IS THIS VALID XML?
// $obj = SimpleXML_Load_String($xml);
// var_dump($obj);

Open in new window

And on the client side, this seemed to work.
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />

<!-- SEE http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_28509243.html -->

<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
function getGroups(){
    $.ajax({
        type: "GET",
        url:  "temp_markremms_server.php",
        data: "ParentGroupID=26,TypeID=25",
        dataType: "text",
        success: function(xml){
            xmlDoc = $.parseXML( xml ),
            myxml = $( xmlDoc );
            $(myxml).each(function(){
                $(this).find("Groups").each(function(){
                    $(this).find('item').each(function(){
                        $(this).find('GroupId').each(function(){
                            GroupID = $(this).text();
                        });
                        $(this).find('Name').each(function(){
                            Name = $(this).text();
                        });
                        $('#Groups').append($('<p>' + GroupID + ' - ' + Name + '</p>'));
                    });
                });
            });
         }
         ,
         error: function(){
             alert('error Groups');
         }
     });
}

$(document).ready(function(){
    getGroups();
});
</script>

<title>HTML5 Page With AJAX + XML</title>
</head>
<body>

<div id="Groups"></div>

</body>
</html>

Open in new window

0
 
markremmsAuthor Commented:
Thanks both of you.

Ray - I get warnings that my XML is invalid (as you suggested).

It is produced by a NuSOAP server so it's in a full SOAP envelope.  Is that the problem?
0
 
markremmsAuthor Commented:
Here's a SOAP response example.  It has headers which I guess might be a problem. I've cut out a  load of irrelevant stuff but I think the structure is still OK

HTTP/1.1 200 OK Date: Mon, 01 Sep 2014 10:16:16 GMT Server: Apache/2.2.26 (Unix) mod_ssl/2.2.26 OpenSSL/1.0.1e-fips mod_jk/1.2.37 mod_bwlimited/1.4 X-Powered-By: PHP/5.4.26 X-SOAP-Server: NuSOAP/0.9.5 (1.123) Content-Length: 18946 Connection: close Content-Type: text/xml; charset=ISO-8859-1 

<?xml version="1.0" encoding="ISO-8859-1"?><SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tns="http://www.dir.org.uk/server.php?wsdl"><SOAP-ENV:Body><ns1:getSubGroupsOfTypeResponse xmlns:ns1="http://www.dir.org.uk/server.php?wsdl">

<Groups xsi:type="SOAP-ENC:Array" SOAP-ENC:arrayType="tns:Group[13]">
  <item xsi:type="tns:Group">
    <GroupId xsi:type="xsd:int">7165</GroupId>
    <ParentGroupId xsi:type="xsd:int">26</ParentGroupId>
    <Name xsi:type="xsd:string">A Name</Name>
    <Type xsi:type="xsd:string">A type</Type>
    <TypeID xsi:type="xsd:int">10</TypeID>
  </item></Groups>
</ns1:getSubGroupsOfTypeResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

Open in new window

0
 
Ray PaseurCommented:
Now you're undoubtedly starting to understand why some people believe that SOAP is the devil.  I don't go quite that far, but I've always found that RESTful API interfaces are much easier to use.

There is still something wrong with the XML according to Chrome:

Uncaught Error: Invalid XML: <?xml version="1.0" encoding="ISO-8859-1"?>
<SOAP-ENV:Envelope SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w...<omitted>...}
0
 
markremmsAuthor Commented:
Sorry got to dash - will be back in a couple of hours.
0
 
markremmsAuthor Commented:
Yes I'm seeing that error too - is it because of the headers or are they ignored?
0
 
Ray PaseurCommented:
I don't know.  I gave up on SOAP (and especially NuSOAP) because of so many experiences just like this.  Opaque error messages, or useless messages like "Invalid XML" are incredible time-wasters.  And there is one other thing you need to know about PHP SOAP support.  It's not really very good at all.  For but one example, the same tag name in two different namespaces causes a tag name collision.  Leads one to wonder "what are namespaces for?"  This bug has been in the language for several years, suggesting that PHP is never going to fix it.

Do you have any other way to retrieve the data from the API?
0
 
markremmsAuthor Commented:
No I don't - and having spent a fair amount of time (funded by a client) on learning how to deal with SOAP / nuSOAP and building the service I'm pretty committed to it!

I shall have to persevere at least for now I think unless I can provide an equivalent service which is more usable without charging for it.  Using SOAP was my suggestion based upon a bit of reading around -  seemed like the logical thing to use...

If this isn't fixable it's a hard (but useful) lesson to learn!
0
 
Ray PaseurCommented:
Maybe you can use the XML without using the SOAP tags?
0
 
markremmsAuthor Commented:
I was wondering about that -just need to work out how to get rid of them if that's the way forward.  Going to check validity of the XML first though.
0
 
Ray PaseurCommented:
Check this one for an example of the XML without the SOAP tags.
http://www.experts-exchange.com/Programming/Languages/Scripting/AJAX/Q_28509243.html#a40296857

If you have a server-side scripting language that is under your control it may be easy to generate the XML without the SOAP tags.
0
 
markremmsAuthor Commented:
That link seems to be to this question....  infinite loop alert!  :-)
0
 
markremmsAuthor Commented:
I can get nusoap to output json instead - maybe that will improve matters.
0
 
Ray PaseurCommented:
Yes, if you can get a JSON string it might be a much faster path to success!

But that aside, can you help me out about the "infinite loop alert?"  What browser gave that message?
0
 
markremmsAuthor Commented:
Check this one for an example of the XML without the SOAP tags.
http://www.experts-exchange.com/Programming/Languages/Scripting/AJAX/Q_28509243.html#a40296857

Sorry my British sense of humour might not have been direct enough!  The link here is to this page, so if you follow it you arrive back at this page which then has this link..to itself and so on.

Not a browser message - just me trying (and failing!) to be funny.
0
 
Ray PaseurCommented:
Oh, I understand now ;-)  You might be surprised how many in the E-E community don't actually read the posted comments!  And since E-E is making incremental changes to the web platform, I thought there might have actually been a redirect loop or something.  (I'm on the product advisory committee, so I try to look out for things like that).

Irony: the first casualty of the internet.
0
 
markremmsAuthor Commented:
Outputting json instead of XML is straightforward - done it.

Can see the output in chrome but when I call it from javascript I get an empty object.   The browser console also reports the returned page as empty so I think the problem is in the script not the server side stuff.  Any ideas - it's probably something daft?:

function getGroups(){
$.ajax({
        type: "GET",
        url:  "client-getSubGroupsOfType.php",
        data: "ParentGroupID=26,TypeID=25",
        dataType: 'json',
        success: function(data) {
            Groups = data;
            var out = "";
		    var i;
		    for(i = 0; i < Groups.length; i++) {
		        out += '<p>' + Groups[i].GroupID + '&nbsp;' + Groups[i].Name + '</p>';
		    }
            $('#Groups').append($(out));
        }
});
}
$(document).ready(function(){
    getGroups();
});

Open in new window

0
 
markremmsAuthor Commented:
Example json from browsing to the called page
[{"GroupId":7165,"ParentGroupId":26,"Name":"name1","Type":"Type1","TypeID":10,"AdminAddress1":"","AdminAddress2":"","AdminAddress3":"","AdminAddress4":"","AdminPostalTown":"","AdminCounty":"","AdminCountry":"UK","AdminPostcode":"","PhyAddress1":"","PhyAddress2":"","PhyAddress3":"","PhyAddress4":"","PhyPostalTown":"","PhyCounty":"","PhyPostcode":"","Website":"","Email":"","ClericalContacts":[],"CuriaContacts":[],"SGL":-1,"SubGroups":[]},{"GroupId":7169,"ParentGroupId":26,"Name":"name2","Type":"type1","TypeID":10,"AdminAddress1":"","AdminAddress2":"","AdminAddress3":"","AdminAddress4":"","AdminPostalTown":"","AdminCounty":"","AdminCountry":"UK","AdminPostcode":"","PhyAddress1":"","PhyAddress2":"","PhyAddress3":"","PhyAddress4":"","PhyPostalTown":"","PhyCounty":"","PhyPostcode":"","Website":"","Email":"","ClericalContacts":[],"CuriaContacts":[],"SGL":-1,"SubGroups":[]}]

Open in new window

0
 
Ray PaseurCommented:
Let me experiment a bit...
0
 
Ray PaseurCommented:
Try this: http://iconoun.com/demo/temp_markremms.php

<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />

<!-- SEE http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_28509243.html -->

<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
function getGroups(){
    $.ajax({
        type: "GET",
        url:  "temp_markremms_server.php",
        data: "ParentGroupID=26,TypeID=25",
        dataType: 'json',
        success: function(data) {
            Groups = data;
            var out = "";
            var i;
            for(i = 0; i < Groups.length; i++) {
                out += '<p>' + Groups[i].GroupId + '&nbsp;' + Groups[i].Name + '</p>';
            }
            $('#Groups').append($(out));
        }
    });
}
$(document).ready(function(){
    getGroups();
});

</script>

<title>HTML5 Page With AJAX + JSON</title>
</head>
<body>

<div id="Groups"></div>

</body>
</html>

Open in new window

Server side code:
<?php // demo/temp_markremms_server.php
error_reporting(E_ALL);

$jso = <<<EOD
[{"GroupId":7165,"ParentGroupId":26,"Name":"name1","Type":"Type1","TypeID":10,"AdminAddress1":"","AdminAddress2":"","AdminAddress3":"","AdminAddress4":"","AdminPostalTown":"","AdminCounty":"","AdminCountry":"UK","AdminPostcode":"","PhyAddress1":"","PhyAddress2":"","PhyAddress3":"","PhyAddress4":"","PhyPostalTown":"","PhyCounty":"","PhyPostcode":"","Website":"","Email":"","ClericalContacts":[],"CuriaContacts":[],"SGL":-1,"SubGroups":[]},{"GroupId":7169,"ParentGroupId":26,"Name":"name2","Type":"type1","TypeID":10,"AdminAddress1":"","AdminAddress2":"","AdminAddress3":"","AdminAddress4":"","AdminPostalTown":"","AdminCounty":"","AdminCountry":"UK","AdminPostcode":"","PhyAddress1":"","PhyAddress2":"","PhyAddress3":"","PhyAddress4":"","PhyPostalTown":"","PhyCounty":"","PhyPostcode":"","Website":"","Email":"","ClericalContacts":[],"CuriaContacts":[],"SGL":-1,"SubGroups":[]}]
EOD;

// IS THIS VALID JSON?
if ($obj = json_decode($jso))
{
    // WRITE THE RESPONSE
	echo $jso;
}
else trigger_error('[{"Error":"BogusJSON"}]', E_USER_ERROR);

Open in new window

0
 
Ray PaseurCommented:
I can't really test this from the original data source.  Here is the message I get:

XMLHttpRequest cannot load http://url-path-to/client-getSubGroupsOfType.php?ParentGroupID=26,TypeID=25.
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Origin 'http://iconoun.com' is therefore not allowed access.
Am I correct in my understanding that you control the server-side PHP script?  If not, there is a large research project ahead.  If so, read on.

I believe (but cannot test) this.  The PHP server-side script that produces this data needs to send some header() information before writing the JSON string.

header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
header('Access-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization, X-Request-With');
header('Access-Control-Allow-Credentials: true');

Open in new window

0
 
Ray PaseurCommented:
Here is an example of using a proxy.  The client-side script will make the AJAX request to the server-side script on the same "origin" as the script.  The server-side script acts as an intermediary, making an HTTP request, server-to-server, to the true source of the data.

Client-side script:
<!DOCTYPE html>
<html dir="ltr" lang="en-US">
<head>
<meta charset="utf-8" />

<!-- SEE http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_28509243.html -->

<meta name="robots" content="noindex, nofollow" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
<script>
function getGroups(){
    $.ajax({
        type: "GET",
        url:  "temp_markremms_server.php",
        data: "ParentGroupID=26&TypeID=25",
        dataType: 'json',
        success: function(resp){
            Groups = resp;
            var out = "";
            var i;
            for(i = 0; i < Groups.length; i++) {
                out += '<p>' + Groups[i].GroupId + '&nbsp;' + Groups[i].Name + '</p>';
            }
            $('#Groups').append($(out));
        }
    });
}
$(document).ready(function(){
    getGroups();
});

</script>

<title>HTML5 Page With AJAX + JSON</title>
</head>
<body>

<div id="Groups"></div>

</body>
</html>

Open in new window

Server-side proxy script with the true URL obscured:
<?php // demo/temp_markremms_server.php
error_reporting(E_ALL);

// A PROXY TO READ THE DATA - AVOID CROSS-DOMAIN ISSUES

// THE URL TO READ THE REMOTE RESOURCE (NOT THE REAL URL)
$url = 'http://url-path-to/client-getSubGroupsOfType.php';

// THE GET REQUEST
$get = '?';
foreach ($_GET as $key => $str)
{
    $get .= $key . '=' . urlencode($str) . '&';
}
$get = rtrim($get, '&');
$get = rtrim($get, '?');
$url .= $get;
$jso = file_get_contents($url);

// IS THIS VALID JSON?
if ($obj = json_decode($jso))
{
    // WRITE THE RESPONSE
    echo $jso;
}
else
{
    echo htmlentities($jso);
    trigger_error('BogusJSON', E_USER_ERROR);
}

Open in new window

Example in action: http://iconoun.com/demo/temp_markremms.php
0
 
markremmsAuthor Commented:
Ray - you're spot on with that.  Many, many thanks.
0
 
markremmsAuthor Commented:
Ray Paseur is exemplary.  He clearly cares about helping others to learn, takes time to understand and experiment and gives clear, reasoned explanations for his solutions.   He is emphatically not looking for the "quick points" but obviously gets real pleasure from helping complete strangers by offering the benefit of his experience.

Thanks Ray!
0
 
Ray PaseurCommented:
Thanks for the points and thanks for using E-E! ~Ray
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 15
  • 12
Tackle projects and never again get stuck behind a technical roadblock.
Join Now