如何用jQuery解析XML跨域?

时间:2022-08-23 10:07:05

How would I go around the cross-domain issue when parsing XML from a different server/domain? Could someone provide me with an example? The example doesn't have to be restricted to jQuery only, as JavaScript will also suffice.

在解析来自不同服务器/域的XML时,我如何处理跨域问题?有人能给我举个例子吗?这个例子并不仅仅局限于jQuery,因为JavaScript也足够了。

3 个解决方案

#1


67  

To fully understand why pure cross-domain XML will not work, it helps to first look at how cross domain JSON is facilitated.

要充分理解纯跨域XML为什么不能工作,首先要了解如何方便跨域JSON。

First, let's look at what happens when you make an AJAX request in jQuery:

首先,让我们看看使用jQuery发出AJAX请求时会发生什么:

$.ajax({
    url: '/user.php?userId=123',
    success: function(data) {
        alert(data); // alerts the response
    });

In the above example, the AJAX request is made relative to the domain. We know that if we attempt to add a different domain before the path, the request will fail with a security exception.

在上面的示例中,AJAX请求相对于域进行。我们知道,如果我们试图在路径之前添加一个不同的域,请求将失败,并出现安全异常。

However, that's not to say that the browser cannot make requests to another domain. Here is an example that may be familiar to you:

但是,这并不是说浏览器不能向另一个域发出请求。这里有一个你可能很熟悉的例子:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

Based on our knowledge of how to import JavaScript on the page, we see that it is possible to load a resource that exists on another domain!

根据我们如何在页面上导入JavaScript的知识,我们可以加载存在于另一个域的资源!

JSONP is a concept that exploits this knowledge. JSONP stands for "JSON with padding", and it's success hinges on the fact that JavaScript Objects can be expressed using a string notation, and the fact that JavaScript script tags can load and run content from external domains.

JSONP是一个利用这些知识的概念。JSONP代表“带有填充的JSON”,它的成功取决于JavaScript对象可以使用字符串表示法表示,以及JavaScript脚本标记可以从外部域加载和运行内容。

Under the hood, jQuery's JSONP looks something like this although it may not be exact:

在幕后,jQuery的JSONP看起来是这样的,尽管它可能并不准确:

// programmatically load a script tag on the page using the given url
function loadRemoteData(url) {
    var script = document.createElement("script");
    script.setAttribute("type","text/javascript");
    script.setAttribute("src", url);
    document.getElementsByTagName("head")[0].appendChild(script);
}

Also, on the page somewhere, we define a callback handler:

另外,在页面某处,我们定义了一个回调处理程序:

function processData(jsonResult) {
    alert(JSON.stringify(jsonResult)); //alert the JSON as a string
}

Here, we make the request:

在此,我们提出以下要求:

// make a request for the data using the script tag remoting approach.
loadRemoteData("http://example.com/users.php?userId=123&callback=processData");

For this to work properly, our PHP script must both return the data in JSON format, and it must also add "padding" around the string in the form of a JavaScript function name that we may pass in as a parameter (i.e. "callback")

为了使其正常工作,我们的PHP脚本必须返回JSON格式的数据,并且它还必须以JavaScript函数名的形式在字符串周围添加“填充”,我们可以将其作为参数传入。“回调”)

Thus, the response from the server may look something like this, if we were to look at it in the Firebug or Chrome NET tab:

因此,服务器的响应可能看起来像这样,如果我们在Firebug或Chrome NET选项卡中查看它:

processData( { "userId" : "123" , "name" : "James" , "email" : "example@example.com" } );

Because we know JavaScript content runs as soon as it's downloaded, our processData function we defined earlier is immediately called and is passed our JSON string as a parameter. It is then alerted, using JSON.stringify to convert the object back into a string.

因为我们知道JavaScript内容一经下载就会运行,所以我们前面定义的processData函数立即被调用,并作为参数传递JSON字符串。然后使用JSON通知它。stringify将对象转换回字符串。

Since it's an object, I could also access it's properties, like so:

因为它是一个对象,我也可以访问它的属性,比如:

function processData(jsonResult) {
    alert(JSON.stringify(jsonResult)); //alert the JSON as a string

    // alert the name and email
    alert("User name is " + jsonResult.name + " and email is " + jsonResult.email);
}

Finally, let's move onto the main question: Can JSONP be used to fetch XML, or can we parse XML cross-domain? The answer, as others have pointed out, is a resounding NO, but let's look at why by using an example:

最后,让我们进入一个主要问题:JSONP可以用于获取XML,还是可以解析XML跨域?正如其他人指出的,答案是一个响亮的“不”,但让我们通过一个例子来看看为什么:

processData(<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>example@example.com</email></user>);

Now, what will happen if raw XML is passed into the function? It will break, as JavaScript has no way to convert XML into JSON.

现在,如果原始XML被传递到函数中会发生什么?它将会崩溃,因为JavaScript无法将XML转换成JSON。

However, suppose we put the XML in quotes:

但是,假设我们将XML放在引号中:

processData("<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>example@example.com</email></user>");

Now, in this example, the jsonResult variable actually takes a string, which we can work with. Using some JavaScript XML parsing utilities, we could load that string into the XML DOM Parser and do stuff with it!

现在,在这个例子中,jsonResult变量实际上接受一个字符串,我们可以使用它。使用一些JavaScript XML解析工具,我们可以将该字符串加载到XML DOM解析器中,并对其进行处理!

However, it's not pure XML, it's still a JavaScript response under the hood. The response type from the PHP server is still text/javascript, and we're still using a script tag to load what is really just plain JavaScript.

但是,它不是纯XML,它仍然是一个JavaScript响应。PHP服务器的响应类型仍然是文本/javascript,我们仍然使用脚本标记来加载真正的纯javascript。

