Cách sử dụng jQuery để phân tích cú pháp XML với không gian tên


82

Tôi mới sử dụng jQuery và muốn phân tích cú pháp một tài liệu XML.

Tôi có thể phân tích cú pháp XML thông thường với các không gian tên mặc định nhưng với các XML như:

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

Tất cả những gì tôi thực sự muốn là <z:row>.

Cho đến nay, tôi đã sử dụng:

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

thực sự không có may mắn. Có ý kiến ​​gì không?


Bỏ qua tiền tố không gian tên đã làm việc cho tôi. Xem câu trả lời này: stackoverflow.com/a/25089647/2539811
Vincil Bishop

Câu trả lời:


135

Tôi hiểu rồi.

Hóa ra nó đòi hỏi \\phải thoát khỏi ruột già.

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

Như Rich đã chỉ ra:

Giải pháp tốt hơn không yêu cầu thoát và hoạt động trên tất cả các trình duyệt "hiện đại":

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

2
$('[nodeName=rs:data]', xml).find('[nodeName=z:row]')- làm việc với 1.3.2 dưới WebKit (nơi phương pháp ruột thoát rõ ràng không)
gnarf

2
điều này dường như đã ngừng hoạt động trong jQuery phiên bản 1.4.4, điều này tôi nghĩ có nghĩa là jQuery có hỗ trợ không gian tên XML tốt hơn. Vì vậy, để được an toàn, các công trình này$('[nodeName=rs:data],data')
Josh Pearce

15
Bây giờ jQuery 1.7 đã hết và giải pháp cuối cùng này không hoạt động nữa. Cách mới là gì?
Gapipro

3
Trong jQuery 1.8.x nó không hoạt động nữa. Nó sẽ được thực hiện với giải pháp tương thích lớp giả tùy chỉnh, như được giải thích ở đây .
Miere

5
Mặc dù đây trả lời câu hỏi cho doc XML nào đó, tôi muốn nhắc nhở mọi người rằng tiền tố thích rs, dthoặc slà thực sự không phải là không gian tên. Không gian tên là URN ở đầu tệp. Các tiền tố chỉ là bí danh do tác giả tài liệu chọn để giữ cho mọi thứ ngắn gọn. Cùng một tài liệu, khớp với các không gian tên giống nhau có thể được tạo với các tiền tố hoàn toàn khác nhau. Tôi khuyến khích mọi người tìm kiếm các API hiểu không gian tên thay vì giả sử các tiền tố trong truy vấn của bạn. Ví dụ: trong API DOM của trình duyệt, bạn có thể sử dụng getElementByTagNameNS()getAttributeNS().
sergiopereira

35

Tôi đã dành vài giờ cho bài đọc này về các plugin và tất cả các loại giải pháp mà không may mắn.

ArnisAndy đã đăng một liên kết đến một cuộc thảo luận jQuery, nơi câu trả lời này được cung cấp và tôi có thể xác nhận rằng điều này phù hợp với tôi trong Chrome (v18.0), FireFox (v11.0), IE (v9.08) và Safari (v5.1.5 ) bằng cách sử dụng jQuery (v1.7.2).

Tôi đang cố gắng tìm kiếm một nguồn cấp dữ liệu WordPress trong đó nội dung được đặt tên là <content: encoded> và đây là những gì phù hợp với tôi:

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

3
Đây là cách duy nhất hoạt động đáng tin cậy đối với tôi bằng cách sử dụng jQuery mới nhất (cùng phiên bản), vì vậy cảm ơn bạn!
Dominic K

2
Điều này làm việc cho tôi trong khi tôi đã sử dụng một .each()vòng lặp để lặp qua itemcác yếu tố: $('dc\\:creator, creator', this).text(). Mặc dù vậy, tôi không chắc tại sao cần bổ sung , creatordc\\:creatorkhông chỉ hoạt động.
Fillip Peyton

20

Nếu bạn đang sử dụng jquery 1.5, bạn sẽ phải thêm dấu ngoặc kép xung quanh giá trị thuộc tính bộ chọn nút để làm cho nó hoạt động:

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

19

Mặc dù câu trả lời trên có vẻ đúng nhưng nó không hoạt động trong các trình duyệt webkit (Safari, Chrome). Một giải pháp tốt hơn mà tôi tin rằng sẽ là:

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

