Programing

자바 스크립트로 XML 인쇄하기

lottogame 2020. 7. 13. 08:09
반응형

자바 스크립트로 XML 인쇄하기


예쁜 인쇄하려는 들여 쓰기되지 않은 XML을 나타내는 문자열이 있습니다. 예를 들면 다음과 같습니다.

<root><node/></root>

되어야한다 :

<root>
  <node/>
</root>

구문 강조는 필수 사항이 아닙니다. 문제를 해결하기 위해 먼저 캐리지 리턴과 공백을 추가하도록 XML을 변환 한 다음 pre 태그를 사용 하여 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 페이지에서 예쁘게 인쇄하는 더 좋은 방법을 알고 있습니까? 작업을 수행 할 수있는 모든 자바 스크립트 프레임 워크 및 / 또는 플러그인을 환영합니다. 내 유일한 요구 사항은 클라이언트 측에서 수행해야합니다.


질문의 텍스트 에서 HTML 형식의 결과와 달리 문자열 결과가 예상된다는 인상을 얻습니다 .

이 경우 가장 간단한 방법은 ID 변환<xsl:output indent="yes"/>지침을 사용 하여 XML 문서를 처리하는 것입니다 .

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

    <xsl : template match = "node () | @ *">
      <xsl : 복사>
        <xsl : 적용 템플릿 select = "node () | @ *"/>
      </ xsl : copy>
    </ xsl : template>
</ xsl : stylesheet>

제공된 XML 문서에이 변환을 적용 할 때 :

<root> <노드 /> </ root>

대부분의 XSLT 프로세서 (.NET XslCompiledTransform, Saxon 6.5.4 및 Saxon 9.0.0.2, AltovaXML)는 원하는 결과를 생성합니다.

<루트>
  <노드 />
</ root>

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

이것은 타사 라이브러리없이 기본 자바 스크립트 도구를 사용하여 수행 할 수 있으며 @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


개인적으로, 나는 이 기능으로 google-code-prettify를 사용합니다 :

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

비슷한 요구 사항이 있었지만 다음과 같이 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);
}

나를 위해 일한다!


또는 다른 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'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;
};

여기에 주어진 모든 자바 스크립트 함수는 종료 태그 '>'와 시작 태그 '<'사이에 공백이 지정되지 않은 xml 문서에서 작동하지 않습니다. 그것들을 고치려면 함수의 첫 번째 줄만 바꾸면됩니다.

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

으로

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

스텁 노드 (document.createElement ( 'div')-또는 동등한 라이브러리 사용)를 작성하고 XML 문자열 (innerHTML을 통해)을 채우고 루트 요소 또는 스텁 요소에 대해 간단한 재귀 함수를 호출하는 경우는 어떻습니까? 뿌리가 없습니다. 이 함수는 모든 자식 노드에 대해 스스로를 호출합니다.

그런 다음 길을 따라 구문을 강조 표시하고 마크 업이 올바르게 구성되었는지 확인하십시오 (내부 HTML을 통해 추가 할 때 브라우저가 자동으로 수행함) 등 코드가 많지 않고 충분히 빠릅니다.


JavaScript 솔루션을 찾고 있다면 http://prettydiff.com/?m=beautify 의 Pretty Diff 도구에서 코드를 가져 오십시오.

s 매개 변수를 사용하여 파일을 도구로 보낼 수도 있습니다. http://prettydiff.com/?m=beautify&s=https://stackoverflow.com/


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: <xmlstuff>&#10; &#09;<node />&#10;</xmlstuff>   


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

XMLSpectrum은 XML을 형식화하고 속성 들여 쓰기를 지원하며 XML 및 모든 내장 XPath 표현식에 대해 구문 강조를 수행합니다.

XMLSpectrum formatted XML

XMLSpectrum은 XSLT 2.0으로 코딩 된 오픈 소스 프로젝트이므로 Saxon-HE (권장) 또는 Saxon-CE를 사용하는 클라이언트 측과 같은 프로세서로이 서버 측을 실행할 수 있습니다.

XMLSpectrum은 아직 브라우저에서 실행되도록 최적화되지 않았으므로이 서버 측을 실행하는 것이 좋습니다.


Use above method for pretty print and then add this in any div by using jquery text() method. for example id of div is xmldiv then use :

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


here is another function to format 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;
}

You can get pretty formatted xml with xml-beautify

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

indent:indent pattern like white spaces

useSelfClosingElement: true=>use self-closing element when empty element.

JSFiddle

Original(Before)

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

Beautified(After)

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

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

Xml-to-json library has method formatXml(xml). I am the maintainer of the project.

참고URL : https://stackoverflow.com/questions/376373/pretty-printing-xml-with-javascript

반응형