Довольно печатать XML с помощью javascript

У меня есть строка, которая представляет собой не отступающий XML, который я бы хотел напечатать. Например:

<root><node/></root>

должен стать:

<root>
  <node/>
</root>

Выделение синтаксиса не является обязательным требованием. Чтобы решить проблему, я сначала преобразую XML, чтобы добавить возврат каретки и пробелы, а затем использовать

Ответ 1

Из текста вопроса создается впечатление, что ожидается результат строки, в отличие от результата в формате HTML.

Если это так, , самый простой способ добиться этого - обработать документ XML с помощью преобразования и с помощью <xsl:output indent="yes"/> инструкция:

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>

    <xsl:template match="node()|@*">
      <xsl:copy>
        <xsl:apply-templates select="node()|@*"/>
      </xsl:copy>
    </xsl:template>
</xsl:stylesheet>

Применяя это преобразование к предоставленному XML-документу:

<root><node/></root>

большинство XSLT-процессоров (.NET XslCompiledTransform, Saxon 6.5.4 и Saxon 9.0.0.2, AltovaXML) создают желаемый результат:

<root>
  <node />
</root>

Ответ 2

рассмотрим использование vkBeautify плагина

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

он написан на простом javascript, очень мал: менее 1,5 К, если его минитизировать, очень быстро: менее 5 мс. для обработки XML-текста 50K.

Ответ 3

Незначительная модификация функции javascript efnx clckclcks. Я изменил форматирование с пробелов на вкладку, но, самое главное, я разрешил текст оставаться в одной строке:

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 <?xml ... ?> declaration
            if (ln.match(/\s*<\?xml/)) {
                formatted += ln + "\n";
                continue;
            }
            // ---

            var single = Boolean(ln.match(/<.+\/>/)); // is this line a single tag? ex. <br />
            var closing = Boolean(ln.match(/<\/.+>/)); // is this a closing tag? ex. </a>
            var opening = Boolean(ln.match(/<[^!].*>/)); // is this even a tag (that 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;
    };

Ответ 4

Это можно сделать с помощью встроенных инструментов javascript, без сторонних библиотек, расширяя ответ @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
        '<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">',
        '  <xsl:strip-space elements="*"/>',
        '  <xsl:template match="para[content-style][not(text())]">', // change to just text() to strip space in text nodes
        '    <xsl:value-of select="normalize-space(.)"/>',
        '  </xsl:template>',
        '  <xsl:template match="node()|@*">',
        '    <xsl:copy><xsl:apply-templates select="node()|@*"/></xsl:copy>',
        '  </xsl:template>',
        '  <xsl:output indent="yes"/>',
        '</xsl:stylesheet>',
    ].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('<root><node/></root>'));

Выходы:

<root>
  <node/>
</root>

JSFiddle

Ответ 5

Personnaly, я использую google-code-prettify с этой функцией:

prettyPrintOne('<root><node1><root>', 'xml')

Ответ 6

Нашел эту ветку, когда у меня было похожее требование, но я упростил код OP следующим образом:

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

у меня работает!

Ответ 7

Или, если вам просто нужна другая функция js, я изменил Darin (много):

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. <br />
        var closing = Boolean(ln.match(/<\/.+>/)); // is this a closing tag? ex. </a>
        var opening = Boolean(ln.match(/<[^!].*>/)); // is this even a tag (that 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;
};

Ответ 8

Все приведенные здесь функции javascript не будут работать для XML-документа с неопределенными пробелами между конечным тегом ' > ' и стартовым тегом '<'. Чтобы исправить их, вам просто нужно заменить первую строку в функциях

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

по

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

Ответ 9

как насчет создания заглушки node (document.createElement('div') - или используя эквивалент вашей библиотеки), заполняя его строкой xml (через innerHTML) и вызывая простую рекурсивную функцию для корневого элемента/или элемент заглушки в случае, если у вас нет корня. Функция будет вызывать себя для всех дочерних узлов.

Затем вы можете синтаксически выделить на этом пути, убедитесь, что разметка хорошо сформирована (выполняется автоматически браузером при добавлении через innerHTML) и т.д. Это будет не так много кода и, вероятно, достаточно быстро.

Ответ 10

Если вы ищете решение для JavaScript, просто возьмите код из инструмента Pretty Diff в http://prettydiff.com/?m=beautify

Вы также можете отправлять файлы в инструмент с помощью параметра s, например: /fooobar.com/...

Ответ 12

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

Ответ 13

Or just print out the special HTML characters?

Ex: <xmlstuff>&#10; &#09;<node />&#10;</xmlstuff>   


&#09;   Horizontal tab  
&#10;   Line feed

Ответ 14

XMLSpectrum форматирует XML, поддерживает отступ атрибутов, а также выделяет синтаксис для XML и любых встроенных выражений XPath:

XMLSpectrum formatted XML

XMLSpectrum - проект с открытым исходным кодом, закодированный в XSLT 2.0, поэтому вы можете запускать эту серверную часть с процессором, например Saxon-HE (рекомендуется) или с клиентской стороны, используя Saxon-CE.

XMLSpectrum еще не оптимизирован для работы в браузере - следовательно, рекомендуется запустить эту серверную сторону.

Ответ 15

Используйте вышеописанный метод для красивой печати, а затем добавьте это в любой div с помощью метода jquery text(). например id id div xmldiv, то используйте:

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

Ответ 16

вот еще одна функция для форматирования 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 </
            if(xml.charAt(i+1) == '/'){
                inClosingTag = true;
                dent(--indent);
            }
            out+=c;
        }else if(c=='>'){
            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;
}

Ответ 17

Вы можете получить довольно отформатированный XML с помощью xml-beautify

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

отступ: шаблон отступа, как пробелы

useSelfClosingElement: true => использовать самозакрывающийся элемент, когда пустой элемент.

JSFiddle

Original (Перед)

<?xml version="1.0" encoding="utf-8"?><example version="2.0">
  <head><title>Original aTitle</title></head>
  <body info="none" ></body>
</example>

Приукрашена (После)

<?xml version="1.0" encoding="utf-8"?>
<example version="2.0">
  <head>
    <title>Original aTitle</title>
  </head>
  <body info="none" />
</example>

Ответ 18

var reg = /(>)\s*(<)(\/*)/g;
xml = xml.replace(/\r|\n/g, ''); //deleting already existing whitespaces
xml = xml.replace(reg, '$1\r\n$2$3');

Ответ 19

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

Эта библиотека работает для меня. Поддерживает вкладку, поддерживает веб-интерфейс и версию node. Также поддерживает JS, HTML, CSS. Также доступен как CDN.