Jak używać jQuery do analizowania XML z przestrzeniami nazw


82

Jestem nowy w jQuery i chciałbym przeanalizować dokument XML.

Jestem w stanie przeanalizować zwykły XML z domyślnymi przestrzeniami nazw, ale z XML, takimi jak:

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

Wszystko, czego naprawdę chcę, to <z:row> .

Do tej pory używałem:

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

bez powodzenia. Jakieś pomysły?


Pominięcie przedrostka przestrzeni nazw zadziałało dla mnie. Zobacz tę odpowiedź: stackoverflow.com/a/25089647/2539811
Vincil Bishop

Odpowiedzi:


135

Mam to.

Okazuje się, że wymaga \\ucieczki z okrężnicy.

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

Jak wskazał Rich:

Lepsze rozwiązanie nie wymaga ucieczki i działa na wszystkich "nowoczesnych" przeglądarkach:

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

2
$('[nodeName=rs:data]', xml).find('[nodeName=z:row]')- działa z 1.3.2 pod WebKitem (gdzie metoda ucieczki dwukropka najwyraźniej nie działa)
gnarf

2
wydaje się, że przestało to działać w jQuery w wersji 1.4.4, co moim zdaniem oznacza, że ​​jQuery ma lepszą obsługę przestrzeni nazw XML. Aby być bezpiecznym, to działa$('[nodeName=rs:data],data')
Josh Pearce

15
Teraz jQuery 1.7 jest niedostępny i to ostatnie rozwiązanie już nie działa. Jaka jest nowa droga?
Gapipro

3
W jQuery 1.8.x już nie działa. Należy to osiągnąć przy użyciu niestandardowego obejścia kompatybilności pseudoklas, jak wyjaśniono tutaj .
Miere

5
Nawet jeśli to jest odpowiedź na pytanie dla danego dokumentu XML, chciałbym przypomnieć ludziom, że przedrostki podoba rs, dtczy snie są naprawdę nazw. Przestrzenie nazw to URN w górnej części pliku. Przedrostki to po prostu aliasy wybrane przez autora dokumentu, aby zachować zwięzłość. Ten sam dokument, pasujący do tych samych przestrzeni nazw, można utworzyć z zupełnie różnymi prefiksami. Zachęcam wszystkich do szukania interfejsów API, które rozumieją przestrzenie nazw, zamiast zakładać prefiksy w zapytaniach. Np. W przeglądarce DOM API możesz używać getElementByTagNameNS()i getAttributeNS().
sergiopereira

35

Spędziłem kilka godzin na czytaniu o wtyczkach i wszelkiego rodzaju rozwiązaniach bez powodzenia.

ArnisAndy opublikował łącze do dyskusji jQuery, w której jest oferowana ta odpowiedź i mogę potwierdzić, że działa to dla mnie w Chrome (wersja 18.0), FireFox (wersja 11.0), IE (wersja 9.08) i Safari (wersja 5.1.5) ) przy użyciu jQuery (v1.7.2).

Próbuję zeskrobać kanał WordPress, w którym zawartość nosi nazwę <content: encoded> i to właśnie zadziałało:

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

3
To był jedyny, który niezawodnie działał dla mnie przy użyciu najnowszej wersji jQuery (ta sama wersja), więc dziękuję!
Dominic K

2
Ten pracował dla mnie podczas gdy użyłem .each()pętli do iterację itemelementów: $('dc\\:creator, creator', this).text(). Chociaż nie jestem pewien, dlaczego ten dodatek , creatorbył potrzebny i dc\\:creatornie tylko działał.
Fillip Peyton

20

Jeśli używasz jquery 1.5, będziesz musiał dodać cudzysłowy wokół wartości atrybutu selektora węzła, aby działało:

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

19

Chociaż powyższa odpowiedź wydaje się być poprawna, nie działa ona w przeglądarkach webkit (Safari, Chrome). Uważam, że lepszym rozwiązaniem byłoby:

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

5
wydaje się, że przestało to działać w jQuery w wersji 1.4.4, co moim zdaniem oznacza, że ​​jQuery ma lepszą obsługę przestrzeni nazw XML. Aby być bezpiecznym, to działa$('[nodeName=rs:data],data')
Josh Pearce

16

Na wypadek, gdyby ktoś musiał to zrobić bez jQuery , tylko z normalnym Javascriptem i dla Google Chrome (webkit) , jest to jedyny sposób, w jaki udało mi się go uruchomić po wielu badaniach i testach.

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

Że będzie pracować dla pobierania następujący węzeł: <prefix:name>. Jak widać, przedrostek lub przestrzeń nazw są pomijane i będą dopasowywać elementy z różnymi przestrzeniami nazw pod warunkiem, że nazwa znacznika toname . Ale miejmy nadzieję, że nie będzie to dla ciebie problemem.

Nic z tego nie zadziałało (rozwijam rozszerzenie Google Chrome):

getElementsByTagNameNS("prefix", "name")

getElementsByTagName("prefix:name")

getElementsByTagName("prefix\\:name")

getElementsByTagName("name")

Edycja : po pewnym śnie znalazłem działające obejście :) Ta funkcja zwraca pierwszy węzeł pasujący do pełnego, nanodeNameprzykład<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;
}

Można go łatwo zmodyfikować w przypadku konieczności zwrócenia wszystkich pasujących elementów. Mam nadzieję, że to pomoże!


14

Żadne z powyższych rozwiązań nie działa tak dobrze. Znalazłem to i poprawiono szybkość. po prostu dodaj to, działało jak urok:

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

stosowanie:

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

źródło: http://www.steveworkman.com/html5-2/javascript/2011/improving-javascript-xml-node-finding-performance-by-2000/


