112

Tôi có một chuỗi đại diện cho một XML không thụt lề mà tôi muốn in đẹp. Ví dụ:

<root><node/></root>

nên trở thành:

<root>
  <node/>
</root>

Làm nổi bật cú pháp không phải là một yêu cầu. Để giải quyết vấn đề, trước tiên tôi chuyển đổi XML để thêm lợi nhuận vận chuyển và khoảng trắng và sau đó sử dụng thẻ trước để xuất XML. Để thêm dòng mới và khoảng trắng tôi đã viết hàm sau:

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

Sau đó tôi gọi hàm như thế này:

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

Điều này hoạt động hoàn toàn tốt cho tôi nhưng trong khi tôi đang viết chức năng trước đó tôi nghĩ rằng phải có một cách tốt hơn. Vì vậy, câu hỏi của tôi là bạn có biết cách nào tốt hơn để đưa ra một chuỗi XML để in nó trong một trang html không? Bất kỳ khung javascript và / hoặc plugin nào có thể thực hiện công việc đều được chào đón. Yêu cầu duy nhất của tôi là điều này phải được thực hiện ở phía khách hàng.

|
54

Từ văn bản của câu hỏi, tôi có ấn tượng rằng một kết quả chuỗi được mong đợi , trái ngược với kết quả được định dạng HTML.

Nếu đúng như vậy, cách đơn giản nhất để đạt được điều này là xử lý tài liệu XML bằng cách chuyển đổi danh tính và bằng một <xsl:output indent="yes"/>hướng dẫn :

<xsl: bản định kiểu = "1.0"
 xmlns: xsl = "http://www.w3.org/1999/XSL/Transform">
 <xsl: output omit-xml-kê khai = "yes" indent = "yes" />

    <xsl: template match = "node () | @ *">
      <xsl: sao chép>
        <xsl: application-samples select = "node () | @ *" />
      </ xsl: sao chép>
    </ xsl: mẫu>
</ xsl: biểu định kiểu>

Khi áp dụng chuyển đổi này trên tài liệu XML được cung cấp:

<root> <nút /> </ root>

hầu hết các bộ xử lý XSLT (.NET XslCompiledTransform, Saxon 6.5.4 và Saxon 9.0.0.2, AltovaXML) tạo ra kết quả mong muốn:

<root>
  <nút />
</ root>
|
  • 1

    Nó trông giống như một giải pháp tuyệt vời. Có cách nào trình duyệt chéo để áp dụng chuyển đổi này trong javascript không? Tôi không có một kịch bản phía máy chủ để dựa vào.

    – Hoàng Thiếu Cường 08:06:47 18/12/2008
  • 1
  • 1

    Điều này không hoạt động trên chrome. Tôi nên kiểm tra nếu Sarissa hoạt động trên chrome đầu tiên. Đã lãng phí gần một giờ về việc này.

    – Trịnh Gia Bạch 04:18:33 25/01/2011
  • 1

    @ablmf: "Không hoạt động" là gì? "Chrome" là gì? Tôi chưa bao giờ nghe nói về bộ xử lý XSLT như vậy. Ngoài ra, nếu bạn xem ngày trả lời, trình duyệt Chrome không tồn tại vào thời điểm đó.

    – Hoàng Quỳnh Loan 04:38:22 25/01/2011
  • 1

    @ablmf: Cũng lưu ý rằng câu hỏi này (và câu trả lời của tôi cho câu hỏi này) là lấy XML khá đẹp dưới dạng chuỗi (văn bản) chứ không phải HTML. Không có gì ngạc nhiên khi một chuỗi như vậy không hiển thị trong trình duyệt. Để có đầu ra HTML ưa thích (hiển thị ala IE XML), hãy xem phép chuyển đổi XSLT được sử dụng trong XPath Visualizer. Bạn có thể tải xuống Trình hiển thị XPath tại: huttar.net/dimitre/XPV/TopXML-XPV.html . Bạn có thể cần điều chỉnh mã một chút (chẳng hạn như để loại bỏ các chức năng mở rộng javascript để thu gọn / mở rộng một nút), nhưng nếu không thì HTML kết quả sẽ hiển thị tốt.

    – Hoàng Hải Phong 04:47:08 25/01/2011
61

xem xét sử dụng plugin vkBeautify

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

nó được viết bằng javascript đơn giản, rất nhỏ: ít hơn 1,5K nếu được rút gọn, rất nhanh: ít hơn 5 msec. để xử lý văn bản XML 50K.

|
31

