जावास्क्रिप्ट के साथ सुंदर मुद्रण XML


135

मेरे पास एक स्ट्रिंग है जो एक गैर इंडेंटेड एक्सएमएल का प्रतिनिधित्व करता है जिसे मैं सुंदर प्रिंट करना चाहता हूं। उदाहरण के लिए:

<root><node/></root>

बन जाना चाहिए:

<root>
  <node/>
</root>

सिंटेक्स हाइलाइटिंग एक आवश्यकता नहीं है। समस्या से निपटने के लिए मैं पहले गाड़ी के रिटर्न और सफेद रिक्त स्थान को जोड़ने के लिए XML को रूपांतरित करता हूं और फिर XML को आउटपुट करने के लिए एक पूर्व टैग का उपयोग करता हूं । नई लाइनों और सफेद रिक्त स्थान को जोड़ने के लिए मैंने निम्नलिखित फ़ंक्शन लिखा:

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( /.+<\/\w[^>]*>$/ )) {
            indent = 0;
        } else if (node.match( /^<\/\w/ )) {
            if (pad != 0) {
                pad -= 1;
            }
        } else if (node.match( /^<\w[^>]*[^\/]>.*$/ )) {
            indent = 1;
        } else {
            indent = 0;
        }

        var padding = '';
        for (var i = 0; i < pad; i++) {
            padding += '  ';
        }

        formatted += padding + node + '\r\n';
        pad += indent;
    });

    return formatted;
}

मैं तो इस तरह के समारोह कहते हैं:

jQuery('pre.formatted-xml').text(formatXml('<root><node1/></root>'));

यह मेरे लिए पूरी तरह से ठीक काम करता है लेकिन जब मैं पिछले समारोह को लिख रहा था तो मैंने सोचा कि एक बेहतर तरीका होना चाहिए। तो मेरा सवाल यह है कि क्या आप XML पेज को html पेज में सुंदर प्रिंट करने के लिए दिए गए किसी भी बेहतर तरीके से जानते हैं? कोई भी जावास्क्रिप्ट फ्रेमवर्क और / या प्लगइन्स जो काम कर सकते हैं उनका स्वागत है। मेरी एकमात्र आवश्यकता यह है कि क्लाइंट की तरफ से किया जाए।


2
एक फैंसी HTML आउटपुट (ala IE XML डिस्प्ले) के लिए, XPath विज़ुअलाइज़र में प्रयुक्त XSLT परिवर्तन देखें। आप XPath विज़ुअलाइज़र को यहां डाउनलोड कर सकते हैं: huttar.net/dimitre/XPV/TopXML-XPV.html
दिमित्रे नोवाचेव

/ .+<\/\w इस तरह के RegExp में "+" निकालें "+" को हटा दें क्योंकि यह "लंबे गुण मान" वाले नोड्स के लिए कुछ जावास्क्रिप्ट इंजन में कोड को धीमा कर देता है।
4esn0k

जवाबों:


58

प्रश्न के पाठ से मुझे यह आभास होता है कि एक स्ट्रिंग परिणाम अपेक्षित है HTML-स्वरूपित परिणाम के विपरीत, ।

यदि ऐसा है, तो इसे प्राप्त करने का सबसे सरल तरीका पहचान दस्तावेज के साथ एक्सएमएल दस्तावेज़ को संसाधित करना और एक <xsl:output indent="yes"/>निर्देश है :

<xsl: स्टाइलशीट संस्करण = "1.0"
 xmlns: XSL = "http://www.w3.org/1999/XSL/Transform">
 <xsl: आउटपुट omit-xml-घोषणापत्र = "हां" इंडेंट = "हां" />

    <xsl: टेम्पलेट मिलान = "नोड () | @ *">
      <XSL: प्रति>
        <xsl: एप्लाइड-टेम्प्लेट = "नोड () | @ *" /> का चयन करें
      </ XSL: प्रति>
    </ XSL: टेम्पलेट>
