Синтаксический анализ jQuery XML с использованием пространств имен.
Я новичок в 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>
"S.
Пока что я занимаюсь:
$.get(xmlPath, {}, function(xml) {
$("rs:data", xml).find("z:row").each(function(i) {
alert("found zrow");
});
}, "xml");
С действительно не повезло. Есть идеи? Благодарю.
20 ответов
Я понял.
Оказывается, это требует \\
чтобы избежать толстой кишки.
$.get(xmlPath, {}, function(xml) {
$("rs\\:data", xml).find("z\\:row").each(function(i) {
alert("found zrow");
});
}, "xml");
Как отметил Рич:
Лучшее решение не требует экранирования и работает во всех "современных" браузерах:
.find("[nodeName=z:row]")
Я потратил несколько часов на это чтение о плагинах и всевозможных решениях без удачи.
ArnisAndy опубликовал ссылку на обсуждение jQuery, где предлагается этот ответ, и я могу подтвердить, что это работает для меня в Chrome(v18.0), FireFox(v11.0), IE(v9.08) и Safari (v5.1.5)) с помощью jQuery (v1.7.2).
Я пытаюсь почистить ленту WordPress, где контент называется
content: $this.find("content\\:encoded, encoded").text()
Если вы используете jquery 1.5, вам нужно добавить кавычки вокруг значения атрибута селектора узла, чтобы он работал:
.find('[nodeName="z:row"]')
Хотя приведенный выше ответ кажется правильным, он не работает в браузерах webkit (Safari, Chrome). Я считаю, что лучшим решением будет:
.find("[nodeName=z:myRow, myRow]")
В случае, если кому-то нужно сделать это без 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;
}
Его можно легко изменить, если вам нужно вернуть все соответствующие элементы. Надеюсь, поможет!
Ни одно из вышеуказанных решений не работает так хорошо. Я нашел это и был улучшен для скорости. просто добавьте это, работал как шарм:
$.fn.filterNode = function(name) {
return this.find('*').filter(function() {
return this.nodeName === name;
});
};
использование:
var ineedthatelementwiththepsuedo = $('someparentelement').filterNode('dc:creator');
"\\" побег не является надежным и простым
.find('[nodeName="z:row"]')
Похоже, что метод был сломан в Jquery 1.7. Я смог найти решение для 1.7, используя функцию фильтра, здесь: Улучшение производительности Javascript XML-узла.
Стоит отметить, что в jQuery 1.7 были некоторые проблемы с поиском элементов пространства имен. Смотрите эти ссылки для получения дополнительной информации:
Найденное решение в комментарии: синтаксический анализ XML с пространствами имен с использованием jQuery $(). Find
Использование второй половины имени узла после двоеточия сработало для меня. Использовал .find("lat") вместо .find("geo\:lat"), и это сработало для меня.
Моя настройка:
- Chrome 42
- JQuery 2.1.3
Пример XML (фрагмент из API контактов 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>
Код разбора:
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
По состоянию на начало 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")
- Хром 44.0.2403.89м:
.find("row")
Синтаксис .find("[nodeName=z:row]")
не работает ни в одном из браузеров, упомянутых выше. Я не нашел способа применить пространство имен в Chrome.
Собрав все воедино, следующий синтаксис работает во всех браузерах, упомянутых выше: .find("row,z\\:row")
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.
Мое решение (потому что я использую прокси Php) состоит в том, чтобы заменить: namespace на _ ... так что больше никаких проблем с пространством имен;-)
Будь проще!
Оригинальный ответ: XML-анализ jQuery, как получить атрибут элемента
Вот пример того, как успешно получить значение в Chrome.
item.description = jQuery(this).find("[nodeName=itunes\\:summary]").eq(0).text();
Содержание: $this.find("content\\:encoded, encoded").text()
это идеальное решение...
Как упомянуто выше, есть проблемы с вышеупомянутым решением с текущими браузерами / версиями 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-xmlns для jQuery для работы с пространствами имен в селекторах.
Просто заменил пространство имен пустой строкой. У меня отлично работает. Проверенное решение для браузеров: Firefox, IE, Chrome
Моя задача состояла в том, чтобы прочитать и проанализировать EXCEL-файл через API-интерфейс REST Sharepoint EXCEL. XML-ответ содержит теги с пространством имен "x:".
Я решил заменить пространство имен в XML пустой строкой. Работает так: 1. Получить интересующий узел из XML-ответа 2. Преобразовать выбранный узел XML-Response (Document) в строку 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
Кроме того, вы можете использовать fast-xml-parser в своем проекте и конвертировать данные 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-parser.
Я не видел никакой документации по использованию JQuery для разбора XML. JQuery обычно использует Dom Browser для просмотра HTML-документа, я не верю, что он читает сам HTML.
Вероятно, вам стоит взглянуть на встроенную обработку XML в самом JavaScript.
http://www.webreference.com/programming/javascript/definitive2/
Для браузеров Webkit вы можете просто оставить двоеточие. Так что найти <media:content>
например, в ленте RSS вы можете сделать это:
$(this).find("content");