Як використовувати jQuery для аналізу XML із просторами імен


82

Я новачок у jQuery і хочу проаналізувати документ XML.

Я можу проаналізувати звичайний XML із просторами імен за замовчуванням, але з XML, таким як:

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

Все, що я справді хочу, - це <z:row>.

Дотепер я використовував:

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

справді не пощастило. Будь-які ідеї?


Опускання префіксу простору імен спрацювало для мене. Дивіться цей відповідь: stackoverflow.com/a/25089647/2539811
Vincil Bishop

Відповіді:


135

Зрозумів.

Виявляється, це вимагає \\втечі з товстої кишки.

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

Як зазначив Річ:

Краще рішення не вимагає екранування та працює на всіх "сучасних" браузерах:

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

2
$('[nodeName=rs:data]', xml).find('[nodeName=z:row]')- працює з 1.3.2 під WebKit (де метод екранованої ободової кишки, мабуть, не працює)
gnarf

2
здається, це перестало працювати у jQuery версії 1.4.4, що, на мою думку, означає, що jQuery має кращу підтримку простору імен XML. Тож, щоб перестрахуватися, це працює$('[nodeName=rs:data],data')
Джош Пірс,

15
Зараз jQuery 1.7 вийшов, і це останнє рішення вже не працює. Що нового?
Gapipro

3
У jQuery 1.8.x це вже не працює. Це повинно бути здійснено за допомогою спеціального обхідного способу сумісності з псевдокласом, як пояснено тут .
Miere

5
Незважаючи на те, що це відповідь на це питання для даного XML - документ, я хотів би, щоб нагадати людям про те , що префікси подобається rs, dtабо sнасправді не просторів імен. Простори імен - це URN у верхній частині файлу. Префікси - це просто псевдоніми, вибрані автором документа, щоб скоротити час. Той самий документ, що відповідає одній і тій же просторі імен, може бути створений із абсолютно різними префіксами. Я закликаю всіх шукати API, які розуміють простори імен, а не приймати префікси у ваших запитах. Наприклад, у браузері DOM API ви можете використовувати getElementByTagNameNS()і getAttributeNS().
sergiopereira

35

Я витратив кілька годин на це читання про плагіни та всілякі рішення без удачі.

ArnisAndy опублікував посилання на обговорення jQuery, де пропонується така відповідь, і я можу підтвердити, що це працює для мене в Chrome (v18.0), FireFox (v11.0), IE (v9.08) і Safari (v5.1.5 ) за допомогою jQuery (v1.7.2).

Я намагаюся зішкребти стрічку WordPress, де вміст називається <content: encoded>, і ось що мені вдалося:

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

3
Це був єдиний, який надійно працював у мене, використовуючи останню jQuery (та сама версія), тож дякую!
Домінік К

2
Це працює для мене , поки я використовував .each()цикл для перебору itemелементів: $('dc\\:creator, creator', this).text(). Хоча, я не впевнений, навіщо , creatorпотрібна була додаткова програма , яка dc\\:creatorне просто спрацювала.
Філіп Пейтон,

20

Якщо ви використовуєте jquery 1.5, вам доведеться додавати лапки навколо значення атрибута селектора вузла, щоб воно працювало:

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

19

Незважаючи на те, що наведена вище відповідь є правильною, вона не працює у веб-переглядачах webkit (Safari, Chrome). Я вважаю кращим рішенням:

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

5
здається, це перестало працювати у jQuery версії 1.4.4, що, на мою думку, означає, що jQuery має кращу підтримку простору імен XML. Тож, щоб перестрахуватися, це працює$('[nodeName=rs:data],data')
Джош Пірс,

17

Якщо комусь потрібно зробити це без jQuery , лише із звичайним Javascript, а для Google Chrome (webkit) це єдиний спосіб, який я знайшов, щоб змусити його працювати після довгих досліджень та тестувань.

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

Це буде працювати для отримання наступного вузла: <prefix:name>. Як бачите, префікс або простір імен опущено, і він буде відповідати елементам з різними просторами імен за умови, що ім'я тегу є name. Але, сподіваємось, це не буде для вас проблемою.

Мені нічого з цього не вдалося (я розробляю розширення Google Chrome):

getElementsByTagNameNS("prefix", "name")

getElementsByTagName("prefix:name")

getElementsByTagName("prefix\\:name")

getElementsByTagName("name")

Редагувати : після деякого сну я знайшов робочий обхідний шлях :) Ця функція повертає перший вузол, що відповідає повному,nodeNameнаприклад<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;
}

Його можна легко змінити, якщо вам потрібно повернути всі відповідні елементи. Сподіваюся, це допоможе!


14

Жодне з наведених вище рішень не працює так добре. Я знайшов це та покращив швидкість. просто додайте це, працювало як шарм:

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

використання:

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

джерело: http://www.steveworkman.com/html5-2/javascript/2011/improving-javascript-xml-node-finding-performance-by-2000/


Дякуємо за фрагмент - це надзвичайно корисно / вирішує проблему.
Гілман


