Main Menu

xml pretty print

Started by RJP74, June 27, 2013, 07:33:38 PM

Previous topic - Next topic

RJP74

I am evaluating editors and one of my needs is to be able to convert a one line xml string into a human readable form.
As I didn't find such a function I wrote a simple script to do this to see how easy the scripting is to use.
Access it as needed from the tools menu. I did not implement any integration with HippoEdit Menus.

here is the code - also in an attachment. :)

Code (javascript) Select
#include "he_utils.js" // generic helper functions

AddScriptInfo("0BE253F8-BE23-4B7C-928C-38293F18C9D2", "XMLPrettyPrint", "1.0.0.0", "XML Pretty Print", "HippoEDIT", "rjp", "none");

var sel = ActiveView.Selection;
if ( sel.IsEmpty )
sel = new Range(0, 0, ActiveDocument.LineCount - 1, ActiveDocument.GetLineLength(ActiveDocument.LineCount - 1));
var SelectedText = ActiveView.Document.GetText(sel);

var xmlNew = xmlPP(SelectedText);
ActiveDocument.ReplaceText(sel, xmlNew, AddUndoActionType("XMLPrettyPrint"));

function xmlPP(xml) {
var reg = /(>)(<)(\/*)/g;
var xmlNew = xml.replace(reg, "$1\r\n$2$3"); // split into separate lines
var xmlArray = xmlNew.split("\r\n"); // split into an array.
var currentIndent = 0;
var formatted = "";

for (var ixml = 0; ixml < xmlArray.length; ixml++) {
var node = xmlArray[ixml];
node = node.replace(/^\s+/g, ''); // left trim function in case already formatted
node = node.replace(/\s+$/g, ''); // right trim function in case already formatted
if (node.length > 0) {   // eliminate blank lines
var nextIndent = 0;
var leftFill = "";

// work out how much to indent
if (node.match(/.+<\/\w[^>]*>$/)) {} // ignore these
else if (node.match(/^<\/\w/)) { // terminator - decrease padding
if (currentIndent > 0) currentIndent -= 1; }
else if (node.match(/^<\w[^>]*[^\/]>.*$/)) // indent - next node not this.
nextIndent = 1;

//create the indent
for (var i = 0; i < currentIndent; i++) {leftFill += "   ";} // uses 3 spaces per indent.
formatted += leftFill + node + "\r\n";
currentIndent += nextIndent;
}
}
return formatted;
}


alex

Hi RJP74,

That is cool!

If you not aware, we offer free license for new script/plugin.
And because the script is valuable, you was able to create it even without API documentation ;) and you are actually the first who have created some new script (except of me) - you got a free license. Please send me a private message (or mail to supportbox at hippoedit) with name you want to use for registration and email, I send you a license key then.

Because as I said the function you added is actually rather useful, I have reworked your code a little bit and converted into a plug-in (you do not need AddScriptInfo if use only as tool script).
It now integrates much better into HE and replaces standard formatting commands (FormatSelection and FormatAll) if you call if in any XML inherited source file. Similar like JS beautifier plugin does.

Please review, if all is OK, I can publish it then in library, to be available from online repository.
Code (javascript) Select
#include "he_utils.js" // generic helper functions
#import "es5.js"

AddScriptInfo("0BE253F8-BE23-4B7C-928C-38293F18C9D2", "XMLPrettyPrint", "1.0.0.0", "XML Pretty Print", "rjp");

Application.onTextFormat = function(sel, bIndent) {
var syntax = this.GetStyleFromPos(sel.Start).Style.Syntax;
if (syntax.IsInheritedFrom("xml")) {
if (sel.IsEmpty) sel = new Range(0, 0, ActiveDocument.LineCount - 1, ActiveDocument.GetLineLength(ActiveDocument.LineCount - 1));
var text = ax2js(this.GetLines(sel, false)).join("");
if (text != "")
this.ActiveView.Position = this.ReplaceText(sel, xmlPP(text, this.LineBreak, mul(" ", this.IndentSize)), AddUndoActionType("XML Pretty Print"));
return true;
}
return false;
}

function mul(str, num) {
return num ? Array(num + 1).join(str) : "";
}

function xmlPP(xml, lb, defaultIndent) {
var xmlNew = xml.replace(/>\s*</g, ">\r\n<"); // split into separate lines
var xmlArray = xmlNew.split("\r\n"); // split into an array
var currentIndent = 0;
var formatted = "";

for (var ixml = 0; ixml < xmlArray.length; ixml++) {
var node = xmlArray[ixml];
node = node.trim(); // trim leading/trailing spaces
if (node.length > 0) { // eliminate blank lines
var nextIndent = 0;

// work out how much to indent
if (node.match(/.+<\/\w[^>]*>$/)) {} // ignore these
else if (node.match(/^<\/\w/)) { // terminator - decrease padding
if (currentIndent > 0) currentIndent -= 1;
} else if (node.match(/^<\w[^>]*[^\/]>.*$/)) // indent - next node not this.
nextIndent = 1;

//create the indent, by use of document default spaces count per indent
var leftFill = mul(defaultIndent, currentIndent);
formatted += leftFill + node + lb;
currentIndent += nextIndent;
}
}
return formatted;
}


HippoEDIT team
[url="http://www.hippoedit.com/"]http://www.hippoedit.com/[/url]

alex

HippoEDIT team
[url="http://www.hippoedit.com/"]http://www.hippoedit.com/[/url]

Dokkie

I'm using HE V 1.5x. I've installed XMLprettyPrint today using the online facility. Installation appears to work.
However I get an error when attempting to format a single line XML.
Routine stops on this line:    Var Busetabs = (Tabmode != Etabmodetabstospaces);
Error message indicates the     Etabmodetabstospaces is undefined.

RJP74

Hi,,

it seems the constants have been updated but not the xmlprettyprint module and associated documentation.
These syntax constants should now start ec... not e....
or in other words this page is out of date:
http://wiki.hippoedit.com/scripting/api/tab-modes

As a work around please edit your xmlPrettyPrint.hejs in c:\programFiles and change these two lines:

var bUseTabs = (TabMode != ecTabModeTabsToSpaces);
if ( bUseTabs && TabMode == ecTabModeAuto )

I will submit this as a bug and it should be corrected on the main server soon.

alex

Hi Guys,

constants were changed by design to have consistence in naming of all constants exposed. This was done already long time ago, but after 1.50 release.
The simplest solution would be to install 1.51 beta from forum - it uses newest naming.

The workaround to keep scripts running in 1.50 and 1.51 is to use constants values instead of constants itself. I have done it in some plugins, but not everywhere.

I will try to release 1.51 soon to eliminate such problems.

BR, Alex.
HippoEDIT team
[url="http://www.hippoedit.com/"]http://www.hippoedit.com/[/url]

Dokkie

Thank you,
Have installed v1.51 beta and ensured that variable indicated have changed. Pretty printing now works.