Разбор XML переменной строки в JavaScript


205

У меня есть переменная строка, которая содержит правильно сформированный и действительный XML. Мне нужно использовать код JavaScript для разбора этого канала.

Как я могу сделать это, используя (совместимый с браузером) код JavaScript?

Ответы:


91

Обновление: для более правильного ответа см. Ответ Тима Дауна .

Internet Explorer и, например, браузеры на основе Mozilla предоставляют различные объекты для синтаксического анализа XML, поэтому для обработки различий между браузерами целесообразно использовать среду JavaScript, такую ​​как jQuery .

Действительно простой пример:

var xml = "<music><album>Beethoven</album></music>";

var result = $(xml).find("album").text();

Примечание: как указано в комментариях; JQuery на самом деле не выполняет синтаксический анализ XML, он опирается на метод DOM innerHTML и анализирует его так же, как и любой другой HTML, поэтому будьте осторожны при использовании имен элементов HTML в своем XML. Но я думаю, что он довольно хорошо работает для простого «разбора» XML, но, вероятно, он не рекомендуется для интенсивного или «динамического» разбора XML, когда вы не знаете, что произойдет с XML, и он проверяет, все ли анализируется, как ожидалось.


6
Код для абстрагирования разницы в синтаксическом анализе XML между IE и другими браузерами состоит из нескольких тривиальных строк, поэтому не стоит использовать jKuery на 50 Кбайт. Манипулирование получающейся в результате DOM XML - это другой вопрос.
— Тим Даун

7
И что-то, чего я не осознавал во время публикации моего предыдущего комментария, это то, что jQuery даже не анализирует XML, он просто назначает его как innerHTMLсвойство элемента, что вовсе не надежно.
— Тим Даун

Обратите внимание, что JQuery не поддерживает пространства имен XML. См. Zachleat.com/web/2008/05/10/selecting-xml-with-javascript
— mikemaccana

10
Этот ответ неверен. См stackoverflow.com/questions/2124924/... , stackoverflow.com/questions/2908899/... , ответ @ Тим Дауна и сам Jquery документации , где говорится: «Обратите внимание , что [ jQuery()] разбирает HTML, а не XML»
— Crescent Fresh

2
@SanderVersluys: поскольку автор не принимает другой ответ, я бы добавил в ваш ответ примечание, содержащее ссылку на правильный ответ @ TimDown . Таким образом, людям не нужно читать все эти комментарии, чтобы найти правильный ответ.
— Чувственный

321

Обновленный ответ на 2017 год

Следующее будет анализировать строку XML в документ XML во всех основных браузерах. Если вам не нужна поддержка IE <= 8 или какой-то непонятный браузер, вы можете использовать следующую функцию:

function parseXml(xmlStr) {
   return new window.DOMParser().parseFromString(xmlStr, "text/xml");
}

Если вам нужно поддерживать IE <= 8, то сработает следующее:

var parseXml;

if (typeof window.DOMParser != "undefined") {
    parseXml = function(xmlStr) {
        return new window.DOMParser().parseFromString(xmlStr, "text/xml");
    };
} else if (typeof window.ActiveXObject != "undefined" &&
       new window.ActiveXObject("Microsoft.XMLDOM")) {
    parseXml = function(xmlStr) {
        var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = "false";
        xmlDoc.loadXML(xmlStr);
        return xmlDoc;
    };
} else {
    throw new Error("No XML parser found");
}

Получив Documentчерез parseXml, вы можете использовать обычные методы / свойства обхода DOM, такие как childNodesи, getElementsByTagName()чтобы получить нужные вам узлы.

Пример использования:

var xml = parseXml("<foo>Stuff</foo>");
alert(xml.documentElement.nodeName);

Если вы используете jQuery, начиная с версии 1.5 вы можете использовать его встроенный parseXML()метод, который функционально идентичен функции выше.

var xml = $.parseXML("<foo>Stuff</foo>");
alert(xml.documentElement.nodeName);

56
Я согласен, это должен быть принят ответ. Мой ответ так стар с первых дней, мне всегда было любопытно, что он все еще получает откаты. Кто-нибудь за удаление моего принятого ответа? И система голосования несовершенна? Уповните этим людям!
— Сандер Верслуйс

@SanderVersluys: Вы можете удалить свой ответ?
— Витман

1
Пришлось опровергнуть вас за то, что вы сказали, что «других достойных ответов нет». Ответ @SanderVersluys работал в моем случае нормально. Что не приличного в этом я не знаю.
— Эрик

2
@EricTurner: я поддерживаю это, и сам Сандер отрекся от его ответа. Документы jQuery говорят вам не использовать $()для разбора XML . Читайте комментарии более внимательно: во многих ситуациях это просто не работает.
— Тим Даун

