web-dev-qa-db-fra.com

analyse XML jQuery avec des espaces de noms

Je suis nouveau sur jQuery et voudrais analyser un document XML.

Je suis en mesure d'analyser le code XML standard avec les espaces de noms par défaut, mais avec XML comme:

<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-Microsoft-com:rowset" xmlns:z="#RowsetSchema">
   <s:Schema id="RowsetSchema">
     <s:ElementType name="row" content="eltOnly" rs:CommandTimeout="30">
       <s:AttributeType name="ows_ID" rs:name="ID" rs:number="1">
        <s:datatype dt:type="i4" dt:maxLength="4" />
      </s:AttributeType>
       <s:AttributeType name="ows_DocIcon" rs:name="Type" rs:number="2">
        <s:datatype dt:type="string" dt:maxLength="512" />
      </s:AttributeType>
       <s:AttributeType name="ows_LinkTitle" rs:name="Title" rs:number="3">
        <s:datatype dt:type="string" dt:maxLength="512" />
      </s:AttributeType>
       <s:AttributeType name="ows_ServiceCategory" rs:name="Service Category" rs:number="4">
        <s:datatype dt:type="string" dt:maxLength="512" />
      </s:AttributeType>
    </s:ElementType>
  </s:Schema>
   <rs:data>
    <z:row ows_ID="2" ows_LinkTitle="Sample Data 1" />
    <z:row ows_ID="3" ows_LinkTitle="Sample Data 2" />
    <z:row ows_ID="4" ows_LinkTitle="Sample Data 3" />
  </rs:data>
</xml>

Tout ce que je veux vraiment, ce sont les <z:row>.

Jusqu'ici, j'ai fait:

$.get(xmlPath, {}, function(xml) {
    $("rs:data", xml).find("z:row").each(function(i) {
        alert("found zrow");
    });
}, "xml");

Avec vraiment pas de chance. Des idées? Merci.

79
Brian Liang

J? ai compris.

Il s'avère qu'il nécessite \\ pour échapper aux deux points.

$.get(xmlPath, {}, function(xml) {
    $("rs\\:data", xml).find("z\\:row").each(function(i) {
        alert("found zrow");
    });
}, "xml");

Comme l'a souligné Rich:

La meilleure solution ne nécessite pas de fuite et fonctionne sur tous les navigateurs "modernes":

.find("[nodeName=z:row]")
130
Brian Liang

J'ai passé plusieurs heures à lire des informations sur les plug-ins et toutes sortes de solutions sans succès.

ArnisAndy a posté un lien vers une discussion jQuery, où cette réponse est proposée et je peux confirmer que cela fonctionne pour moi dans Chrome (v18.0), FireFox (v11.0), IE (v9.08) et Safari (v5.1.5 ) en utilisant jQuery (v1.7.2).

J'essaie de gratter un flux WordPress dont le contenu est nommé <content: encoded> et voici ce qui a fonctionné pour moi:

content: $this.find("content\\:encoded, encoded").text()
35
Fasani

Si vous utilisez jquery 1.5, vous devrez ajouter des guillemets autour de la valeur de l'attribut sélecteur de nœud pour que cela fonctionne

.find('[nodeName="z:row"]')
20
s0laris

Bien que la réponse ci-dessus semble être correcte, elle ne fonctionne pas dans les navigateurs Webkit (Safari, Chrome). Une meilleure solution serait, selon moi:

.find("[nodeName=z:myRow, myRow]")    
19
Rich

Au cas où quelqu'un aurait besoin de faire cela sans jQuery, juste avec du Javascript normal, et pour Google Chrome (webkit), c'est le seul moyen que j'ai trouvé pour le faire fonctionner après beaucoup de recherches et d'essais.

parentNode.getElementsByTagNameNS("*", "name");

Cela fonctionnera pour récupérer le noeud suivant: <prefix:name>. Comme vous pouvez le constater, le préfixe ou l’espace de nom est omis et il fera correspondre les éléments ayant différents espaces de nom à condition que le nom de la balise soit name. Mais espérons que cela ne sera pas un problème pour vous.

Rien de tout cela n'a fonctionné pour moi (Je développe une extension Google Chrome):

getElementsByTagNameNS("prefix", "name")

getElementsByTagName("prefix:name")

getElementsByTagName("prefix\\:name")

getElementsByTagName("name")

Edit: après un sommeil, j'ai trouvé une solution de contournement :) Cette fonction retourne la première noeud correspondant à un nodeName complet tel que <prefix:name>:

// Helper function for nodes names that include a prefix and a colon, such as "<yt:rating>"
function getElementByNodeName(parentNode, nodeName)
{   
    var colonIndex = nodeName.indexOf(":");
    var tag = nodeName.substr(colonIndex + 1);
    var nodes = parentNode.getElementsByTagNameNS("*", tag);
    for (var i = 0; i < nodes.length; i++)
    {
        if (nodes[i].nodeName == nodeName) return nodes[i]
    }
    return undefined;
}