5
điều này dường như đã ngừng hoạt động trong jQuery phiên bản 1.4.4, điều này tôi nghĩ có nghĩa là jQuery có hỗ trợ không gian tên XML tốt hơn. Vì vậy, để được an toàn, các công trình này$('[nodeName=rs:data],data')
Josh Pearce

16

Trong trường hợp ai đó cần làm điều này mà không cần jQuery , chỉ với Javascript thông thường và đối với Google Chrome (webkit) , đây là cách duy nhất tôi tìm thấy để làm cho nó hoạt động sau rất nhiều nghiên cứu và thử nghiệm.

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

Điều đó sẽ làm việc để lấy các nút sau: <prefix:name>. Như bạn có thể thấy tiền tố hoặc không gian tên bị bỏ qua và nó sẽ khớp với các phần tử có không gian tên khác nhau miễn là tên thẻ name. Nhưng hy vọng điều này sẽ không có vấn đề gì với bạn.

Không có cách nào trong số này phù hợp với tôi (tôi đang phát triển một tiện ích mở rộng của Google Chrome):

getElementsByTagNameNS("prefix", "name")

getElementsByTagName("prefix:name")

getElementsByTagName("prefix\\:name")

getElementsByTagName("name")

Chỉnh sửa : sau một thời gian ngủ, tôi đã tìm thấy một giải pháp hoạt động :) Hàm này trả về nút đầu tiên khớp với một nút đầy đủ,nodeNamechẳng hạn như<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;
}

Nó có thể dễ dàng được sửa đổi trong trường hợp bạn cần trả lại tất cả các phần tử phù hợp. Hy vọng nó giúp!


14

Không có giải pháp nào ở trên hoạt động tốt. Tôi đã tìm thấy điều này và đã được cải thiện về tốc độ. chỉ cần thêm điều này, hoạt động như một sự quyến rũ:

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

sử dụng:

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

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


Cảm ơn bạn về đoạn mã - điều này cực kỳ hữu ích / giải quyết được vấn đề.
Gilman


3

Cần lưu ý rằng kể từ jQuery 1.7, đã có vấn đề với một số cách giải quyết để tìm các phần tử có không gian tên. Xem các liên kết này để biết thêm thông tin:


Nếu hiệu suất là quan trọng, thì giải pháp tốt nhất là chọn các thẻ không có jQuery. Để so sánh, xem: jsperf.com/node-vs-double-select/13

3

Giải pháp tìm thấy trong nhận xét: Phân tích cú pháp XML với không gian tên bằng jQuery $ (). Find

Sử dụng nửa sau của tên nút sau dấu hai chấm phù hợp với tôi. Đã sử dụng .find ("lat") thay vì .find ("geo \: lat") và nó phù hợp với tôi.


Thiết lập của tôi:

  • Chrome 42
  • jQuery 2.1.3

XML mẫu (đoạn mã từ API Danh bạ 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>

Phân tích cú pháp mã:

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


Rất vui vì tôi có thể giúp :)
Mike Grace

2

jQuery 1.7 không hoạt động với những điều sau:

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

Một giải pháp mà tôi đã thực hiện để làm việc trong Chrome, Firefox và IE là sử dụng bộ chọn hoạt động trong IE VÀ bộ chọn hoạt động trong Chrome, dựa trên thực tế là một cách hoạt động trong IE và một cách khác trong Chrome:

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

Trong IE, điều này trả về các nút bằng cách sử dụng không gian tên (Firefox và IE yêu cầu không gian tên) và trong Chrome, bộ chọn trả về các nút dựa trên bộ chọn không phải không gian tên. Tôi chưa thử nghiệm điều này trong Safari, nhưng nó sẽ hoạt động vì nó hoạt động trong Chrome.


2

Giải pháp của tôi (vì tôi sử dụng proxy Php) là thay thế: namespace bằng _ ... để không còn vấn đề về namespace ;-)

Hãy giữ nó đơn giản!



2

Kể từ đầu năm 2016, đối với tôi, cú pháp sau hoạt động với jQuery 1.12.0:

  • IE 11 (11.0.9600.18204, Cập nhật 11.0.28, KB3134815): .find("z\\:row")
  • Firefox 44.0.2: .find("z\\:row")
  • Chrome 44.0.2403.89m: .find("row")