1
@DWoldrich: я видел оба пути в Интернете, и я подозреваю, что это работает в обоих направлениях. Наиболее достоверный ответ , который я могу найти, - это msdn.microsoft.com/en-us/library/ms761398(v=vs.85).aspx , в котором говорится, что следует использовать логическое значение. Тем не менее, и то, какое значение вы вкладываете в это, полностью зависит от вас, метод jQueryparseXML() использует строку. Я немного опасаюсь изменить ответ, потому что у меня нет простого способа проверить это прямо сейчас.
— Тим Даун

19

Большинство примеров в сети (и некоторые из представленных выше) показывают, как загрузить XML из файла способом, совместимым с браузером. Это оказывается легко, за исключением случая с Google Chrome, который не поддерживает этот document.implementation.createDocument()метод. При использовании Chrome для загрузки файла XML в объект XmlDocument необходимо использовать встроенный объект XmlHttp, а затем загрузить файл, передав его URI.

В вашем случае сценарий другой, потому что вы хотите загрузить XML из строковой переменной , а не URL. Однако для этого требования Chrome предположительно работает так же, как Mozilla (или я так слышал), и поддерживает метод parseFromString ().

Вот функция, которую я использую (это часть библиотеки совместимости браузера, которую я сейчас создаю):

function LoadXMLString(xmlString)
{
  // ObjectExists checks if the passed parameter is not null.
  // isString (as the name suggests) checks if the type is a valid string.
  if (ObjectExists(xmlString) && isString(xmlString))
  {
    var xDoc;
    // The GetBrowserType function returns a 2-letter code representing
    // ...the type of browser.
    var bType = GetBrowserType();

    switch(bType)
    {
      case "ie":
        // This actually calls into a function that returns a DOMDocument 
        // on the basis of the MSXML version installed.
        // Simplified here for illustration.
        xDoc = new ActiveXObject("MSXML2.DOMDocument")
        xDoc.async = false;
        xDoc.loadXML(xmlString);
        break;
      default:
        var dp = new DOMParser();
        xDoc = dp.parseFromString(xmlString, "text/xml");
        break;
    }
    return xDoc;
  }
  else
    return null;
}

16
Мне известны противоречивые мнения относительно прослушивания браузера, и именно поэтому я не включил эту функцию здесь. Однако не было установлено, что это НЕПРАВИЛЬНО. В любом случае, это наводит на мысль примером.
— Cerebrus

1
Я считаю, что это неправильно, потому что вы не можете гарантировать, что это правильно. Любой может подделать строки UA, и сомнительно, что КАЖДЫЙ браузер, отличный от IE, поддерживает DOMParser, и что ваш сниффер в браузере - ИДЕАЛЬНЫЙ. И, кроме того, гораздо проще сделать это правильно:if(window.ActiveXObject){...}
— 1j01