Dziękuję za fragment - jest to niezwykle pomocne / rozwiązuje problem.
Gilman,


3

Warto zauważyć, że od wersji jQuery 1.7 występowały problemy z niektórymi obejściami dotyczącymi znajdowania elementów w przestrzeni nazw. Zobacz te linki, aby uzyskać więcej informacji:


Jeśli wydajność jest ważna, najlepszym rozwiązaniem jest wybranie tagów bez jQuery. Dla porównania patrz: jsperf.com/node-vs-double-select/13

3

Znalezione rozwiązanie w komentarzu: Parsowanie XML z przestrzeniami nazw za pomocą jQuery $ (). Find

U mnie zadziałało używanie drugiej połowy nazwy węzła po dwukropku. Używane .find ( "lat") zamiast .find ( "geo \: lat") i pracował dla mnie.


Moja konfiguracja:

  • Chrome 42
  • jQuery 2.1.3

Przykładowy kod XML (fragment z interfejsu API Kontaktów Google):

<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@example.com" primary="true"/>
</entry>

Kod parsowania:

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


Cieszę się, że mogłem pomóc :)
Mike Grace

2

jQuery 1.7 nie działa z następującymi elementami:

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

Jednym z rozwiązań, które udało mi się pracować w Chrome, Firefox i IE, jest użycie selektorów, które działają w IE ORAZ selektory, które działają w Chrome, w oparciu o fakt, że jeden sposób działa w IE, a drugi w Chrome:

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

W IE zwraca to węzły przy użyciu przestrzeni nazw (Firefox i IE wymagają przestrzeni nazw), aw przeglądarce Chrome selektor zwraca węzły na podstawie selektora innego niż przestrzeń nazw. Nie testowałem tego w Safari, ale powinno działać, ponieważ działa w Chrome.


2

Moim rozwiązaniem (ponieważ używam proxy PHP) jest zastąpienie: przestrzeń nazw przez _ ... więc koniec problemów z przestrzenią nazw ;-)

Nie komplikuj !



2

Od początku 2016 r. Dla mnie z jQuery 1.12.0 działa następująca składnia:

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

Składnia .find("[nodeName=z:row]") nie działa w żadnej z wyżej wymienionych przeglądarek. Nie znalazłem sposobu na zastosowanie przestrzeni nazw w Chrome.

Podsumowując, następująca składnia działa we wszystkich wymienionych powyżej przeglądarkach: .find("row,z\\:row")


1

Jak wspomniano powyżej, istnieją problemy z powyższym rozwiązaniem w obecnych przeglądarkach / wersjach jQuery - sugerowana wtyczka nie działa całkowicie z powodu problemów z wielkością liter ( nodeNamejako właściwość czasami jest pisana wielkimi literami). Tak więc napisałem następującą szybką funkcję:

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

Przykładowe użycie:

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

biorąc pod uwagę problemy z wersją jQuery, jest to zdecydowanie najlepsze rozwiązanie
MatteoSp



0

Nie widziałem żadnej dokumentacji dotyczącej używania JQuery do analizowania XML. JQuery zwykle używa domeny przeglądarki do przeglądania dokumentu HTML, nie sądzę, aby czyta ona sam html.

Prawdopodobnie powinieneś spojrzeć na wbudowaną obsługę XML w samym JavaScript.

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


3
Całkowicie się nie zgadzam. jQuery sprawia, że ​​obsługa XML odpowiedzi jest łatwa, jedyną komplikacją, jaką napotkasz, jest używanie przestrzeni nazw xml.
Richard Clayton

1
@Richard: Podczas korzystania z Ajax, jQuery używa responseXMLwłaściwości wbudowanego XMLHttpRequestobiektu, który w rzeczywistości jest dokumentem XML. Jednak jQuery (do 1.5, kiedy parseXMLzostał wprowadzony) nie miał możliwości analizowania XML, więc Chris miał rację.
Tim Down

0

właśnie zastąpiłem przestrzeń nazw pustym ciągiem. U mnie działa dobrze. Testowane rozwiązanie w różnych przeglądarkach: Firefox, IE, Chrome

Moim zadaniem było odczytanie i przeanalizowanie pliku EXCEL przez Sharepoint EXCEL REST API. Odpowiedź XML zawiera tagi z przestrzenią nazw „x:”.

Postanowiłem zastąpić przestrzeń nazw w XML-u pustym ciągiem. Działa w ten sposób: 1. Pobierz żądany węzeł z odpowiedzi XML 2. Przekształć wybrany węzeł Odpowiedź XML (dokument) na łańcuch 2. Zastąp przestrzeń nazw pustym ciągiem 3. Przekształć ciąg z powrotem na dokument XML

Zobacz zarys kodu tutaj ->

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
}

Rozwiązanie dotyczące konwersji XML na ciąg znaków znajdziesz tutaj: http://www.sencha.com/forum/showthread.php?34553-Convert-DOM-XML-Document-to-string


0

Alternatywnie możesz użyć fast-xml-parser w swoim projekcie i przekonwertować dane XML na obiekt JS / JSON. Następnie możesz użyć go jako właściwości obiektu. Nie używa JQuery ani innych bibliotek, ale rozwiąże Twój cel.

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>

Możesz ignorować przestrzenie nazw podczas analizowania do obiektu js / json. W takim przypadku możesz uzyskać bezpośredni dostęp do plików jsObj.xml.data.row.

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

Zastrzeżenie : stworzyłem parser fast-xml.


-1

W przypadku przeglądarek Webkit możesz po prostu pominąć dwukropek. Aby znaleźć <media:content>na przykład kanał RSS, możesz zrobić to:

$(this).find("content");

W najnowszym safari nie obsługuje użycia. działa tylko w poprzedniej wersji.
Baryon Lee
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.