web-dev-qa-db-fra.com

Comment analyser XML sur plusieurs domaines dans jQuery?

Comment résoudre le problème inter-domaines lors de l'analyse XML à partir d'un serveur/domaine différent? Quelqu'un pourrait-il me donner un exemple? L'exemple ne doit pas nécessairement être limité à jQuery, car JavaScript suffira également.

21
UserIsCorrupt

Pour bien comprendre pourquoi le XML interdomaine pure ne fonctionne pas, il est utile de commencer par examiner la manière dont le JSON interdomaine est facilité.

Tout d’abord, regardons ce qui se passe lorsque vous faites une demande AJAX dans jQuery:

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

Dans l'exemple ci-dessus, la demande AJAX est effectuée par rapport au domaine. Nous savons que si nous essayons d'ajouter un domaine différent avant le chemin, la demande échouera avec une exception de sécurité.

Cependant, cela ne veut pas dire que le navigateur ne peut pas envoyer de requêtes à un autre domaine. Voici un exemple que vous connaissez peut-être:

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

Grâce à notre connaissance de l'importation de JavaScript sur la page, nous constatons qu'il est possible de charger une ressource existant sur un autre domaine!

JSONP est un concept qui exploite ces connaissances. JSONP signifie "JSON with padding". Son succès dépend du fait que les objets JavaScript peuvent être exprimés à l'aide d'une notation de chaîne et du fait que les balises de script JavaScript peuvent charger et exécuter du contenu à partir de domaines externes.

Sous le capot, le JSONP de jQuery ressemble à ceci, même s'il n'est peut-être pas exact:

// 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);
}

De plus, quelque part sur la page, nous définissons un gestionnaire de rappel:

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

Ici, nous faisons la demande:

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

Pour que cela fonctionne correctement, notre script PHP doit renvoyer les données au format JSON, et il doit également ajouter un "remplissage" autour de la chaîne sous la forme d'un nom de fonction JavaScript que nous pouvons transmettre en tant que paramètre ( c'est à dire "callback")

Ainsi, la réponse du serveur peut ressembler à quelque chose comme ceci, si nous la regardions dans l’onglet Firebug ou Chrome NET:

processData( { "userId" : "123" , "name" : "James" , "email" : "[email protected]" } );

Parce que nous savons que le contenu JavaScript s'exécute dès son téléchargement, notre fonction processData définie précédemment est immédiatement appelée et notre chaîne JSON est transmise en tant que paramètre. Il est ensuite alerté à l'aide de JSON.stringify pour reconvertir l'objet en chaîne. 

Puisqu'il s'agit d'un objet, je pourrais également accéder à ses propriétés, comme ceci:

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);
}

Enfin, passons à la question principale: Peut-on utiliser JSONP pour extraire du XML, ou peut-on analyser le XML inter-domaines? La réponse, comme d'autres l'ont souligné, est un non retentissant, mais voyons pourquoi en utilisant un exemple:

processData(<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>[email protected]</email></user>);

Maintenant, qu'arrivera-t-il si du XML brut est transmis à la fonction? Cela va casser, car JavaScript n'a aucun moyen de convertir XML en JSON.

Cependant, supposons que nous mettions le XML entre guillemets:

processData("<?xml version="1.0"><user><userid>12345</userid><name>James</name><email>[email protected]</email></user>");

Dans cet exemple, la variable jsonResult prend en fait une chaîne avec laquelle nous pouvons travailler. En utilisant des utilitaires d’analyse XML XML, nous pourrions charger cette chaîne dans l’analyseur DOM XML et faire des choses avec!

Cependant, ce n'est pas du pur XML, mais une réponse JavaScript sous le capot. Le type de réponse du serveur PHP est toujours text/javascript, et nous utilisons toujours une balise script pour charger ce qui est vraiment du simple JavaScript.

En résumé, vous pouvez travailler avec "XMLP" ou XML avec un remplissage (je viens de le créer, ce n'est pas réel!), Mais si vous allez avoir toute la peine de modifier réellement votre réponse pour renvoyer un rappel de fonction vous pouvez tout aussi bien convertir votre sortie au format JSON et laisser le navigateur gérer les conversions automatiquement et en mode natif et vous éviter ainsi d'avoir à utiliser un analyseur XML.

Mais si pour une raison quelconque il est plus facile de conserver vos données au format XML, vous pouvez modifier la réponse et lui attribuer un wrapper JavaScript.

Les cas dans lesquels cela pourrait être utile pourraient être les cas si vous avez des données XML provenant d'une application héritée stockée dans une base de données et que vous les renvoyez au côté client en utilisant des appels de balises de script ou JSONP.

67
jmort253

J'ai trouvé une très bonne solution pour récupérer XML à partir d'une requête ajax interdomaine.

Depuis jQuery 1.5, vous pouvez utiliser dataType "jsonp xml" (http://api.jquery.com/jQuery.ajax/)!

Donc j'ai utilisé ceci:

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

Pour mes services Web, côté serveur, j’encapsulais le résultat de la chaîne xml dans le rappel créé par 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);
        }

et la méthode magique (je l'ai trouvée dans un autre thread Stack) dont vous aurez besoin pour purifier votre chaîne xml (pour que javascript puisse l'analyser):

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();
        }

J'espère que cela aidera!

5
LoSTxMiND

Je me rends compte que c’est une vieille question, mais j’ai trouvé cela en cherchant. Et aussi, je pense que la réponse est pour une question légèrement différente de celle postée ici, donc je veux ajouter cette réponse qui devrait fonctionner dans au moins jQuery 1.12 et ultérieur. Je n'ai pas testé dans les versions précédentes.

OK, je veux demander cette URL: http://sample.domain/feeds/itemdata.xml

Et je veux trouver la Item dans qui ressemble à ceci:

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

Cela fonctionne, inter-domaine:

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