Разбор 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.