How to pretty print the XML.

Priyanka_77
Tera Contributor

I wan to develop one function which takes the XML as an input and returns an well formatted XML with indentation, just like how we do pretty print.

How can i do that?
Example:
<level1>
<level2>
<apple>content</apple>
<boo>something else</boo>
<level3>
<baba>other things</baba>
<level3>
<foo>hello</foo>
<something/>
<level2>
<level1>

Well formatted XML:
<level1>

 <level2>
   <apple>content</apple>
   <boo>something else</boo>
   <level3>
     <baba>other things</baba>
   </level3>
   <foo>hello</foo>
   <something />
  </level2>
</level1>

- sub levels are indented
- if the tag has no other tag the closing is at the end of line

1 ACCEPTED SOLUTION

@Priyanka_77 

this worked fine for me

function prettyPrintXML(xml) {
    xml = xml.replace(/>\s+</g, '><').trim(); // Remove whitespace between tags

    var result = '';
    var indentStep = '  ';
    var indent = '';

    // Split into nodes with regex, preserving text between tags
    var re = /(<[^>]+>|[^<]+)/g;
    var nodes = [];
    var match;
    while (match = re.exec(xml)) {
        // Remove empty text nodes
        if (match[0].trim() === '') continue;
        nodes.push(match[0]);
    }

    var i = 0;
    while (i < nodes.length) {
        var node = nodes[i];

        // Open tag
        var openTagMatch = node.match(/^<([a-zA-Z0-9_:.-]+)[^>]*>$/);
        if (openTagMatch) {
            // Check for the pattern: <tag>text</tag>
            if (
                i + 2 < nodes.length &&
                !nodes[i + 1].match(/^</) && // next node is text
                nodes[i + 2].match(new RegExp('^</'+openTagMatch[1]+'>\\s*$')) // and next-next node is matching close tag
            ) {
                result += indent + node + nodes[i + 1].trim() + nodes[i + 2] + '\n';
                i += 3;
                continue;
            } else {
                result += indent + node + '\n';
                indent += indentStep;
                i++;
                continue;
            }
        }

        // Close tag
        if (node.match(/^<\/[a-zA-Z0-9_:.-]+>/)) {
            indent = indent.substring(0, indent.length - indentStep.length);
            result += indent + node + '\n';
            i++;
            continue;
        }

        // Self-closing tag
        if (node.match(/^<[^>]+\/>$/)) {
            result += indent + node + '\n';
            i++;
            continue;
        }

        // Text or other stuff
        result += indent + node.trim() + '\n';
        i++;
    }
    return result.trim();
}

// EXAMPLE USAGE:
var uglyXml = '<level1><level2><apple>content</apple><boo>something else</boo><level3><baba>other things</baba></level3><foo>hello</foo><something/></level2></level1>';
gs.info('\n' + prettyPrintXML(uglyXml));

Output:

AnkurBawiskar_0-1753162638138.png

 

If my response helped please mark it correct and close the thread so that it benefits future readers.

Regards,
Ankur
✨ Certified Technical Architect  ||  ✨ 9x ServiceNow MVP  ||  ✨ ServiceNow Community Leader

View solution in original post

6 REPLIES 6

SumanthDosapati
Mega Sage
Mega Sage

@Priyanka_77 

 

You can use this simple script

var xmlString = 'your unformatted xml string here';

var xmlDoc = new XMLDocument(xmlString);
gs.info('\n' + xmlDoc.toIndentedString());  //This will print the formatted xml as string.

 

If you want to get xml from a gliderecord object, use below.

 var gr = new GlideRecord('incident');
 gr.get("0c5f3cece1b12010f877971dea0b1449");
 
 var xmlString = new GlideRecordXMLSerializer().serialize(gr); //this will be unformatted xml as string.

 

Accept the solution and mark as helpful if it does, to benefit future readers.
Regards,
Sumanth

 

Thanks - this worked for me!