Il peut facilement être modifié si vous devez renvoyer tous les éléments correspondants. J'espère que ça aide!

15
cprcrack

Aucune des solutions ci-dessus ne fonctionne aussi bien. J'ai trouvé cela et a été amélioré pour la vitesse. ajoutez simplement ceci, a fonctionné comme un charme: 

$.fn.filterNode = function(name) {
    return this.find('*').filter(function() {
       return this.nodeName === name;
    });
};

usage: 

var ineedthatelementwiththepsuedo = $('someparentelement').filterNode('dc:creator');

source: http://www.steveworkman.com/html5-2/javascript/2011/improving-javascript-xml-node-finding-performance-by-2000/

14
Tj Tate

Le "\\" s’échappant n’est pas infaillible et simple 

.find('[nodeName="z:row"]')

La méthode semble avoir été interrompue à partir de Jquery 1.7. J'ai pu trouver une solution pour la version 1.7 à l'aide d'une fonction de filtrage, ici: Amélioration de la performance de recherche de nœud XML Javascript

9
jmazella

Il est intéressant de noter que depuis jQuery 1.7, certaines solutions de contournement visant à rechercher des éléments espacés de noms posaient problème. Voir ces liens pour plus d'informations:

3
ArnisAndy

Solution trouvée dans le commentaire: Analyse de XML avec des espaces de noms utilisant jQuery $ (). Find

Utiliser la seconde moitié du nom du noeud après que les deux points aient fonctionné pour moi. Utilisé .find ("lat") au lieu de .find ("geo \: lat") et cela a fonctionné pour moi.


Ma configuration:

  • Chrome 42
  • jQuery 2.1.3

Exemple de XML (extrait de l'API Google Contacts):

<entry>
  <id>http://www.google.com/m8/feeds/contacts/mstefanow%40gmail.com/base/0</id>
  <Gd:email rel="http://schemas.google.com/g/2005#other" address="[email protected]" primary="true"/>
</entry>

Code d'analyse:

var xmlDoc = $.parseXML( xml );
var $xml = $( xmlDoc );
var $emailNode = $xml.find( "email" );
$("#email").html($emailNode.attr("address"));

Plnkr: http://plnkr.co/edit/l8VzyDq1NHtn5qC9zTjf?p=preview

3
Michal Stefanow

jQuery 1.7 ne fonctionne pas avec les éléments suivants: 

$(xml).find("[nodeName=a:IndexField2]")

L’une des solutions que j’ai pu utiliser dans Chrome, Firefox et IE consiste à utiliser des sélecteurs fonctionnant dans IE ET des sélecteurs fonctionnant dans Chrome, sur la base du fait qu’un moyen fonctionne dans IE et l'autre en Chrome:

$(xml).find('a\\\\:IndexField2, IndexField2')

Dans IE, cela retourne les nœuds utilisant l’espace de nom (Firefox et IE exigent l’espace de nommage), et sous Chrome, le sélecteur renvoie les nœuds basés sur le sélecteur d’espace de nom différent. Je n'ai pas testé cela dans Safari, mais cela devrait fonctionner car il fonctionne dans Chrome.

2
SeattleDiver

Réponse originale: XML ​​jQuery comment obtenir un attribut d’élément

Voici un exemple expliquant comment obtenir correctement la valeur dans Chrome.

 item.description = jQuery(this).find("[nodeName=iTunes\\:summary]").eq(0).text();
2
jdrefahl

Depuis début 2016, la syntaxe suivante fonctionne pour jQuery 1.12.0:

  • IE 11 (11.0.9600.18204, mise à jour 11.0.28, KB3134815): .find("z\\:row")
  • Firefox 44.0.2: .find("z\\:row")
  • Chrome 44.0.2403.89m: .find("row")

La syntaxe .find("[nodeName=z:row]") ne fonctionne dans aucun des navigateurs mentionnés ci-dessus. Je n'ai trouvé aucun moyen d'appliquer un espace de nom dans Chrome.

En résumé, la syntaxe suivante fonctionne dans tous les navigateurs mentionnés ci-dessus: .find("row,z\\:row")

2
stefan.schwetschke

Ma solution (parce que j'utilise un proxy Php) est de remplacer: namespace par _ ... donc plus de problèmes d'espace de nommage ;-)

Rester simple !

2
Thomas Decaux

Il existe un plugin jquery-xmlns pour que jQuery fonctionne avec les espaces de noms dans les sélecteurs.

1
Dima Fomin

contenu: $this.find("content\\:encoded, encoded").text()

est la solution parfaite ...

1
MackMon

Comme mentionné ci-dessus, la solution ci-dessus pose des problèmes avec les navigateurs/versions actuels de jQuery - le plug-in suggéré ne fonctionne pas complètement non plus en raison de problèmes de casse (nodeName, en tant que propriété, est parfois tout en majuscule). J'ai donc écrit la fonction rapide suivante:

$.findNS = function (o, nodeName)
{
    return o.children().filter(function ()
    {
        if (this.nodeName)
            return this.nodeName.toUpperCase() == nodeName.toUpperCase();
        else
            return false;
    });
};

Exemple d'utilisation:

$.findNS($(xml), 'x:row');
1
Mike Oliver

Je n'ai vu aucune documentation sur l'utilisation de JQuery pour analyser XML JQuery utilise généralement le navigateur Browser pour parcourir un document HTML, je ne crois pas qu'il lise le code HTML lui-même.

Vous devriez probablement regarder la gestion XML intégrée dans JavaScript lui-même.

http://www.webreference.com/programming/javascript/definitive2/

0
Chris Brandsma

vient de remplacer l'espace de noms par une chaîne vide. Fonctionne bien pour moi. Solution testée sur plusieurs navigateurs: Firefox, IE, Chrome

Ma tâche consistait à lire et à analyser un fichier Excel via l'API Sharepoint Excel REST. La réponse XML contient des balises avec un espace de noms "x:".

J'ai décidé de remplacer l'espace de nom dans le XML par une chaîne vide. Fonctionne comme suit: 1. Extraire le nœud d’intérêt de la réponse XML 2. Convertissez le noeud XML-Response (Document) sélectionné en chaîne 2. Remplacer l'espace de noms par une chaîne vide 3. Convertir une chaîne en XML-Document

Voir le contour du code ici ->

function processXMLResponse)(xData)
{
  var xml = TOOLS.convertXMLToString("", "",$(xData).find("entry content")[0]);
  xml = xml.replace(/x:/g, "");            // replace all occurences of namespace
  xData =  TOOLS.createXMLDocument(xml);   // convert string back to XML
}

