Análise XML de uma Cadeia de Caracteres Variável em JavaScript

204

Eu tenho uma seqüência de caracteres variável que contém XML bem formado e válido. Preciso usar o código JavaScript para analisar este feed.

Como posso fazer isso usando o código JavaScript (compatível com o navegador)?

David Bonnici
fonte

Respostas:

90

Atualização: para obter uma resposta mais correta, consulte a resposta de Tim Down .

O Internet Explorer e, por exemplo, os navegadores baseados no Mozilla expõem objetos diferentes para análise de XML, portanto, é aconselhável usar uma estrutura JavaScript como o jQuery para lidar com as diferenças entre navegadores.

Um exemplo realmente básico é:

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

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

Nota: Como indicado nos comentários; O jQuery realmente não faz nenhuma análise XML, ele depende do método DOM innerHTML e o analisará como se fosse um HTML, por isso tome cuidado ao usar nomes de elementos HTML no XML. Mas acho que funciona razoavelmente bem para simples 'análise' de XML, mas provavelmente não é sugerido para análise intensiva ou 'dinâmica' de XML, onde você não antecipa qual XML será baixado e testará se tudo for analisado conforme o esperado.

Sander Versluys
fonte
6
O código para abstrair a diferença na análise de XML entre o IE e outros navegadores é algumas linhas triviais, portanto não vale a pena apostar em 50K de jQuery por conta própria. Manipular o DOM do XML resultante é outra questão.
Tim Down
7
E algo que eu não percebi no momento de postar meu comentário anterior é que o jQuery nem analisa o XML, simplesmente o atribui como innerHTMLpropriedade de um elemento, o que não é de todo confiável.
Tim Down
Observe que o JQuery não suporta namespaces XML. Veja zachleat.com/web/2008/05/10/selecting-xml-with-javascript
mikemaccana
10
Esta resposta está errada. Consulte stackoverflow.com/questions/2124924/… , stackoverflow.com/questions/2908899/… , a resposta do Tim Down e a documentação do jQuery em si, onde afirma: "Observe que [ jQuery()] analisa HTML, não XML"
Crescent Fresh
2
@SanderVersluys: como o autor não está aceitando outra resposta, eu incluiria uma nota na sua resposta, com o link para a resposta correta do @ TimDown . Dessa forma, as pessoas não precisam ler todos esses comentários para descobrir a resposta correta.
Sensible
321

Resposta atualizada para 2017

A seguir, será analisada uma sequência XML em um documento XML em todos os principais navegadores. A menos que você precise de suporte para o IE <= 8 ou algum navegador obscuro, poderá usar a seguinte função:

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

Se você precisar oferecer suporte ao IE <= 8, o seguinte fará o trabalho:

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");
}

Depois de obter uma Documentvia parseXml, você pode usar os métodos / propriedades normais de travessia do DOM, como childNodese getElementsByTagName()para obter os nós que deseja.

Exemplo de uso:

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

Se você estiver usando o jQuery, a partir da versão 1.5, poderá usar seu parseXML()método interno, que é funcionalmente idêntico à função acima.

var xml = $.parseXML("<foo>Stuff</foo>");
alert(xml.documentElement.nodeName);
Tim Down
fonte
56
Eu concordo, essa resposta deve ser aceita. Minha resposta é tão antiga desde os primeiros dias, sempre achei curioso que ainda receba votos. Alguém a favor de remover minha resposta aceita? E o sistema de votação é falho? Voto positivo para este povo!
Sander Versluys
@SanderVersluys: Você é capaz de remover sua resposta?
Witman
1
Tive que recusar a votação por dizer que "não há outras respostas decentes". A resposta @SanderVersluys funcionou bem no meu caso. O que não é decente nisso, eu não sei.
19612 eric
2
@ EricTurner: Eu apoio e o próprio Sander negou sua resposta. Os documentos do jQuery dizem para você não usar $()para análise de XML . Leia os comentários com mais cuidado: ele simplesmente não funciona em muitas situações.
Tim Baixo
1
@DWoldrich: Eu vi as duas formas na web e suspeito que funcione nos dois sentidos. O mais próximo que posso encontrar de uma resposta oficial é msdn.microsoft.com/en-us/library/ms761398(v=vs.85).aspx , que diz que um booleano deve ser usado. No entanto, e quanto valor você atribui a isso depende inteiramente de você, o parseXML()método do jQuery usa uma string. Estou um pouco desconfiado de mudar a resposta, porque não tenho como testá-la agora.
Tim Baixo
19