Итак, теперь IE9 + поддерживает DOMParser , как вы собираетесь это поддерживать? -1 за то, что говорит @ 1j01. Все, что вам нужно проверить, это var dp; try{ dp = new DOMParser() } catch(e) { }; if(dp) { // DOMParser supported } else { // alert('you need to consider upgrading your browser\nOr pay extra money so developer can support the old versions using browser sniffing (eww)') }.
— Анни

13

Marknote - это удобный облегченный кросс-браузерный парсер XML XML. Он объектно-ориентированный, и у него множество примеров, а также документирование API . Это довольно новый, но до сих пор хорошо работал в одном из моих проектов. Мне нравится то, что он будет читать XML напрямую из строк или URL-адресов, и вы также можете использовать его для преобразования XML в JSON.

Вот пример того, что вы можете сделать с помощью Marknote:

var str = '<books>' +
          '  <book title="A Tale of Two Cities"/>' +
          '  <book title="1984"/>' +
          '</books>';

var parser = new marknote.Parser();
var doc = parser.parse(str);

var bookEls = doc.getRootElement().getChildElements();

for (var i=0; i<bookEls.length; i++) {
    var bookEl = bookEls[i];
    // alerts "Element name is 'book' and book title is '...'"
    alert("Element name is '" + bookEl.getName() + 
        "' and book title is '" + 
        bookEl.getAttributeValue("title") + "'"
    );
}

Кажется, что marknote реализует чистый анализатор javascript. Это означает, что он должен быть совместим с любым движком javascript, где бы он ни использовался в браузере, в node.js или в автономном движке javascript ...
— Coyote

8

Я всегда использовал подход ниже, который работает в IE и Firefox.

Пример XML:

<fruits>
  <fruit name="Apple" colour="Green" />
  <fruit name="Banana" colour="Yellow" />
</fruits>

JavaScript:

function getFruits(xml) {
  var fruits = xml.getElementsByTagName("fruits")[0];
  if (fruits) {
    var fruitsNodes = fruits.childNodes;
    if (fruitsNodes) {
      for (var i = 0; i < fruitsNodes.length; i++) {
        var name = fruitsNodes[i].getAttribute("name");
        var colour = fruitsNodes[i].getAttribute("colour");
        alert("Fruit " + name + " is coloured " + colour);
      }
    }
  }
}

Как бы вы взяли ценность, если бы у вас была такая ситуация <fruit> value </ fruit>?
— Сибля

1
@Siblja вам нужно использовать innerTextвместоgetAttribute()
— Manux22


2

Пожалуйста, посмотрите на XML DOM Parser ( W3Schools ). Это учебник по разбору XML DOM. Фактический парсер DOM отличается от браузера к браузеру, но API DOM стандартизирован и остается тем же самым (более или менее).

В качестве альтернативы используйте E4X, если вы можете ограничиться Firefox. Его относительно легче использовать, и он является частью JavaScript начиная с версии 1.6. Вот небольшой пример использования ...

//Using E4X
var xmlDoc=new XML();
xmlDoc.load("note.xml");
document.write(xmlDoc.body); //Note: 'body' is actually a tag in note.xml,
//but it can be accessed as if it were a regular property of xmlDoc.

0
<script language="JavaScript">
function importXML()
{
    if (document.implementation && document.implementation.createDocument)
    {
            xmlDoc = document.implementation.createDocument("", "", null);
            xmlDoc.onload = createTable;
    }
    else if (window.ActiveXObject)
    {
            xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
            xmlDoc.onreadystatechange = function () {
                    if (xmlDoc.readyState == 4) createTable()
            };
    }
    else
    {
            alert('Your browser can\'t handle this script');
            return;
    }
    xmlDoc.load("emperors.xml");
}

function createTable()
{
    var theData="";
    var x = xmlDoc.getElementsByTagName('emperor');
    var newEl = document.createElement('TABLE');
    newEl.setAttribute('cellPadding',3);
    newEl.setAttribute('cellSpacing',0);
    newEl.setAttribute('border',1);
    var tmp = document.createElement('TBODY');
    newEl.appendChild(tmp);
    var row = document.createElement('TR');
    for (j=0;j<x[0].childNodes.length;j++)
    {
            if (x[0].childNodes[j].nodeType != 1) continue;
            var container = document.createElement('TH');
            theData = document.createTextNode(x[0].childNodes[j].nodeName);
            container.appendChild(theData);
            row.appendChild(container);
    }
    tmp.appendChild(row);
    for (i=0;i<x.length;i++)
    {
            var row = document.createElement('TR');
            for (j=0;j<x[i].childNodes.length;j++)
            {
                    if (x[i].childNodes[j].nodeType != 1) continue;
                    var container = document.createElement('TD');
                    var theData = document.createTextNode(x[i].childNodes[j].firstChild.nodeValue);
                    container.appendChild(theData);
                    row.appendChild(container);
            }
            tmp.appendChild(row);
    }
    document.getElementById('writeroot').appendChild(newEl);
}
</script>
</HEAD>

<BODY onLoad="javascript:importXML();">
<p id=writeroot> </p>
</BODY>

Для получения дополнительной информации обратитесь к этому http://www.easycodingclub.com/xml-parser-in-javascript/javascript-tutorials/


0

Отказ от ответственности : я создал fast-xml-parser

Я создал fast-xml-parser для анализа строки XML в объект JS / JSON или промежуточный объект обхода. Ожидается, что он будет совместим во всех браузерах (однако протестирован только на Chrome, Firefox и IE).

использование

var options = { //default
    attrPrefix : "@_",
    attrNodeName: false,
    textNodeName : "#text",
    ignoreNonTextNodeAttr : true,
    ignoreTextNodeAttr : true,
    ignoreNameSpace : true,
    ignoreRootElement : false,
    textNodeConversion : true,
    textAttrConversion : false,
    arrayMode : false
};

if(parser.validate(xmlData)){//optional
    var jsonObj = parser.parse(xmlData, options);
}

//Intermediate obj
var tObj = parser.getTraversalObj(xmlData,options);
:
var jsonObj = parser.convertToJson(tObj);

Примечание : он не использует синтаксический анализатор DOM, но анализирует строку с использованием RE и преобразует ее в объект JS / JSON.

Попробуйте онлайн , CDN


-1

Вы также можете с помощью функции jquery ($. ParseXML) управлять строкой XML

пример JavaScript:

var xmlString = '<languages><language name="c"></language><language name="php"></language></languages>';
var xmlDoc = $.parseXML(xmlString);
$(xmlDoc).find('name').each(function(){
    console.log('name:'+$(this).attr('name'))
})
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.