Cú pháp .find("[nodeName=z:row]")không hoạt động trong bất kỳ trình duyệt nào được đề cập ở trên. Tôi không tìm thấy cách nào để áp dụng không gian tên trong Chrome.

Kết hợp tất cả lại với nhau, cú pháp sau hoạt động trong tất cả các trình duyệt được đề cập ở trên: .find("row,z\\:row")


1

Như đã đề cập ở trên, có vấn đề với giải pháp trên với các trình duyệt / phiên bản jQuery hiện tại - trình cắm được đề xuất cũng không hoàn toàn hoạt động vì các vấn đề chữ hoa ( nodeName, như một thuộc tính, đôi khi ở tất cả các chữ hoa). Vì vậy, tôi đã viết hàm nhanh sau:

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

Ví dụ sử dụng:

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

với các vấn đề về phiên bản jQuery, đây rõ ràng là giải pháp tốt nhất
MatteoSp

1

Nội dung: $this.find("content\\:encoded, encoded").text()

là giải pháp hoàn hảo ...



0

Tôi chưa thấy bất kỳ tài liệu nào về cách sử dụng JQuery để phân tích cú pháp XML. JQuery thường sử dụng dom Trình duyệt để duyệt tài liệu HTML, tôi không tin rằng nó đọc chính html.

Bạn có thể nên xem cách xử lý XML được xây dựng trong chính JavaScript.

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


3
Hoàn toàn không đồng ý. jQuery giúp xử lý XML phản hồi dễ dàng, điều phức tạp duy nhất mà bạn gặp phải là sử dụng không gian tên xml.
Richard Clayton

1
@Richard: Khi sử dụng Ajax, jQuery sử dụng thuộc responseXMLtính của XMLHttpRequestđối tượng dựng sẵn , đây thực sự là một tài liệu XML. Tuy nhiên, jQuery (cho đến ngày 1.5, khi parseXMLđược giới thiệu) không có cách nào để phân tích cú pháp XML, vì vậy Chris đã đúng.
Tim Down

0

chỉ cần thay thế không gian tên bằng chuỗi trống. Hoạt động tốt cho tôi. Giải pháp đã thử nghiệm trên các trình duyệt: Firefox, IE, Chrome

Nhiệm vụ của tôi là đọc và phân tích cú pháp tệp EXCEL thông qua API Sharepoint EXCEL REST. Phản hồi XML chứa các thẻ có không gian tên "x:".

Tôi quyết định thay thế không gian tên trong XML bằng một chuỗi trống. Hoạt động theo cách này: 1. Đưa nút quan tâm ra khỏi phản hồi XML 2. Chuyển đổi nút đã chọn XML-Phản hồi (Tài liệu) thành Chuỗi 2. Thay thế không gian tên bằng chuỗi trống 3. Chuyển đổi chuỗi trở lại XML-Tài liệu

Xem đề cương mã tại đây ->

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
}

Để chuyển đổi từ XML sang chuỗi, hãy tìm giải pháp tại đây: http://www.sencha.com/forum/showthread.php?34553-Convert-DOM-XML-Document-to-string


0

Ngoài ra, bạn có thể sử dụng fast-xml-parser trong dự án của mình và chuyển đổi dữ liệu XML thành đối tượng JS / JSON. Sau đó, bạn có thể sử dụng nó làm thuộc tính đối tượng. Nó không sử dụng JQuery hoặc các thư viện khác nhưng nó sẽ giải quyết mục đích của bạn.

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>

Bạn có thể bỏ qua không gian tên trong khi phân tích cú pháp thành đối tượng js / json. Trong trường hợp này, bạn có thể truy cập trực tiếp như jsObj.xml.data.row.

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

Tuyên bố từ chối trách nhiệm : Tôi đã tạo nhanh-xml-parser.


-1

Đối với trình duyệt Webkit, bạn chỉ cần bỏ dấu hai chấm. Vì vậy, để tìm <media:content>trong một nguồn cấp RSS, bạn có thể làm như sau:

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

Trong safari mới nhất, nó không hỗ trợ việc sử dụng. nó chỉ hoạt động phiên bản trước.
Baryon Lee
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.