A maioria dos exemplos na Web (e alguns apresentados acima) mostram como carregar um XML de um arquivo de maneira compatível com o navegador. Isso é fácil, exceto no caso do Google Chrome, que não suporta o document.implementation.createDocument()método. Ao usar o Chrome, para carregar um arquivo XML em um objeto XmlDocument, você precisa usar o objeto XmlHttp embutido e, em seguida, carregar o arquivo passando seu URI.

No seu caso, o cenário é diferente, porque você deseja carregar o XML de uma variável de sequência , não de um URL. No entanto, para esse requisito, o Chrome funciona exatamente como o Mozilla (ou pelo menos ouvi dizer) e suporta o método parseFromString ().

Aqui está uma função que eu uso (faz parte da biblioteca de compatibilidade do navegador que estou construindo):

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;
}
Cerebrus
fonte
16
Estou ciente das opiniões polêmicas sobre o cheiro do navegador e é por isso que não incluí essa função aqui. No entanto, ainda não foi estabelecido que está errado. De qualquer forma, este é um exemplo sugestivo .
Cerebrus 16/03/09
1
Eu acredito que está errado, pois você não pode garantir que está certo. Qualquer um pode falsificar as seqüências de caracteres UA, e é duvidoso que TODOS os navegadores que não sejam do IE suportem o DOMParser e que o farejador do navegador seja PERFEITO. Além disso, é muito mais fácil fazê-lo da maneira certa:if(window.ActiveXObject){...}
1j01
Então agora o IE9 + suporta o DOMParser , como você vai apoiar isso? -1 para o que @ 1j01 está dizendo. Tudo que você precisa verificar é 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)') }.
Annie
13

O Marknote é um bom analisador XML de JavaScript de navegador leve e leve. É orientado a objetos e tem muitos exemplos, além da API estar documentada. É relativamente novo, mas funcionou muito bem em um dos meus projetos até agora. Uma coisa que eu gosto é que ele lê XML diretamente de strings ou URLs e você também pode usá-lo para converter o XML em JSON.

Aqui está um exemplo do que você pode fazer com o 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") + "'"
    );
}
Mike McMillien
fonte
Parece que a nota implementa um analisador de javascript puro. Isso significa que ele deve ser compatível com qualquer motor de javascript, onde quer que seja usado em um navegador, em node.js ou em um motor independente javascript ...
Coyote
8

Eu sempre usei a abordagem abaixo, que funciona no IE e Firefox.

XML de exemplo:

<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);
      }
    }
  }
}
John Topley
fonte
Como você aceitaria um valor se tivesse essa situação <fruit> value </fruit>?
Siblja
1
@Siblja você precisa usar em innerTextvez de #getAttribute()
Manux22 /
8

Aparentemente, o jQuery agora fornece o jQuery.parseXML http://api.jquery.com/jQuery.parseXML/ a partir da versão 1.5

jQuery.parseXML( data ) Devoluções: XMLDocument

Jamie Pate
fonte
2

Por favor, dê uma olhada no XML DOM Parser ( W3Schools ). É um tutorial sobre análise XML DOM. O analisador DOM real difere de navegador para navegador, mas a API do DOM é padronizada e permanece a mesma (mais ou menos).

Como alternativa, use o E4X se você puder se restringir ao Firefox. É relativamente mais fácil de usar e faz parte do JavaScript desde a versão 1.6. Aqui está uma pequena amostra de uso ...

//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.
Autodidata
fonte
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>

Para obter mais informações, consulte este http://www.easycodingclub.com/xml-parser-in-javascript/javascript-tutorials/

easycodingclub
fonte
0

Isenção de responsabilidade : eu criei o analisador-xml-rápido

Eu criei o fast-xml-parser para analisar uma string XML no objeto JS / JSON ou no objeto transversal intermediário. Espera-se que seja compatível com todos os navegadores (porém testado apenas no Chrome, Firefox e IE).

Uso

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

Nota : Ele não usa o analisador DOM, mas analisa a sequência usando RE e a converte em objeto JS / JSON.

Experimente online , CDN

Amit Kumar Gupta
fonte
-1

Você também pode, através da função jquery ($. ParseXML), manipular a sequência xml

exemplo 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'))
})
user6016338
fonte