我有一个字符串,表示我想要打印的非缩进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页面中漂亮打印吗?任何可以完成这项工作的javascript框架和/或插件都是受欢迎的。我唯一的要求是在客户端完成。
答案 0 :(得分:61)
考虑使用vkBeautify插件
http://www.eslinstructor.net/vkbeautify/
用简单的javascript编写,非常小:如果缩小则小于1.5K,非常快:小于5毫秒。处理50K XML文本。
答案 1 :(得分:54)
从问题的文字我得到的结果是预期字符串结果,而不是HTML格式的结果。
如果是这样,实现此目的的最简单方法是使用identity transformation和<xsl:output indent="yes"/>
指令处理XML文档:
<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 :(得分:31)
轻微修改efnx clckclcks的javascript函数。我将格式从空格更改为制表符,但最重要的是我允许文本保留在一行:
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;
};
答案 3 :(得分:19)
Personnaly,我使用google-code-prettify这个函数:
prettyPrintOne('<root><node1><root>', 'xml')
答案 4 :(得分:16)
这可以使用原生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>
答案 5 :(得分:10)
当我有类似的要求时找到这个帖子,但我简化了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);
}
适合我!
答案 6 :(得分:8)
或者如果你只是喜欢另外一个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;
};
答案 7 :(得分:7)
这个库完全符合您的要求!
答案 8 :(得分:6)
此处给出的所有javascript函数都不适用于在结束标记'&gt;'之间具有未指定空格的xml文档和开始标记'&lt;'。要修复它们,您只需要替换函数中的第一行
var reg = /(>)(<)(\/*)/g;
通过
var reg = /(>)\s*(<)(\/*)/g;
答案 9 :(得分:4)
如果您正在寻找JavaScript解决方案,请从http://prettydiff.com/?m=beautify
中的Pretty Diff工具中获取代码您还可以使用s参数将文件发送到工具,例如: http://prettydiff.com/?m=beautify&s=https://stackoverflow.com/
答案 10 :(得分:4)
如何创建存根节点(document.createElement('div') - 或使用等价的库),用xml字符串填充(通过innerHTML)并为根元素/或存根元素调用简单的递归函数如果你没有root。该函数将为所有子节点调用自身。
然后你可以沿途进行语法高亮,确保标记格式正确(通过innerHTML附加时由浏览器自动完成)等等。它不会那么多代码,而且可能足够快。
答案 11 :(得分:2)
使用上面的方法进行漂亮打印,然后使用jquery text()方法将其添加到任何div中。例如div的id是xmldiv
然后使用:
$("#xmldiv").text(formatXml(youXmlString));
答案 12 :(得分:2)
对于当前的项目,我需要在没有额外库的情况下对 XML 进行美化和着色。以下自包含代码运行良好。
function formatXml(xml,colorize,indent) {
function esc(s){return s.replace(/[-\/&<> ]/g,function(c){ // Escape special chars
return c==' '?' ':'&#'+c.charCodeAt(0)+';';});}
var sm='<div id="xmt">',se='<div id="xel">',sd='<div id="xdt">',
sa='<div id="xat">',tb='<div id="xtb">',tc='<div id="xtc">',
id=indent||' ',sz=tz='</div>',re=is='',ib,ob,at,i;
if (!colorize) sm=se=sd=sa=sz='';
xml.slice(1,-1).split(/>\s*</).forEach(function(nd){
ob=('<'+nd+'>').match(/^(<[!?\/]?)(.*?)([?\/]?>)$/); // Split outer brackets
ib=ob[2].match(/^(.*?)>(.*)<\/(.*)$/)||['',ob[2],'']; // Split inner brackets
at=ib[1].match(/^--.*--$|=|('|").*?\1|[^\t\n\f \/>"'=]+/g)||['']; // Split attributes
if (ob[1]=='</') is=is.substring(id.length); // Decrease indent
re+=tb+tc+esc(is)+tz+tc+sm+esc(ob[1])+sz+se+esc(at[0])+sz;
for (i=1;i<at.length;i++) re+=(at[i]=="="?sm+"="+sz+sd+esc(at[++i]):sa+' '+at[i])+sz;
re+=ib[2]?sm+esc('>')+sz+sd+esc(ib[2])+sz+sm+esc('</')+sz+se+ib[3]+sz:'';
re+=sm+esc(ob[3])+sz+tz+tz;
if (ob[1]+ob[3]+ib[2]=='<>') is+=id; // Increase indent
});
return re;
}
答案 13 :(得分:2)
您可以使用xml-beautify
获得格式精美的xml。var prettyXmlText = new XmlBeautify().beautify(xmlText,
{indent: " ",useSelfClosingElement: true});
缩进:缩进模式,例如空格
useSelfClosingElement :true =>在元素为空时使用自闭合元素。
原始(之前)
<?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>
答案 14 :(得分: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;
}
答案 15 :(得分:2)
XMLSpectrum格式化XML,支持属性缩进,并且还为XML和任何嵌入式XPath表达式进行语法突出显示:
XMLSpectrum是一个开源项目,用XSLT 2.0编写 - 因此您可以使用Saxon-HE(推荐)等处理器或使用Saxon-CE的客户端运行此服务器端。
XMLSpectrum尚未针对在浏览器中运行进行优化 - 因此建议运行此服务器端。
答案 16 :(得分:2)
Or just print out the special HTML characters?
Ex: <xmlstuff> 	<node /> </xmlstuff>
	 Horizontal tab
Line feed
答案 17 :(得分: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';
答案 18 :(得分:1)
https://www.npmjs.com/package/js-beautify
这个图书馆适合我。支持选项卡,支持Web和节点版本。还支持JS,HTML,CSS。也可作为CDN。
答案 19 :(得分:1)
var reg = /(>)\s*(<)(\/*)/g;
xml = xml.replace(/\r|\n/g, ''); //deleting already existing whitespaces
xml = xml.replace(reg, '$1\r\n$2$3');
答案 20 :(得分:0)
Xml-to-json库具有方法formatXml(xml).
,我是项目的维护者。
var prettyXml = formatXml("<a><b/></a>");
// <a>
// <b/>
// </a>
答案 21 :(得分:0)
这是我的版本,可能对其他人有用,使用String builder 看到有人使用相同的代码。
public String FormatXml(String xml, String tab)
{
var sb = new StringBuilder();
int indent = 0;
// find all elements
foreach (string node in Regex.Split(xml,@">\s*<"))
{
// if at end, lower indent
if (Regex.IsMatch(node, @"^\/\w")) indent--;
sb.AppendLine(String.Format("{0}<{1}>", string.Concat(Enumerable.Repeat(tab, indent).ToArray()), node));
// if at start, increase indent
if (Regex.IsMatch(node, @"^<?\w[^>]*[^\/]$")) indent++;
}
// correct first < and last > from the output
String result = sb.ToString().Substring(1);
return result.Remove(result.Length - Environment.NewLine.Length-1);
}
答案 22 :(得分:0)
您也可以使用 Saxon-JS 客户端:
<script src="SaxonJS/SaxonJS2.js"></script>
<script>
let myXML = `<root><node/></root>`;
SaxonJS.getResource({
text: myXML.replace(`xml:space="preserve"`, ''),
type: "xml"
}).then(doc => {
const output = SaxonJS.serialize(doc, {method: "xml", indent: true, "omit-xml-declaration":true});
console.log(output);
})
</script>
答案 23 :(得分:0)
XML 格式化可以通过解析 xml、在 dom 树中添加或更改文本节点以进行缩进,然后将 DOM 序列化回 xml 来完成。
请检查 https://jsonbrowser.sourceforge.io/formatxml.js 中的 formatxml 函数 您可以在 https://jsonbrowser.sourceforge.io/ 中看到正在运行的函数 在 Xml 标签下。
以下是简化代码。 formatxml.js 添加错误检查、可选删除注释、缩进作为参数并处理父节点之间的非空格文本。
const parser = new DOMParser();
const serializer = new XMLSerializer();
function formatXml(xml) {
let xmlDoc = parser.parseFromString(xml, 'application/xml');
let rootElement = xmlDoc.documentElement;
indentChildren(xmlDoc, rootElement, "\n", "\n ");
xml = serializer.serializeToString(xmlDoc);
return xml;
}
function indentChildren(xmlDoc, node, prevPrefix, prefix) {
let children = node.childNodes;
let i;
let prevChild = null;
let prevChildType = 1;
let child = null;
let childType;
for (i = 0; i < children.length; i++) {
child = children[i];
childType = child.nodeType;
if (childType != 3) {
if (prevChildType == 3) {
// Update prev text node with correct indent
prevChild.nodeValue = prefix;
} else {
// Create and insert text node with correct indent
let textNode = xmlDoc.createTextNode(prefix);
node.insertBefore(textNode, child);
i++;
}
if (childType == 1) {
let isLeaf = child.childNodes.length == 0 || child.childNodes.length == 1 && child.childNodes[0].nodeType != 1;
if (!isLeaf) {
indentChildren(xmlDoc, child, prefix, prefix + " ");
}
}
}
prevChild = child;
prevChildType =childType;
}
if (child != null) {
// Previous level indentation after last child
if (childType == 3) {
child.nodeValue = prevPrefix;
} else {
let textNode = xmlDoc.createTextNode(prevPrefix);
node.append(textNode);
}
}
}