Sửa đổi nhẹ chức năng javascript của efnx clckclcks. Tôi đã thay đổi định dạng từ dấu cách sang tab, nhưng quan trọng nhất là tôi cho phép văn bản duy trì trên một dòng:

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

    bạn có thể vui lòng cập nhật chức năng của mình để xem xét nhận xét của Chuan Ma bên dưới không? Đã làm cho tôi. Cảm ơn. Chỉnh sửa: Tôi chỉ làm điều đó bản thân mình.

    – Đỗ Phước Nhân 20:47:14 30/03/2015
  • 1

    Xin chào, tôi đã cải thiện một chút chức năng của bạn để xử lý chính xác <?xml ... ?>khai báo tùy chọn ở đầu văn bản XML

    – Hoàng Ngọc Cường 14:11:16 03/07/2017
19

Cá nhân, tôi sử dụng google-code-prettify với chức năng này:

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

Điều này có thể được thực hiện bằng các công cụ javascript gốc, không có lib của bên thứ 3, mở rộng câu trả lời của @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>'));

Đầu ra:

<root>
  <node/>
</root>

Câu đố

|
  • 1

    Câu trả lời rất hay, nhưng không may là Internet Explorer. Hãy tổ chức lại bữa tiệc.

    – Tạ Mỹ Tâm 13:33:39 05/01/2018
  • 1

    thật tuyệt, nó chỉ hoạt động khi đầu vào xml là một dòng duy nhất ... nếu bạn không quan tâm đến nhiều dòng trong các nút văn bản, trước khi gọi prettify, hãy gọiprivate 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"), " "); }

    – Dương Thu Ngà 17:39:00 13/06/2018
  • 1

    Tôi nhận được một lỗi, nhưng lỗi không có tin nhắn. Nó cũng xảy ra trong fiddle, sử dụng firefox.

    – Lý Vân Sơn 15:51:00 23/08/2018
10

Tìm thấy chủ đề này khi tôi có một yêu cầu tương tự nhưng tôi đã đơn giản hóa mã của OP như sau:

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

làm việc cho tôi

|
8

Hoặc nếu bạn chỉ thích một chức năng js khác để làm điều đó, tôi đã sửa đổi Darin (rất nhiều):

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

Thư viện này làm chính xác những gì bạn muốn!

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

|
6

Tất cả các hàm javascript được cung cấp ở đây sẽ không hoạt động đối với tài liệu xml có khoảng trắng không xác định giữa thẻ kết thúc '>' và thẻ bắt đầu '<'. Để sửa chúng, bạn chỉ cần thay thế dòng đầu tiên trong các chức năng

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

bởi

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

Nếu bạn đang tìm kiếm một giải pháp JavaScript, chỉ cần lấy mã từ công cụ Pretty Diff tại http://prettydiff.com/?m=beautify

Bạn cũng có thể gửi tệp đến công cụ bằng tham số s, chẳng hạn như: http://prettydiff.com/?m=beautify&s=https://stackoverflow.com/

|
4

Điều gì về việc tạo một nút sơ khai (document.createEuity ('div') - hoặc sử dụng thư viện của bạn tương đương), điền vào chuỗi xml (thông qua InternalHTML) và gọi hàm đệ quy đơn giản cho phần tử gốc / hoặc phần tử gốc trong trường hợp bạn không có gốc. Hàm sẽ tự gọi cho tất cả các nút con.

Sau đó, bạn có thể tô sáng cú pháp trên đường đi, chắc chắn rằng đánh dấu được hình thành tốt (được trình duyệt tự động thực hiện khi nối thêm qua InternalHTML), v.v. Nó sẽ không đủ mã và có thể đủ nhanh.

|
2

Bạn có thể nhận được xml được định dạng đẹp với xml-beautify

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

thụt lề : mô hình thụt lề như khoảng trắng

useSelfClosesEuity : true => sử dụng phần tử tự đóng khi phần tử trống.

Câu đố

Bản gốc (Trước)

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

Làm đẹp (Sau)

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

đây là một chức năng khác để định dạng 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

Sử dụng phương thức trên cho bản in đẹp và sau đó thêm phần này vào bất kỳ div nào bằng cách sử dụng phương thức jquery text () . ví dụ id của div xmldivthì sử dụng:

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

|
2

XMLSpectrum định dạng XML, hỗ trợ thụt lề thuộc tính và cũng làm nổi bật cú pháp cho XML và bất kỳ biểu thức XPath nhúng nào:

XMLSpectrum là một dự án nguồn mở, được mã hóa trong XSLT 2.0 - vì vậy bạn có thể chạy phía máy chủ này với bộ xử lý như Saxon-HE (được khuyến nghị) hoặc phía máy khách sử dụng Saxon-CE.

XMLSpectrum chưa được tối ưu hóa để chạy trong trình duyệt - do đó khuyến nghị nên chạy phía máy chủ này.

|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.