Pour la conversion XML en chaîne, trouvez une solution ici: http://www.sencha.com/forum/showthread.php?34553-Convert-DOM-XML-Document-to-string

0
Karl

Vous pouvez également utiliser fast-xml-parser dans votre projet et convertir les données XML en objet JS/JSON. Ensuite, vous pouvez l'utiliser comme propriété d'objet. Il n'utilise pas JQuery ou d'autres bibliothèques mais cela résoudra votre problème.

var xmlData = '<xml xmlns:s="uuid:BDC6E3F0-6DA3-11d1-A2A3-00AA00C14882" xmlns:dt="uuid:C2F41010-65B3-11d1-A29F-00AA00C14882" xmlns:rs="urn:schemas-Microsoft-com:rowset" xmlns:z="#RowsetSchema">'
+'   <s:Schema id="RowsetSchema">'
+'     <s:ElementType name="row" content="eltOnly" rs:CommandTimeout="30">'
+'       <s:AttributeType name="ows_ID" rs:name="ID" rs:number="1">'
+'        <s:datatype dt:type="i4" dt:maxLength="4" />'
+'      </s:AttributeType>'
+'       <s:AttributeType name="ows_DocIcon" rs:name="Type" rs:number="2">'
+'        <s:datatype dt:type="string" dt:maxLength="512" />'
+'      </s:AttributeType>'
+'       <s:AttributeType name="ows_LinkTitle" rs:name="Title" rs:number="3">'
+'        <s:datatype dt:type="string" dt:maxLength="512" />'
+'      </s:AttributeType>'
+'       <s:AttributeType name="ows_ServiceCategory" rs:name="Service Category" rs:number="4">'
+'        <s:datatype dt:type="string" dt:maxLength="512" />'
+'      </s:AttributeType>'
+'    </s:ElementType>'
+'  </s:Schema>'
+'   <rs:data>'
+'    <z:row ows_ID="2" ows_LinkTitle="Sample Data 1" />'
+'    <z:row ows_ID="3" ows_LinkTitle="Sample Data 2" />'
+'    <z:row ows_ID="4" ows_LinkTitle="Sample Data 3" />'
+'  </rs:data>'
+'</xml>'

var jsObj = parser.parse(xmlData,{attrPrefix:"",ignoreTextNodeAttr: false});
document.write(JSON.stringify(jsObj.xml["rs:data"]["z:row"][0],null,4) + "<br>");
document.write(JSON.stringify(jsObj.xml["rs:data"]["z:row"][1],null,4) + "<br>");
document.write(JSON.stringify(jsObj.xml["rs:data"]["z:row"][2],null,4) + "<br>");
<script src="https://cdnjs.cloudflare.com/ajax/libs/fast-xml-parser/2.9.2/parser.min.js"></script>

Vous pouvez ignorer les espaces de noms lors de l'analyse syntaxique de l'objet js/json. Dans ce cas, vous pouvez accéder directement au jsObj.xml.data.row.

for(var i=0; i< jsObj.xml.data.row.length; i++){
  console.log(jsObj.xml.data.row[i]);
}

Disclaimer: J'ai créé fast-xml-parser.

0
Amit Kumar Gupta