Impressão bonita XML com javascript

Eu tenho uma string que representa um XML não recortado que eu gostaria de imprimir bastante. Por exemplo:

 

Deve se tornar:

    

O realce de syntax não é um requisito. Para resolver o problema, primeiro eu transformo o XML para adicionar retornos de carro e espaços em branco e, em seguida, uso uma tag pré para gerar o XML. Para adicionar novas linhas e espaços em branco eu escrevi a seguinte function:

 function formatXml(xml) { var formatted = ''; var reg = /(>)(<)(\/*)/g; xml = xml.replace(reg, '$1\r\n$2$3'); var pad = 0; jQuery.each(xml.split('\r\n'), function(index, node) { var indent = 0; if (node.match( /.+]*>$/ )) { indent = 0; } else if (node.match( /^<\/\w/ )) { if (pad != 0) { pad -= 1; } } else if (node.match( /^]*[^\/]>.*$/ )) { indent = 1; } else { indent = 0; } var padding = ''; for (var i = 0; i < pad; i++) { padding += ' '; } formatted += padding + node + '\r\n'; pad += indent; }); return formatted; } 

Eu então chamo a function assim:

 jQuery('pre.formatted-xml').text(formatXml('')); 

Isso funciona perfeitamente bem para mim, mas enquanto eu estava escrevendo a function anterior eu pensei que deveria haver uma maneira melhor. Então, minha pergunta é que você conhece alguma maneira melhor dada uma string XML para imprimir em uma página html? Quaisquer frameworks javascript e / ou plugins que poderiam fazer o trabalho são bem-vindos. Minha única exigência é que isso seja feito no lado do cliente.

A partir do texto da pergunta, tenho a impressão de que um resultado de string é esperado , ao contrário de um resultado formatado em HTML.

Se isso for verdade, a maneira mais simples de conseguir isso é processar o documento XML com a transformação de identidade e com uma instrução :

 
  

     
       
         
       
     
 

Ao aplicar essa transformação no documento XML fornecido:

   

a maioria dos processadores XSLT (.NET XslCompiledTransform, Saxon 6.5.4 e Saxon 9.0.0.2, AltovaXML) produzem o resultado desejado:

 
   
 

considere usar o plugin vkBeautify

http://www.eslinstructor.net/vkbeautify/

está escrito em javascript simples, muito pequeno: menos de 1.5K se for reduzido, muito rápido: menos de 5 ms. para processar 50 mil texto XML.

Ligeira modificação da function javascript do efnx clckclcks. Alterei a formatação de espaços para tabulação, mas o mais importante é que deixei o texto permanecer em uma linha:

 var formatXml = this.formatXml = function (xml) { var reg = /(>)\s*(< )(\/*)/g; // updated Mar 30, 2015 var wsexp = / *(.*) +\n/g; var contexp = /(<.+>)(.+\n)/g; xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2'); var pad = 0; var formatted = ''; var lines = xml.split('\n'); var indent = 0; var lastType = 'other'; // 4 types of tags - single, closing, opening, other (text, doctype, comment) - 4*4 = 16 transitions var transitions = { 'single->single': 0, 'single->closing': -1, 'single->opening': 0, 'single->other': 0, 'closing->single': 0, 'closing->closing': -1, 'closing->opening': 0, 'closing->other': 0, 'opening->single': 1, 'opening->closing': 0, 'opening->opening': 1, 'opening->other': 1, 'other->single': 0, 'other->closing': -1, 'other->opening': 0, 'other->other': 0 }; for (var i = 0; i < lines.length; i++) { var ln = lines[i]; // Luca Viggiani 2017-07-03: handle optional  declaration if (ln.match(/\s*< \?xml/)) { formatted += ln + "\n"; continue; } // --- var single = Boolean(ln.match(/<.+\/>/)); // is this line a single tag? ex. 
var closing = Boolean(ln.match(/< \/.+>/)); // is this a closing tag? ex. var opening = Boolean(ln.match(/< [^!].*>/)); // is this even a tag (that's not < !something>) var type = single ? 'single' : closing ? 'closing' : opening ? 'opening' : 'other'; var fromTo = lastType + '->' + type; lastType = type; var padding = ''; indent += transitions[fromTo]; for (var j = 0; j < indent; j++) { padding += '\t'; } if (fromTo == 'opening->closing') formatted = formatted.substr(0, formatted.length - 1) + ln + '\n'; // substr removes line break (\n) from prev loop else formatted += padding + ln + '\n'; } return formatted; };

Pessoalmente, eu uso google-code-prettify com esta function:

 prettyPrintOne('', 'xml') 

Ou se você gostaria apenas de outra function js para fazer isso, eu modifiquei o Darin (muito):

 var formatXml = this.formatXml = function (xml) { var reg = /(>)(< )(\/*)/g; var wsexp = / *(.*) +\n/g; var contexp = /(<.+>)(.+\n)/g; xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2'); var pad = 0; var formatted = ''; var lines = xml.split('\n'); var indent = 0; var lastType = 'other'; // 4 types of tags - single, closing, opening, other (text, doctype, comment) - 4*4 = 16 transitions var transitions = { 'single->single' : 0, 'single->closing' : -1, 'single->opening' : 0, 'single->other' : 0, 'closing->single' : 0, 'closing->closing' : -1, 'closing->opening' : 0, 'closing->other' : 0, 'opening->single' : 1, 'opening->closing' : 0, 'opening->opening' : 1, 'opening->other' : 1, 'other->single' : 0, 'other->closing' : -1, 'other->opening' : 0, 'other->other' : 0 }; for (var i=0; i < lines.length; i++) { var ln = lines[i]; var single = Boolean(ln.match(/<.+\/>/)); // is this line a single tag? ex. 
var closing = Boolean(ln.match(/< \/.+>/)); // is this a closing tag? ex. var opening = Boolean(ln.match(/< [^!].*>/)); // is this even a tag (that's not < !something>) var type = single ? 'single' : closing ? 'closing' : opening ? 'opening' : 'other'; var fromTo = lastType + '->' + type; lastType = type; var padding = ''; indent += transitions[fromTo]; for (var j = 0; j < indent; j++) { padding += ' '; } formatted += padding + ln + '\n'; } return formatted; };

Isso pode ser feito usando ferramentas javascript nativas, sem libs de terceiros, estendendo a resposta do @Dimitre Novatchev:

 var prettifyXml = function(sourceXml) { var xmlDoc = new DOMParser().parseFromString(sourceXml, 'application/xml'); var xsltDoc = new DOMParser().parseFromString([ // describes how we want to modify the XML - indent everything '', ' ', ' ', // change to just text() to strip space in text nodes ' ', ' ', ' ', ' ', ' ', ' ', '', ].join('\n'), 'application/xml'); var xsltProcessor = new XSLTProcessor(); xsltProcessor.importStylesheet(xsltDoc); var resultDoc = xsltProcessor.transformToDocument(xmlDoc); var resultXml = new XMLSerializer().serializeToString(resultDoc); return resultXml; }; console.log(prettifyXml('')); 

Saídas:

    

JSFiddle

Todas as funções de javascript fornecidas aqui não funcionarão para um documento xml que tenha espaços em branco não especificados entre a tag de finalização ‘>’ e a tag de início ‘< '. Para consertá-los, você só precisa substituir a primeira linha nas funções

 var reg = /(>)(< )(\/*)/g; 

de

 var reg = /(>)\s*(< )(\/*)/g; 

Esta biblioteca faz exatamente o que você quer!

https://code.google.com/p/vkbeautify/

Que tal criar um nó de stub (document.createElement (‘div’) – ou usando o equivalente da biblioteca), preenchendo-o com a string xml (via innerHTML) e chamando a function recursiva simples para o elemento raiz / ou o elemento stub no caso de você não tem raiz. A function se chamaria para todos os nós filhos.

Você poderia, então, destacar a syntax ao longo do caminho, ter certeza de que a marcação é bem-formada (feita automaticamente pelo navegador ao append via innerHTML) etc. Não seria tanto código e provavelmente rápido o suficiente.

Se você estiver procurando por uma solução JavaScript, basta pegar o código da ferramenta Pretty Diff em http://prettydiff.com/?m=beautify

Você também pode enviar arquivos para a ferramenta usando o parâmetro s, como: http://prettydiff.com/?m=beautify&s=https://stackoverflow.com/

Encontrei este tópico quando tive um requisito semelhante, mas simplifiquei o código do OP da seguinte forma:

 function formatXml(xml, tab) { // tab = optional indent value, default is tab (\t) var formatted = '', indent= ''; tab = tab || '\t'; xml.split(/>\s*\r\n'; if (node.match( /^< ?\w[^>]*[^\/]$/ )) indent += tab; // increase indent }); return formatted.substring(1, formatted.length-3); } 

funciona para mim!

 var formatXml = this.formatXml = function (xml) { var reg = /(>)(< )(\/*)/g; var wsexp = / *(.*) +\n/g; var contexp = /(<.+>)(.+\n)/g; xml = xml.replace(reg, '$1\n$2$3').replace(wsexp, '$1\n').replace(contexp, '$1\n$2'); var pad = 0; var formatted = ''; var lines = xml.split('\n'); var indent = 0; var lastType = 'other'; 
 Or just print out the special HTML characters? Ex: 
 	
 	 Horizontal tab 
 Line feed 

XMLSpectrum formata XML, suporta indentação de atributo e também destaca a syntax para XML e quaisquer expressões XPath incorporadas:

XML formatado XMLSpectrum

O XMLSpectrum é um projeto de código aberto, codificado no XSLT 2.0 – assim você pode rodar este servidor com um processador como o Saxon-HE (recomendado) ou o lado do cliente usando o Saxon-CE.

O XMLSpectrum ainda não está otimizado para ser executado no navegador – daí a recomendação de executar esse servidor.

Use o método acima para impressão bonita e adicione isso em qualquer div usando o método jquery text () . por exemplo id de div é xmldiv então use:

$("#xmldiv").text(formatXml(youXmlString));

aqui está outra function para formatar xml

 function formatXml(xml){ var out = ""; var tab = " "; var indent = 0; var inClosingTag=false; var dent=function(no){ out += "\n"; for(var i=0; i < no; i++) out+=tab; } for (var i=0; i < xml.length; i++) { var c = xml.charAt(i); if(c=='<'){ // handle '){ out+=c; // handle /> if(xml.charAt(i-1) == '/'){ out+="\n"; //dent(--indent) }else{ if(!inClosingTag) dent(++indent); else{ out+="\n"; inClosingTag=false; } } }else{ out+=c; } } return out; } 
 var reg = /(>)\s*(< )(\/*)/g; xml = xml.replace(/\r|\n/g, ''); //deleting already existing whitespaces xml = xml.replace(reg, '$1\r\n$2$3'); 

https://www.npmjs.com/package/js-beautify

Esta biblioteca funciona para mim. Suporta tab, suporta web e versão do nó. Também suporta JS, HTML, CSS. Também disponível como CDN.

Você pode obter xml bem formatado com xml-embelezar

 var prettyXmlText = new XmlBeautify().beautify(xmlText, {indent: " ",useSelfClosingElement: true}); 

recuo : padrão de recuo como espaços em branco

useSelfClosingElement : true => use o elemento de fechamento automático quando o elemento vazio.

JSFiddle

Original (antes)

 < ?xml version="1.0" encoding="utf-8"?> Original aTitle   

Embelezado (depois)

 < ?xml version="1.0" encoding="utf-8"?>   Original aTitle