Verwendung von jQuery für die XML-Analyse mit Namespaces

80

Ich bin neu in jQuery und möchte ein XML-Dokument analysieren.

Ich kann reguläres XML mit den Standard-Namespaces analysieren, aber mit XML wie:

<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>

Alles was ich wirklich will ist das <z:row>.

Bisher habe ich verwendet:

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

mit wirklich keinem Glück. Irgendwelche Ideen?

Brian Liang
quelle
Das Weglassen des Namespace-Präfixes hat bei mir funktioniert. Siehe diese Antwort: stackoverflow.com/a/25089647/2539811
Vincil Bishop

Antworten:

134

Ich habe es verstanden.

Es stellt sich heraus, dass es erforderlich ist \\, dem Doppelpunkt zu entkommen.

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

Wie Rich betonte:

Die bessere Lösung erfordert kein Escape und funktioniert auf allen "modernen" Browsern:

.find("[nodeName=z:row]")
Brian Liang
quelle
2
$('[nodeName=rs:data]', xml).find('[nodeName=z:row]')- funktioniert mit 1.3.2 unter WebKit (wo die Methode des entkommenen Doppelpunkts anscheinend nicht funktioniert)
Gnarf
2
Dies scheint in jQuery Version 1.4.4 nicht mehr zu funktionieren, was meiner Meinung nach bedeutet, dass jQuery eine bessere Unterstützung für XML-Namespaces bietet. Um sicher zu gehen, funktioniert dies$('[nodeName=rs:data],data')
Josh Pearce
15
Jetzt ist jQuery 1.7 verfügbar und diese letzte Lösung funktioniert nicht mehr. Was ist der neue Weg?
Gapipro
3
In jQuery 1.8.x funktioniert es nicht mehr. Dies sollte mit einer benutzerdefinierten Problemumgehung für die Pseudoklassenkompatibilität erreicht werden, wie hier erläutert .
Miere
5
Auch wenn sich die Frage für die gegebene XML - Dokument beantwortet, würde Ich mag die Menschen daran zu erinnern , dass die Präfixe wie rs, dtoder ssind wirklich nicht die Namensräume. Die Namespaces sind die URNs am Anfang der Datei. Die Präfixe sind nur Aliase, die vom Dokumentautor ausgewählt wurden, um die Dinge kurz zu halten. Dasselbe Dokument, das mit denselben Namespaces übereinstimmt, kann mit völlig unterschiedlichen Präfixen erstellt werden. Ich möchte alle dazu ermutigen, nach APIs zu suchen, die Namespaces verstehen, anstatt Präfixe in Ihren Abfragen anzunehmen. ZB können Sie in der Browser-DOM-API getElementByTagNameNS()und verwenden getAttributeNS().
Sergiopereira
35

Ich habe mehrere Stunden damit verbracht, über Plugins und alle möglichen Lösungen zu lesen, ohne Glück.

ArnisAndy hat einen Link zu einer jQuery-Diskussion gepostet, in der diese Antwort angeboten wird, und ich kann bestätigen, dass dies für mich in Chrome (Version 18.0), FireFox (Version 11.0), IE (Version 9.08) und Safari (Version 5.1.5) funktioniert ) mit jQuery (v1.7.2).

Ich versuche, einen WordPress-Feed zu kratzen, in dem der Inhalt <content: encoded> heißt, und das hat bei mir funktioniert:

content: $this.find("content\\:encoded, encoded").text()
MKS
quelle
3
Dies war die einzige, die mit der neuesten jQuery (gleiche Version) zuverlässig für mich funktioniert hat. Vielen Dank!
Dominic K
2
Dies funktionierte für mich, während ich eine .each()Schleife verwendete, um itemElemente zu durchlaufen : $('dc\\:creator, creator', this).text(). Ich bin mir jedoch nicht sicher, warum das Extra , creatorbenötigt wurde und dc\\:creatornicht nur funktioniert hat.
Fillip Peyton
20

Wenn Sie jquery 1.5 verwenden, müssen Sie Anführungszeichen um den Attributwert der Knotenauswahl hinzufügen, damit dies funktioniert:

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