In summary, you could work with "XMLP" or XML with padding (I just made that up, it's not real!), but if you're going to go through all of the trouble of actually modifying your response to return a function callback wrapper, you may as well just convert your output to JSON and let the browser handle conversions automatically and natively and save yourself the trouble of having to use an XML parser.

总之,你可以使用“XMLP”或XML填充(我编的,这不是真的!),但是如果你要经历的所有困难实际上修改响应返回一个函数回调包装,你不妨将输出转换为JSON,让浏览器自动处理转换和本地并保存自己的麻烦使用XML解析器。

But if for some reason it's easier to keep your data in XML format, you could modify the response and give it a JavaScript wrapper.

但是,如果出于某种原因,以XML格式保存数据更容易,您可以修改响应并给它一个JavaScript包装器。

Cases where I could see this being useful might be if you have XML data from a legacy application stored in a database, and you return it to the client-side using script-tag remoting or JSONP calls.

如果您从存储在数据库中的遗留应用程序中获得XML数据,并将其返回给客户端,使用脚本标记remoting或JSONP调用,我可以看到这种情况是有用的。

#2


4  

I found a very good solution to retrieve xml from cross domain ajax request.

我找到了一个很好的方法来从跨域ajax请求中检索xml。

Since jQuery 1.5 you can use dataType "jsonp xml" (http://api.jquery.com/jQuery.ajax/) !

由于jQuery 1.5您可以使用dataType“jsonp xml”(http://api.jquery.com/jQuery.ajax/) !

So i used this :

所以我用了这个:

$.ajax({
            type: "GET",
            url: "http://yoururl",
            dataType: "jsonp xml",
            success: function(xmlResponse) { // process data }
        });

Server side for my Webservices i used to encapsulate the xml string result within the callback created by jQuery:

我使用的web服务的服务器端将xml字符串结果封装在jQuery创建的回调中:

private static Stream GetXmlPStream(string result, string callback)
        {
            if (result == null)
                result = string.Empty;

            result = EncodeJsString(result);

            if (!String.IsNullOrEmpty(callback))
                result = callback + "(" + result + ");";

            byte[] resultBytes = Encoding.UTF8.GetBytes(result);

            if (WebOperationContext.Current != null)
                WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
            return new MemoryStream(resultBytes);
        }

and the magic method (i found it in another Stack thread) that you'll need to sanitize your xml string (so javascript can parse it) :

还有一个神奇的方法(我在另一个堆栈线程中找到的),您需要对xml字符串进行清理(以便javascript可以解析它):

private static string EncodeJsString(string s)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("\"");
            foreach (char c in s)
            {
                switch (c)
                {
                    case '\"':
                        sb.Append("\\\"");
                        break;
                    case '\\':
                        sb.Append("\\\\");
                        break;
                    case '\b':
                        sb.Append("\\b");
                        break;
                    case '\f':
                        sb.Append("\\f");
                        break;
                    case '\n':
                        sb.Append("\\n");
                        break;
                    case '\r':
                        sb.Append("\\r");
                        break;
                    case '\t':
                        sb.Append("\\t");
                        break;
                    default:
                        int i = (int)c;
                        if (i < 32 || i > 127)
                        {
                            sb.AppendFormat("\\u{0:X04}", i);
                        }
                        else
                        {
                            sb.Append(c);
                        }
                        break;
                }
            }
            sb.Append("\"");

            return sb.ToString();
        }

Hope this will help !

希望这能有所帮助!

#3


0  

I realize this is an old question, but I found this while searching. And also, I think the answer is for a slightly different question than the one posted here, so I want to add this answer which should work in at least jQuery 1.12 and later. I haven't tested in earlier versions.

我知道这是一个老问题,但我是在搜索时发现的。而且,我认为这个答案对于一个稍微不同于这里发布的问题,所以我想添加这个答案,这个答案应该至少在jQuery 1.12和之后的版本中有效。我还没有在早期版本中进行测试。

OK, I want to request this URL: http://sample.domain/feeds/itemdata.xml

好的,我想请求这个URL: http://sample.domain/feeds/itemdata.xml

And I want to find the Item in that looks like this:

我想找到这样的项:

<Item>
  <ProductItemNo>1228101530</ProductItemNo>
  ...
</Item>

This works, cross-domain:

这个作品,跨域:

$.ajax({
  dataType: "xml", 
  url: "http://sample.domain/feeds/itemdata.xml", 
  success: function(xml) {
    var itemdata = $(xml).find("ProductItemNo:contains('1228101530')").parent();
  }
});

#1


67  

To fully understand why pure cross-domain XML will not work, it helps to first look at how cross domain JSON is facilitated.

要充分理解纯跨域XML为什么不能工作,首先要了解如何方便跨域JSON。

First, let's look at what happens when you make an AJAX request in jQuery:

首先,让我们看看使用jQuery发出AJAX请求时会发生什么:

$.ajax({
    url: '/user.php?userId=123',
    success: function(data) {
        alert(data); // alerts the response
    });

In the above example, the AJAX request is made relative to the domain. We know that if we attempt to add a different domain before the path, the request will fail with a security exception.

在上面的示例中,AJAX请求相对于域进行。我们知道,如果我们试图在路径之前添加一个不同的域,请求将失败,并出现安全异常。

However, that's not to say that the browser cannot make requests to another domain. Here is an example that may be familiar to you:

但是,这并不是说浏览器不能向另一个域发出请求。这里有一个你可能很熟悉的例子:

<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

Based on our knowledge of how to import JavaScript on the page, we see that it is possible to load a resource that exists on another domain!

根据我们如何在页面上导入JavaScript的知识,我们可以加载存在于另一个域的资源!

JSONP is a concept that exploits this knowledge. JSONP stands for "JSON with padding", and it's success hinges on the fact that JavaScript Objects can be expressed using a string notation, and the fact that JavaScript script tags can load and run content from external domains.

JSONP是一个利用这些知识的概念。JSONP代表“带有填充的JSON”,它的成功取决于JavaScript对象可以使用字符串表示法表示,以及JavaScript脚本标记可以从外部域加载和运行内容。

Under the hood, jQuery's JSONP looks something like this although it may not be exact:

在幕后,jQuery的JSONP看起来是这样的,尽管它可能并不准确:

// programmatically load a script tag on the page using the given url
function loadRemoteData(url) {
    var script = document.createElement("script");
    script.setAttribute("type","text/javascript");
    script.setAttribute("src", url);
    document.getElementsByTagName("head")[0].appendChild(script);
}

Also, on the page somewhere, we define a callback handler:

另外,在页面某处,我们定义了一个回调处理程序:

function processData(jsonResult) {
    alert(JSON.stringify(jsonResult)); //alert the JSON as a string
}

Here, we make the request:

在此,我们提出以下要求:

// make a request for the data using the script tag remoting approach.
loadRemoteData("http://example.com/users.php?userId=123&callback=processData");

For this to work properly, our PHP script must both return the data in JSON format, and it must also add "padding" around the string in the form of a JavaScript function name that we may pass in as a parameter (i.e. "callback")

为了使其正常工作,我们的PHP脚本必须返回JSON格式的数据,并且它还必须以JavaScript函数名的形式在字符串周围添加“填充”,我们可以将其作为参数传入。“回调”)

Thus, the response from the server may look something like this, if we were to look at it in the Firebug or Chrome NET tab:

因此,服务器的响应可能看起来像这样,如果我们在Firebug或Chrome NET选项卡中查看它:

processData( { "userId" : "123" , "name" : "James" , "email" : "example@example.com" } );

Because we know JavaScript content runs as soon as it's downloaded, our processData function we defined earlier is immediately called and is passed our JSON string as a parameter. It is then alerted, using JSON.stringify to convert the object back into a string.

因为我们知道JavaScript内容一经下载就会运行,所以我们前面定义的processData函数立即被调用,并作为参数传递JSON字符串。然后使用JSON通知它。stringify将对象转换回字符串。

Since it's an object, I could also access it's properties, like so:

因为它是一个对象,我也可以访问它的属性,比如:

function processData(jsonResult) {
    alert(JSON.stringify(jsonResult)); //alert the JSON as a string

    // alert the name and email
    alert("User name is " + jsonResult.name + " and email is " + jsonResult.email);
}

Finally, let's move onto the main question: Can JSONP be used to fetch XML, or can we parse XML cross-domain? The answer, as others have pointed out, is a resounding NO, but let's look at why by using an example:

最后,让我们进入一个主要问题:JSONP可以用于获取XML,还是可以解析XML跨域?正如其他人指出的,答案是一个响亮的“不”,但让我们通过一个例子来看看为什么:

processData(<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>example@example.com</email></user>);

Now, what will happen if raw XML is passed into the function? It will break, as JavaScript has no way to convert XML into JSON.

现在,如果原始XML被传递到函数中会发生什么?它将会崩溃,因为JavaScript无法将XML转换成JSON。

However, suppose we put the XML in quotes:

但是,假设我们将XML放在引号中:

processData("<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>example@example.com</email></user>");

Now, in this example, the jsonResult variable actually takes a string, which we can work with. Using some JavaScript XML parsing utilities, we could load that string into the XML DOM Parser and do stuff with it!

现在,在这个例子中,jsonResult变量实际上接受一个字符串,我们可以使用它。使用一些JavaScript XML解析工具,我们可以将该字符串加载到XML DOM解析器中,并对其进行处理!

However, it's not pure XML, it's still a JavaScript response under the hood. The response type from the PHP server is still text/javascript, and we're still using a script tag to load what is really just plain JavaScript.

但是,它不是纯XML,它仍然是一个JavaScript响应。PHP服务器的响应类型仍然是文本/javascript,我们仍然使用脚本标记来加载真正的纯javascript。

In summary, you could work with "XMLP" or XML with padding (I just made that up, it's not real!), but if you're going to go through all of the trouble of actually modifying your response to return a function callback wrapper, you may as well just convert your output to JSON and let the browser handle conversions automatically and natively and save yourself the trouble of having to use an XML parser.

总之,你可以使用“XMLP”或XML填充(我编的,这不是真的!),但是如果你要经历的所有困难实际上修改响应返回一个函数回调包装,你不妨将输出转换为JSON,让浏览器自动处理转换和本地并保存自己的麻烦使用XML解析器。

But if for some reason it's easier to keep your data in XML format, you could modify the response and give it a JavaScript wrapper.

但是,如果出于某种原因,以XML格式保存数据更容易,您可以修改响应并给它一个JavaScript包装器。

Cases where I could see this being useful might be if you have XML data from a legacy application stored in a database, and you return it to the client-side using script-tag remoting or JSONP calls.

如果您从存储在数据库中的遗留应用程序中获得XML数据,并将其返回给客户端,使用脚本标记remoting或JSONP调用,我可以看到这种情况是有用的。

#2


4  

I found a very good solution to retrieve xml from cross domain ajax request.

我找到了一个很好的方法来从跨域ajax请求中检索xml。

Since jQuery 1.5 you can use dataType "jsonp xml" (http://api.jquery.com/jQuery.ajax/) !

由于jQuery 1.5您可以使用dataType“jsonp xml”(http://api.jquery.com/jQuery.ajax/) !

So i used this :

所以我用了这个:

$.ajax({
            type: "GET",
            url: "http://yoururl",
            dataType: "jsonp xml",
            success: function(xmlResponse) { // process data }
        });

Server side for my Webservices i used to encapsulate the xml string result within the callback created by jQuery:

我使用的web服务的服务器端将xml字符串结果封装在jQuery创建的回调中:

private static Stream GetXmlPStream(string result, string callback)
        {
            if (result == null)
                result = string.Empty;

            result = EncodeJsString(result);

            if (!String.IsNullOrEmpty(callback))
                result = callback + "(" + result + ");";

            byte[] resultBytes = Encoding.UTF8.GetBytes(result);

            if (WebOperationContext.Current != null)
                WebOperationContext.Current.OutgoingResponse.ContentType = "application/xml";
            return new MemoryStream(resultBytes);
        }

and the magic method (i found it in another Stack thread) that you'll need to sanitize your xml string (so javascript can parse it) :

还有一个神奇的方法(我在另一个堆栈线程中找到的),您需要对xml字符串进行清理(以便javascript可以解析它):

private static string EncodeJsString(string s)
        {
            StringBuilder sb = new StringBuilder();
            sb.Append("\"");
            foreach (char c in s)
            {
                switch (c)
                {
                    case '\"':
                        sb.Append("\\\"");
                        break;
                    case '\\':
                        sb.Append("\\\\");
                        break;
                    case '\b':
                        sb.Append("\\b");
                        break;
                    case '\f':
                        sb.Append("\\f");
                        break;
                    case '\n':
                        sb.Append("\\n");
                        break;
                    case '\r':
                        sb.Append("\\r");
                        break;
                    case '\t':
                        sb.Append("\\t");
                        break;
                    default:
                        int i = (int)c;
                        if (i < 32 || i > 127)
                        {
                            sb.AppendFormat("\\u{0:X04}", i);
                        }
                        else
                        {
                            sb.Append(c);
                        }
                        break;
                }
            }
            sb.Append("\"");

            return sb.ToString();
        }

Hope this will help !

希望这能有所帮助!

#3


0  

I realize this is an old question, but I found this while searching. And also, I think the answer is for a slightly different question than the one posted here, so I want to add this answer which should work in at least jQuery 1.12 and later. I haven't tested in earlier versions.

我知道这是一个老问题,但我是在搜索时发现的。而且,我认为这个答案对于一个稍微不同于这里发布的问题,所以我想添加这个答案,这个答案应该至少在jQuery 1.12和之后的版本中有效。我还没有在早期版本中进行测试。

OK, I want to request this URL: http://sample.domain/feeds/itemdata.xml

好的,我想请求这个URL: http://sample.domain/feeds/itemdata.xml

And I want to find the Item in that looks like this:

我想找到这样的项:

<Item>
  <ProductItemNo>1228101530</ProductItemNo>
  ...
</Item>

This works, cross-domain:

这个作品,跨域:

$.ajax({
  dataType: "xml", 
  url: "http://sample.domain/feeds/itemdata.xml", 
  success: function(xml) {
    var itemdata = $(xml).find("ProductItemNo:contains('1228101530')").parent();
  }
});