</ XSL: स्टाइलशीट>

प्रदान किए गए XML दस्तावेज़ पर इस परिवर्तन को लागू करते समय:

<जड़> <नोड /> </ जड़>

अधिकांश XSLT प्रोसेसर (.NET XslCompiledTransform, Saxon 6.5.4 और Saxon 9.0.0.2, AltovaXML) वांछित परिणाम का उत्पादन करते हैं:

<जड़>
  <नोड />
</ जड़>

3
यह एक महान समाधान की तरह दिखता है। क्या जावास्क्रिप्ट में इस परिवर्तन को लागू करने के लिए कोई क्रॉस ब्राउज़र तरीका है? मेरे पास भरोसा करने के लिए सर्वर साइड स्क्रिप्ट नहीं है।
डारिन दिमित्रोव

2
हाँ। सरीसा को देखें: dev.abiss.gr/sarissa और यहाँ: xml.com/pub/a/2005/02/23/sarissa.html
दिमित्रे नोवाचेचेव

6
@ सलाम: क्या "काम नहीं करता है"? "Chrome" क्या है? मैंने ऐसे XSLT प्रोसेसर के बारे में कभी नहीं सुना। इसके अलावा, यदि आप उत्तर की तारीख को देखते हैं, तो उस समय क्रोम ब्राउज़र न के बराबर था।
दिमित्रे नोवत्चेव

3
@ बारमफ़: यह भी ध्यान दें कि यह प्रश्न (और मेरा उत्तर) इसे एक्सएमएल को एक स्ट्रिंग (पाठ) के रूप में प्राप्त करना है, न कि एचटीएमएल। कोई आश्चर्य नहीं कि एक ब्राउज़र में ऐसी स्ट्रिंग प्रदर्शित नहीं होती है। फैंसी HTML आउटपुट (ala IE XML डिस्प्ले) के लिए, XPath विज़ुअलाइज़र में प्रयुक्त XSLT परिवर्तन देखें। आप XPath विज़ुअलाइज़र को huttar.net/dimitre/XPV/TopXML-XpV.html पर डाउनलोड कर सकते हैं । आपको कोड को थोड़ा समायोजित करने की आवश्यकता हो सकती है (जैसे कि नोड को ढहाने / विस्तार करने के लिए जावास्क्रिप्ट एक्सटेंशन फ़ंक्शन को हटाने के लिए), लेकिन अन्यथा परिणामी HTML को ठीक प्रदर्शित करना चाहिए।
दिमित्रे नोवत्चेव

2
जॉनक, 2008 में, जब इस सवाल का जवाब दिया गया था, तो लोग IE में जावास्क्रिप्ट से XSLT रूपांतरण शुरू कर रहे थे - MSXML3 का आह्वान। अब वे अभी भी ऐसा कर सकते हैं, हालांकि IE11 के साथ आने वाला XSLT प्रोसेसर MSXML6 है। अन्य सभी ब्राउज़रों में समान क्षमताएं हैं, हालांकि उनके पास अलग-अलग निर्मित एक्सएसएलटी प्रोसेसर हैं। यही कारण है कि मूल प्रश्नकर्ता ने कभी ऐसा प्रश्न नहीं उठाया।
दिमित्रे नोवाचेव

32

एफएफ़एक्स क्लेक्लेक्स की जावास्क्रिप्ट फ़ंक्शन का थोड़ा संशोधन। मैंने स्थानों से टैब में स्वरूपण को बदल दिया है, लेकिन सबसे महत्वपूर्ण बात यह है कि मैंने पाठ को एक पंक्ति में बने रहने दिया:

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

क्या आप चुआन मा की टिप्पणी को ध्यान में रखते हुए अपने कार्य को अद्यतन कर सकते हैं? मेरे लिए काम किया। धन्यवाद। संपादित करें: मैंने इसे स्वयं किया।
लुई एलसी

