Jquery parse xml with name spaces


I

ianB

I am trying to get two values from a web service response.

The web service was called using jquery $ajax:

$.ajax({
url : "http://localhost:3032/ufs/integration/
copymoveTerm",
type : "POST",
dataType : "xml",
data : soapEnv,
success : undoSuccess,
failure : showError,
contentType : "text/xml; charset=\"utf - 8\""
}); // end move AJAX call


And this is the response I get:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://
www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<res:Response xmlns:res="http://www.ebasetech.com/
LADRA_COPYMOVE_TERM_OP/Response">
<res:OUTPUT>
<res:UNDO_COUNT>1.0</res:UNDO_COUNT>
<res:MSG>Undo complete (No more to undo)</res:MSG>
</res:OUTPUT>
</res:Response>
<res:OUTPUT xmlns:res="http://www.ebasetech.com/LADRA_COPYMOVE_TERM_OP/
Response"/>
</soap:Body>
</soap:Envelope>



All I want to do is to get the values of UNDO_COUNT and MSG into
separate variables.

Here is the jquery I am trying to use:

function undoSuccess(xmlData, status, xmlResponse)
{
$(xmlResponse).find('res:OUTPUT').each(function () {
var undoCount = $(this).attr('res:UNDO_COUNT).text();
var msg = $(this).attr('res:MSG).text();
});
}

I have tried it with and without the name space "res:".
I have tried it with xmlData and with xmlResponse
I have tried changing the web service so that UNDO_COUNT and MSG were
elements in their own right or were attributes of OUTPUT all without
success it just bypasses the initial find on OUTPUT.

Any pointers please, I just don't see where I'm going wrong

Thanks

IanBram
 
Ad

Advertisements

A

Andreas Bergmaier

Am 26.02.2011 18:02 A.D., schrieb ianB:
The web service was called using jquery $ajax:

$.ajax({
url : "http://localhost:3032/ufs/integration/
copymoveTerm",
[...]
}); // end move AJAX call
I have tried ...
elements in their own right or were attributes of OUTPUT all without
success it just bypasses the initial find on OUTPUT.

What happens instead?

I'd guess a conflict with the Same origin policy, just as you're trying
to load from localhost.

thinks
Bergi
 
R

RobG

I am trying to get two values from a web service response.

The web service was called using jquery $ajax:

         $.ajax({
            url : "http://localhost:3032/ufs/integration/
copymoveTerm",
            type : "POST",
            dataType : "xml",
            data : soapEnv,
            success : undoSuccess,
            failure : showError,
            contentType : "text/xml; charset=\"utf - 8\""
         }); // end move AJAX call

And this is the response I get:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3..org/2001/XMLSchema-instance">
<soap:Body>
<res:Response xmlns:res="http://www.ebasetech.com/
LADRA_COPYMOVE_TERM_OP/Response">
<res:OUTPUT>
<res:UNDO_COUNT>1.0</res:UNDO_COUNT>
<res:MSG>Undo complete (No more to undo)</res:MSG>
</res:OUTPUT>
</res:Response>
<res:OUTPUT xmlns:res="http://www.ebasetech.com/LADRA_COPYMOVE_TERM_OP/
Response"/>
</soap:Body>
</soap:Envelope>

All I want to do is to get the values of UNDO_COUNT and MSG into
separate variables.

Here is the jquery I am trying to use:

function undoSuccess(xmlData, status, xmlResponse)
{
    $(xmlResponse).find('res:OUTPUT').each(function () {
        var undoCount = $(this).attr('res:UNDO_COUNT).text();
        var msg = $(this).attr('res:MSG).text();

You seem to have unbalanced quotes, which should generate a syntax
error before the code even runs.

I would use getElementsByTagNameNS, but haven't used it for some time
so would have to go back and bone up on it again.
 
T

Thomas 'PointedEars' Lahn

ianB said:
I am trying to get two values from a web service response.

The web service was called using jquery $ajax:

$.ajax({
url : "http://localhost:3032/ufs/integration/
copymoveTerm",
type : "POST",
dataType : "xml",
data : soapEnv,
success : undoSuccess,
failure : showError,
contentType : "text/xml; charset=\"utf - 8\""

I doubt that there should be spaces around the `-'. And why would you not
simply use the apostrophe as string literal delimiter, so that you can write
the value verbatim? Or, better yet, omit the inner quotes as they are
optional?
}); // end move AJAX call


And this is the response I get:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://
www.w3.org/2001/XMLSchema-instance">
<soap:Body>
<res:Response xmlns:res="http://www.ebasetech.com/
LADRA_COPYMOVE_TERM_OP/Response">
<res:OUTPUT>
<res:UNDO_COUNT>1.0</res:UNDO_COUNT>
<res:MSG>Undo complete (No more to undo)</res:MSG>
</res:OUTPUT>
</res:Response>
<res:OUTPUT xmlns:res="http://www.ebasetech.com/LADRA_COPYMOVE_TERM_OP/
Response"/>
</soap:Body>
</soap:Envelope>

All I want to do is to get the values of UNDO_COUNT and MSG into
separate variables.

Here is the jquery I am trying to use:

function undoSuccess(xmlData, status, xmlResponse)
{
$(xmlResponse).find('res:OUTPUT').each(function () {
var undoCount = $(this).attr('res:UNDO_COUNT).text(); ^
var msg = $(this).attr('res:MSG).text(); ^
});
}

I have tried it with and without the name space "res:".
I have tried it with xmlData and with xmlResponse
I have tried changing the web service so that UNDO_COUNT and MSG were
elements in their own right or were attributes of OUTPUT all without
success it just bypasses the initial find on OUTPUT.

Any pointers please, I just don't see where I'm going wrong

First of all, your source code is syntactically invalid; two string literals
are unfinished. Any decent error console would have told you this, so I am
assuming this is just another posting typo.

Therefore, the first thing that is wrong with your code is that you are
applying find() on $(xmlResponse) instead of $(xmlResponse.responseXML).
Surprisingly, jQuery is not able to handle its own response object.


However, your main problem is that you are using jQuery (I have tested with
the latest version 1.5.1). Usually at this point I only write "jQuery is
junk" (which is true, see also [1]) and be done with it, but this particular
problem merits further analysis.

jQuery.find("res:OUTPUT") calls Document::getElementsByTagName("res") (as
neither Expr.leftMatch.ID nor Expr.leftMatch.CLASS or Expr.leftMatch.NAME
would match, but Expr.leftMatch.TAG does; no efficient alternation there, it
really is a guessing game for jQuery/Sizzle *every* *single* *time*) instead
of the proper Document::getElementsByTagNameNS("http://…", "OUTPUT"). This
is due to the fact that `:' in jQuery selectors is seen as an indicator for
a pseudo-class, which causes it to temporarily ignore what follows,
considering what comes before to be an element type name (or in jQuery
speak, a TAG).

Sizzle allows to use "res\\:OUTPUT" to work around that self-inflicted
ambiguity (there really was not if jQuery could tell names from element type
names apart, using unambiguous syntax with an API that deserves to be called
that).

But if one uses Document::getElementsByTagName(), it is not properly defined
which elements are found in a namespaced context (DOM Level 1 methods are
said to be namespace-ignorant, but implementations vary).

So jQuery.find("OUTPUT") works in Chromium 9.0.597.98 (WebCore 534.13), but
not in Iceweasel 3.6.8 (Gecko 1.9.2.8). Apparently WebCore really is
namespace-ignorant then, while Gecko requires the element to be either in a
default namespace or in no namespace.

jQuery.find("res\\:OUTPUT") works in Gecko, but not in WebCore as, even
though the element name passed to Expr.find.TAG() clearly contains a `:'
(indicative of a namespaced QName), getElementsByTagName() is used anyway.

Anyhow, in at least one browser that jQuery claims to support there is no
such element in that XML document. So the jQuery.each() method is invoked
(as always, thanks to the mindless chaining approach), but it finds the
Array that it should iterate over empty.

Now, this is rather unsurprising coming from an individual who dares writing
books containing utter nonsense such as this:

| Since valid HTML is simply as subset of XML, having an efficient way to
| parse and browse DOM documents is absolutely essential for making
| JavaScript development easier. […]
-- Resig, John: "Pro JavaScriptâ„¢ Techniques", Apress, 2006, p. 8 [2]

(No, HTML is _not_ a subset of XML! HTML4 is an application of SGML, XML is
a subset of SGML, and XHTML is an application of XML. [HTML5 is tag soup].)

Further, `res:UNDO_COUNT' and `res:MSG' are _not_ attributes of
`res:OUTPUT'; they are _child elements_. As a result, you cannot retrieve
their text content with jQuery in a cross-browser way (same problem as
before).

Let us take a moment to review this. The advertisement for jQuery reads:

| jQuery
| write less, do more.

Write less? Granted. Do more? No, it does less (than would have been
possible using a better approach. See below for an example.)

| jQuery is a new kind

New kind? No, there have been other monolithic approaches before. All of
them are failures.
of JavaScript

John Resig only thinks he knows what JavaScript is.

Library? It is a monolithic blob, *one* script. Isn't that some kind of a
library: If you want one book, you have to borrow all shelves. I hope your
bag is large enough ;-)

| jQuery is a fast

Negative.

| and concise

In what?

| JavaScript Library that simplifies HTML document traversing,

Ah, not XML? Then why all the (nonfunctional) XML handling code in jQuery?

| event handling,

Facilitated by augmenting a host object, a practice known to be error-prone.

| animating,

I think I can do better. Time will tell.

| and Ajax interactions

With few exceptions, I have done better already. Many other people, too.
Can we can agree on that using polling timers where event listeners are
universally supported is a brain-damaged approach?

| for rapid web development.

As in "coding without knowing what one does"; a recipe for disaster.

| jQuery is designed to change the way that you write JavaScript.

True. It serves well as bad example.

| Lightweight Footprint

Negative. I have to include up to 83 KiB for only the basic features, as
processing gzip-compressed resources is not universally supported.

| CSS3 Compliant

Negative. CSS3 supports XML namespaces. jQuery evidentially does not.

| Cross-browser

Negative. It is evidentially not even compatible across two browsers.

I can only strongly suggest to replace jQuery at least for finding the
element, and to use the proper DOM Level 3 XPath or ─ as a fallback ─ MSXML
XPath approach instead. Assuming `xmlResponse' refers to an object
implementing the XMLDocument interface:

var namespaces = {
res: "http://www.ebasetech.com/LADRA_COPYMOVE_TERM_OP/Response"
};

var doc = xmlResponse.responseXML;
var xpathExpr = '//res:OUTPUT';
if (jsx.object.isMethod(doc, "evaluate"))
{
var nsResolver = function(prefix) {
return namespaces[prefix] || null;
};
var result = doc.evaluate(xpathExpr, doc, nsResolver,
XPath.ORDERED_NODE_ITERATOR_TYPE, null);

var node;
while ((node = result.iterateNext()))
{
/*
* Function expression to have some jQuery equivalence,
* however misguided that might be.
*/
(function() {
var undoCount = doc.evaluate('.//res:UNDO_COUNT/text()', node,
nsResolver, XPathResult.STRING_TYPE);

var msg = doc.evaluate('.//res:MSG/text()', node,
nsResolver, XPathResult.STRING_TYPE);
}());
}
}
else if (jsx.object.isMethod(doc, "selectNodes"))
{
result = doc.selectNodes(xpathExpr);
for (var i = 0, len = result.length; i < len; ++i)
{
var node = result;
var undoCount =
node.selectNodes('.//res:UNDO_COUNT/text()').nodeValue;
var msg = node.selectNodes('.//res:MSG/text()').nodeValue;
}
}

As a result of your posting, I have updated
<http://PointedEars.de/scripts/xpath.js> to use XmlNode::selectNodes()
if Document::evaluate() is unavailable, so that you should be able to solve
your problem with

var result = jsx.xpath.evaluate('//res:OUTPUT', doc,
jsx.xpath.getCustomNSResolver(namespaces));

in all major runtime environments.

`result' would be a reference to an Array instance, which you can iterate
over any way you wish.


PointedEars
___________
[1]
<http://dhtmlkitchen.com/?category=/JavaScript/&date=2010/09/09/&entry=JavaScript-
Query-Engines>
[2] No, I did not need new heating material; you can double-check this for
free in the Amazon preview at <http://www.amazon.com/Pro-JavaScript-
Techniques-John-Resig/dp/1590597273>.
 
Ad

Advertisements

S

S.T.

Here is the jquery I am trying to use:

function undoSuccess(xmlData, status, xmlResponse)
{
$(xmlResponse).find('res:OUTPUT').each(function () {
var undoCount = $(this).attr('res:UNDO_COUNT).text();
var msg = $(this).attr('res:MSG).text();
});
}

There's a relatively new $.parseXML function (1.5+) that might help and,
unless I'm missing something, you're using attr() whereas traversing via
children() would make more sense.

See http://jsfiddle.net/nYdZv/2/ for some possible help. Much of this
topic is well beyond my comfort zone however, so apologies in advance if
I'm way off.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top