3

Варто зазначити, що станом на jQuery 1.7 виникали проблеми з деякими робочими шляхами пошуку елементів з простором імен. Для отримання додаткової інформації дивіться ці посилання:


Якщо продуктивність важлива, то найкращим рішенням буде вибір тегів без jQuery. Для порівняння див .: jsperf.com/node-vs-double-select/13

3

Знайдене рішення в коментарі: Розбір XML з просторами імен за допомогою jQuery $ (). Find

Використання другої половини імені вузла після двокрапки працювало для мене. Використовував .find ("lat") замість .find ("geo \: lat"), і це спрацювало для мене.


Моє налаштування:

  • Chrome 42
  • jQuery 2.1.3

Зразок XML (фрагмент з 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@example.com" primary="true"/>
</entry>

Код розбору:

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


Радий, що зміг допомогти :)
Майк Грейс

2

jQuery 1.7 не працює з наступними:

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

Одне з рішень, яке я отримав для роботи в Chrome, Firefox та IE, - це використання селекторів, які працюють в IE І селекторів, які працюють в Chrome, виходячи з того, що один із способів працює в IE, а інший - у Chrome:

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

В IE це повертає вузли, використовуючи простір імен (Firefox та IE вимагають простір імен), а в Chrome селектор повертає вузли на основі селектора не простору імен. Я не тестував це в Safari, але це повинно працювати, оскільки це працює в Chrome.


2

Моє рішення (оскільки я використовую проксі-сервер Php) полягає в тому, щоб замінити: простір імен на _ ... так що проблем із простором імен більше не буде ;-)

Не ускладнювати !



2

На початок 2016 року для мене такий синтаксис працює з jQuery 1.12.0:

  • IE 11 (11.0.9600.18204, оновлення 11.0.28, KB3134815): .find("z\\:row")
  • Firefox 44.0.2: .find("z\\:row")
  • Chrome 44.0.2403.89м: .find("row")

Синтаксис .find("[nodeName=z:row]")не працює в жодному з браузерів, згаданих вище. Я не знайшов способу застосувати простір імен у Chrome.

Поєднуючи все це, наступний синтаксис працює у всіх згаданих вище браузерах: .find("row,z\\:row")


1

Як уже згадувалося вище, із зазначеним вище рішенням існують проблеми з поточними браузерами / версіями jQuery - запропонований плагін не працює повністю також через проблеми з регістром ( nodeNameяк властивість, іноді у всіх регістрах). Отже, я написав таку швидку функцію:

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

Приклад використання:

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

з огляду на проблеми з версією jQuery, це явно найкраще рішення
MatteoSp



0

Я не бачив жодної документації щодо використання JQuery для синтаксичного аналізу XML. JQuery зазвичай використовує браузер dom для перегляду HTML-документа, я не вірю, що він читає сам html.

Ймовірно, варто поглянути на вбудовану обробку XML у самому JavaScript.

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


3
Повністю не згоден. jQuery полегшує обробку відповідей XML, єдине ускладнення, з яким ви зіткнетеся, - використання просторів імен xml.
Richard Clayton,

1
@Richard: При використанні Ajax jQuery використовує responseXMLвластивість вбудованого XMLHttpRequestоб'єкта, який насправді є XML-документом. Однак jQuery (до 1.5, коли він parseXMLбув представлений) не мав можливості аналізу XML, тому Кріс мав рацію.
Тім Даун

0

просто замінив простір імен порожнім рядком. Для мене чудово працює. Перевірене рішення в браузерах: Firefox, IE, Chrome

Моїм завданням було прочитати та проаналізувати EXCEL-файл через Sharepoint EXCEL REST API. Відповідь XML містить теги із простором імен "x:".

Я вирішив замінити простір імен у XML порожнім рядком. Працює таким чином: 1. Витягніть вузол, що цікавить, із XML-відповіді 2. Перетворіть вибраний вузол XML-відповідь (документ) у рядок 2. Замініть простір імен порожнім рядком 3. Перетворіть рядок назад у XML-документ

Дивіться схему коду тут ->

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
}

Для перетворення XML у рядок знайдіть рішення тут: http://www.sencha.com/forum/showthread.php?34553-Convert-DOM-XML-Document-to-string


0

Крім того, ви можете використовувати швидкий синтаксичний аналізатор у своєму проекті та перетворити дані XML у об’єкт JS / JSON. Тоді ви можете використовувати його як властивість об'єкта. Він не використовує JQuery чи інші бібліотеки, але вирішить вашу мету.

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>

Ви можете ігнорувати простори імен під час аналізу об’єкта js / json. У цьому випадку ви можете отримати прямий доступ як jsObj.xml.data.row.

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

Застереження : я створив синтаксичний аналізатор fast-xml.


-1

Для веб-переглядачів Webkit ви можете просто залишити двокрапку. Отже, щоб знайти, наприклад, <media:content>у стрічці RSS, ви можете зробити це:

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

В останньому сафарі він не підтримує використання. це працює лише попередня версія.
Baryon Lee
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.