Obwohl die obige Antwort richtig zu sein scheint, funktioniert sie in Webkit-Browsern (Safari, Chrome) nicht. Eine bessere Lösung, glaube ich, wäre:

.find("[nodeName=z:myRow, myRow]")    
Reich
quelle
5
Dies scheint in jQuery Version 1.4.4 nicht mehr zu funktionieren, was meiner Meinung nach bedeutet, dass jQuery eine bessere Unterstützung für XML-Namespaces bietet. Um sicher zu gehen, funktioniert dies$('[nodeName=rs:data],data')
Josh Pearce
16

Falls jemand dies ohne jQuery tun muss , nur mit normalem Javascript, und für Google Chrome (Webkit) , ist dies die einzige Möglichkeit, die ich nach vielen Recherchen und Tests zum Laufen gebracht habe .

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

Dies funktioniert zum Abrufen des folgenden Knotens : <prefix:name>. Wie Sie sehen können, wird das Präfix oder der Namespace weggelassen und es werden Elemente mit unterschiedlichen Namespaces abgeglichen, sofern der Tag-Name lautet name. Aber hoffentlich ist dies kein Problem für Sie.

Nichts davon hat bei mir funktioniert (ich entwickle eine Google Chrome-Erweiterung):

getElementsByTagNameNS("prefix", "name")

getElementsByTagName("prefix:name")

getElementsByTagName("prefix\\:name")

getElementsByTagName("name")

Edit : nach etwas Schlaf, fand ich eine Arbeits Abhilfe :) Diese Funktion gibt den ersten Knoten eine vollständige AnpassungnodeNamewie<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;
}

Es kann leicht geändert werden, falls Sie alle übereinstimmenden Elemente zurückgeben müssen. Ich hoffe es hilft!

cprcrack
quelle
14

Keine der oben genannten Lösungen funktioniert so gut. Ich habe das gefunden und wurde für die Geschwindigkeit verbessert. füge dies einfach hinzu, wirkte wie ein Zauber:

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

Verwendung:

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

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

Tj Tate
quelle
Vielen Dank für den Ausschnitt - dies ist äußerst hilfreich / löst das Problem.
Gilman
3

Es ist erwähnenswert, dass es ab jQuery 1.7 Probleme mit einigen Workarounds zum Auffinden von Elementen mit Namespace gab. Weitere Informationen finden Sie unter diesen Links:

ArnisAndy
quelle
Wenn die Leistung wichtig ist, besteht die beste Lösung darin, die Tags ohne jQuery auszuwählen. Einen Vergleich finden Sie unter: jsperf.com/node-vs-double-select/13
3

Gefundene Lösung im Kommentar: Parsen von XML mit Namespaces mit jQuery $ (). Find

Die Verwendung der zweiten Hälfte des Knotennamens nach dem Doppelpunkt hat bei mir funktioniert. Gebrauchte .find ( "lat") statt .find ( "geo \: lat") und es funktionierte für mich.


Mein Setup:

  • Chrome 42
  • jQuery 2.1.3

Beispiel-XML (Ausschnitt aus der Google Contacts-API):

<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>

Parsing-Code:

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

Mars Robertson
quelle
Ich bin froh, dass ich helfen konnte :)
Mike Grace
2

jQuery 1.7 funktioniert nicht mit folgenden Funktionen:

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

Eine Lösung, die ich in Chrome, Firefox und IE zum Laufen gebracht habe, besteht darin, Selektoren zu verwenden, die in IE funktionieren, UND Selektoren, die in Chrome funktionieren, basierend auf der Tatsache, dass eine Möglichkeit in IE und die andere in Chrome funktioniert:

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

In IE werden Knoten zurückgegeben, die den Namespace verwenden (Firefox und IE erfordern den Namespace), und in Chrome gibt der Selektor Knoten zurück, die auf dem Nicht-Namespace-Selektor basieren. Ich habe dies nicht in Safari getestet, aber es sollte funktionieren, da es in Chrome funktioniert.

SeattleDiver
quelle
2

Meine Lösung (weil ich einen PHP-Proxy verwende) besteht darin, den Namespace durch _ ... zu ersetzen, damit keine Namespace-Probleme mehr auftreten ;-)

Halte es einfach !

Thomas Decaux
quelle
2