1
नमस्ते, मैंने वैकल्पिक रूप से सही ढंग से संभालने के लिए आपके फ़ंक्शन में थोड़ा सुधार किया है <?xml ... ?> XML पाठ की शुरुआत में घोषणा
lviggiani

31

यह 3 पार्टी के काम के बिना, देशी जावास्क्रिप्ट टूल का उपयोग करके किया जा सकता है, @Dimitre नोवाचेचेस के उत्तर का विस्तार:

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

नोट, जैसा कि @ jat255 द्वारा बताया गया है, बहुत बढ़िया प्रिंटिंग <xsl:output indent="yes"/>फ़ायरफ़ॉक्स द्वारा समर्थित नहीं है। यह केवल क्रोम, ओपेरा और शायद बाकी वेबकिट-आधारित ब्राउज़रों में काम करता है।


बहुत अच्छा जवाब है, लेकिन दुर्भाग्य से इंटरनेट एक्सप्लोरर। पार्टी फिर से।
वारुयामा

अच्छा है, यह केवल तभी काम करता है जब इनपुट xml सिंगल लाइन हो ... यदि आप टेक्स्ट नोड्स में मल्टी लाइनों के बारे में परवाह नहीं करते हैं, तो प्रीटीफाई करने से पहले, कॉल करेंprivate makeSingleLine(txt: string): string { let s = txt.trim().replace(new RegExp("\r", "g"), "\n"); let angles = ["<", ">"]; let empty = [" ", "\t", "\n"]; while (s.includes(" <") || s.includes("\t<") || s.includes("\n<") || s.includes("> ") || s.includes(">\t") || s.includes(">/n")) { angles.forEach(an => { empty.forEach(em => { s = s.replace(new RegExp(em + an, "g"), an); }); }); } return s.replace(new RegExp("\n", "g"), " "); }
साशा बॉन्ड

5
मुझे एक त्रुटि मिलती है, लेकिन त्रुटि का कोई संदेश नहीं है। यह फ़ायरफ़ॉक्स का उपयोग करके फ़िडल में भी होता है।
टॉम ज़ातो -

यह भी फ़ायरफ़ॉक्स में एक रिक्त त्रुटि के साथ मेरे लिए काम नहीं कर रहा है
jat255

1
इस पर चर्चा की जाती है: stackoverflow.com/questions/51989864/… जाहिर है, फ़ायरफ़ॉक्स को xsl के लिए एक संस्करण विनिर्देशन की आवश्यकता है, लेकिन यह वैसे भी कोई फर्क नहीं पड़ता क्योंकि मोज़िला कार्यान्वयन किसी भी xsl:outputटैग का सम्मान नहीं करता है , इसलिए आपको अच्छा नहीं मिलेगा वैसे भी स्वरूपण।
जाट 25

19

वैयक्तिक रूप से, मैं इस फ़ंक्शन के साथ Google-कोड-पूर्व- उपयोग करता हूं :

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

3
Oups, आपको XML को इंडेंट करने की आवश्यकता है और Google-code-prettify- केवल कोड को रंगीन किया जाएगा। माफ़ करना।
तौव


3
यह एक अच्छे कॉम्बो के लिए किए गए इंडेंटेशन के लिए code.google.com/p/vkbeautify के साथ संयुक्त है ।
Vdex

Google कोड से github.New लिंक पर ले जाया गया: github.com/google/code-prettify
mUser1990

18

जब मुझे एक समान आवश्यकता हुई तो मैंने यह धागा पाया लेकिन मैंने ओपी के कोड को निम्न प्रकार से सरल किया:

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

मेरे लिये कार्य करता है!


सबसे अच्छा जवाब !!
Jcc.Sanabria

8

या यदि आप इसे करने के लिए एक और js फ़ंक्शन पसंद करते हैं, तो मैंने डारिन को संशोधित किया है (बहुत):

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

6

यहाँ दिए गए सभी जावास्क्रिप्ट कार्य अंतिम टैग '>' और प्रारंभ टैग '<' के बीच अनिर्दिष्ट सफेद रिक्त स्थान वाले xml दस्तावेज़ के लिए काम नहीं करेंगे। उन्हें ठीक करने के लिए, आपको केवल फ़ंक्शन में पहली पंक्ति को बदलने की आवश्यकता है

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

द्वारा

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

4

स्टब नोड बनाने के बारे में क्या है (डॉक्यूमेंट.क्रीट ई-क्लेमेंट ('div') - या अपनी लाइब्रेरी समतुल्य का उपयोग करके), इसे xml स्ट्रिंग (आंतरिक HTML के माध्यम से) से भरना और आपके मामले में मूल तत्व / या स्टब एलिमेंट के लिए सरल पुनरावर्ती फ़ंक्शन को कॉल करना। जड़ नहीं है। फ़ंक्शन सभी चाइल्ड नोड्स के लिए खुद को कॉल करेगा।

तब आप सिंटैक्स-हाइलाइट कर सकते हैं, निश्चित हो कि मार्कअप अच्छी तरह से बना हो (इनरएचटीएमएल के माध्यम से अपग्रेड करते समय ब्राउज़र द्वारा स्वचालित रूप से किया जाता है) आदि यह इतना कोड नहीं होगा और शायद बहुत तेजी से।


1
एक अद्भुत, सुरुचिपूर्ण समाधान के लिए रूपरेखा की तरह लगता है। एक कार्यान्वयन के बारे में कैसे?
23

4

यदि आप एक जावास्क्रिप्ट समाधान की तलाश कर रहे हैं, तो बस प्रीटी डिफ टूल से कोड लें http://prettydiff.com/?m=beautify

आप एस पैरामीटर का उपयोग करके टूल को फाइल भी भेज सकते हैं, जैसे: http://prettydiff.com/?m=beautify&s=https://stackoverflow.com/


prettydiff एक वास्तविक अच्छा उपकरण है। यहां उपयोग के बारे में कुछ और जानकारी दी गई है: stackoverflow.com/questions/19822460/pretty-diff-usage/…
bob

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

इस खराब गठित उत्तर के साथ संघर्ष करने के बाद, मुझे यह काम करने के लिए मिला, मुझे लगता है - परिणाम बहुत सुंदर नहीं हैं: कोई इंडेंटेशन नहीं।
जॉन


2

XMLSpectrum प्रारूप XML, विशेषता इंडेंटेशन का समर्थन करता है और XML और किसी भी एम्बेडेड XPath अभिव्यक्तियों के लिए सिंटैक्स-हाइलाइटिंग भी करता है:

XMLSpectrum XML स्वरूपित

XMLSpectrum एक ओपन सोर्स प्रोजेक्ट है, जिसे XSLT 2.0 में कोड किया गया है - इसलिए आप Saxon-CE का उपयोग करके इस सर्वर-साइड को Saxon-HE (अनुशंसित) या क्लाइंट-साइड जैसे प्रोसेसर के साथ चला सकते हैं।

XMLSpectrum ब्राउज़र में चलाने के लिए अभी तक अनुकूलित नहीं है - इसलिए इस सर्वर-साइड को चलाने की सिफारिश की गई है।


2

सुंदर प्रिंट के लिए उपरोक्त विधि का उपयोग करें और फिर jquery पाठ () विधि का उपयोग करके इसे किसी भी div में जोड़ें । उदाहरण के लिए div की आईडी का xmldivउपयोग तब किया जाता है :

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


2
क्या "सुंदर प्रिंट के लिए उपरोक्त विधि"?
जेडब्ल्यू लिम

2

यहाँ 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;
}

2

आप xml-beautify के साथ सुंदर स्वरूपित xml प्राप्त कर सकते हैं

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

मांगपत्र : इंडेंट पैटर्न जैसे व्हाइट स्पेस

useSelfClosingElement : true => रिक्त तत्व का उपयोग करते समय स्व-समापन तत्व का उपयोग करें।

JSFiddle

मूल (पहले)

<?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>

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.