Ab Anfang 2016 funktioniert für mich die folgende Syntax mit jQuery 1.12.0:

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

Die Syntax .find("[nodeName=z:row]")funktioniert in keinem der oben genannten Browser. Ich habe keine Möglichkeit gefunden, einen Namespace in Chrome anzuwenden.

Alles in allem funktioniert die folgende Syntax in allen oben genannten Browsern: .find("row,z\\:row")

stefan.schwetschke
quelle
1

Wie oben erwähnt, gibt es Probleme mit der oben genannten Lösung mit aktuellen Browsern / Versionen von jQuery - das vorgeschlagene Plug-In funktioniert auch aufgrund von Groß- und Kleinschreibung nicht vollständig ( nodeNameals Eigenschaft wird manchmal in Großbuchstaben geschrieben). Also schrieb ich die folgende Schnellfunktion:

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

Anwendungsbeispiel:

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

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

ist die perfekte Lösung ...

Sachinkondana
quelle
1

Es gibt ein Plugin jquery-xmlns für jQuery, um mit Namespaces in Selektoren zu arbeiten.

Dima Fomin
quelle
0

Ich habe keine Dokumentation zur Verwendung von JQuery zum Parsen von XML gesehen. JQuery verwendet normalerweise den Browser dom, um ein HTML-Dokument zu durchsuchen. Ich glaube nicht, dass es das HTML selbst liest.

Sie sollten sich wahrscheinlich die integrierte XML-Behandlung in JavaScript selbst ansehen.

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

Chris Brandsma
quelle
3
Stimme überhaupt nicht zu. jQuery erleichtert die Handhabung von Antwort-XML. Die einzige Komplikation besteht in der Verwendung von XML-Namespaces.
Richard Clayton
1
@Richard: Bei Verwendung von Ajax verwendet jQuery die responseXMLEigenschaft des integrierten XMLHttpRequestObjekts, bei dem es sich tatsächlich um ein XML-Dokument handelt. JQuery (bis parseXMLzur Einführung von 1.5 ) hatte jedoch keine Möglichkeit, XML zu analysieren, sodass Chris Recht hatte.
Tim Down
0

habe gerade den Namespace durch eine leere Zeichenfolge ersetzt. Funktioniert gut für mich. Getestete Lösung für alle Browser: Firefox, IE, Chrome

Meine Aufgabe war es, eine EXCEL-Datei über die Sharepoint EXCEL REST API zu lesen und zu analysieren. Die XML-Antwort enthält Tags mit dem Namespace "x:".

Ich habe beschlossen, den Namespace im XML durch eine leere Zeichenfolge zu ersetzen. Funktioniert folgendermaßen: 1. Holen Sie den gewünschten Knoten aus der XML-Antwort heraus. 2. Konvertieren Sie den ausgewählten Knoten XML-Response (Document) in String. 2. Ersetzen Sie den Namespace durch eine leere Zeichenfolge. 3. Konvertieren Sie die Zeichenfolge zurück in XML-Document

Siehe Code-Gliederung hier ->

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
}

Für die Konvertierung von XML in String finden Sie hier eine Lösung: http://www.sencha.com/forum/showthread.php?34553-Convert-DOM-XML-Document-to-string

Karl
quelle
0

Alternativ können Sie den Fast-XML-Parser in Ihrem Projekt verwenden und die XML-Daten in ein JS / JSON-Objekt konvertieren. Dann können Sie es als Objekteigenschaft verwenden. Es verwendet weder JQuery noch andere Bibliotheken, löst jedoch Ihren Zweck.

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>

Sie können Namespaces ignorieren, während Sie das Objekt js / json analysieren. In diesem Fall können Sie direkt auf as zugreifen jsObj.xml.data.row.

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

Haftungsausschluss : Ich habe einen Fast-XML-Parser erstellt.

Amit Kumar Gupta
quelle
-1

Bei Webkit-Browsern können Sie den Doppelpunkt einfach weglassen. <media:content>Um dies beispielsweise in einem RSS-Feed zu finden , können Sie Folgendes tun:

$(this).find("content");
Donnapep
quelle
In der neuesten Safari wird die Verwendung nicht unterstützt. Es funktioniert nur in der vorherigen Version.
Baryon Lee