/
xml_indent_formatter.py
111 lines (86 loc) · 3.35 KB
/
xml_indent_formatter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# This file is part of IndentX.
# https://github.com/socsieng/IndentX
# Licensed under the MIT license:
# http://www.opensource.org/licenses/MIT-license
# Copyright (c) 2015, Socheat Sieng <socsieng@gmail.com>
import re
from indent_x.general_formatting.string_utility import join
comment_exp = re.compile(r'<!--([\s\S]*?)-->', re.M)
preserve_indent_exp = re.compile('^(.*)$', re.M)
class XmlIndentFormatter(object):
position = 0
depth = 0
prevDepth = 0
add = False
beforeString = '\n'
openExp = re.compile(r'<(?![/?!])[^>]+(?<!/)>')
closeExp = re.compile(r'</[^>]+>')
selfClosingExp = re.compile(r'<[^>]+/>')
expressions = [openExp, closeExp, selfClosingExp, comment_exp]
openExpSpace = re.compile(r'\s+')
trimExp = re.compile(r'(^\s*|\s*$)')
def __init__(self, indentString = '\t', removeComments = False, removeEmptyLines = False):
self.indentString = indentString
self.removeComments = removeComments
self.removeEmptyLines = removeEmptyLines
def getFirstMatch(self, string, startPos):
pos = len(string)
m = None
for exp in self.expressions:
match = exp.search(string, startPos)
if match:
if match.start() < pos:
pos = match.start();
m = match
return m
def indent(self, xml):
output = ''
pos = 0
m = None
e = None
newline = self.beforeString
if self.indentString == '':
newline = ''
while True:
m = self.getFirstMatch(xml, pos)
if m:
match = self.trimExp.sub('', m.group(0))
pre = self.trimExp.sub('', xml[pos:m.start()])
pos = m.end()
if m.re == self.openExp:
output = join(newline, output + pre, (self.indentString * self.depth) + self.openExpSpace.sub(' ', match))
self.depth += 1
self.add = True
elif m.re == self.closeExp:
if self.depth == self.prevDepth and self.add:
#close on new line
output += pre + match
self.depth -= 1
else:
self.depth -= 1
output = join(newline, output + pre, (self.indentString * self.depth) + match)
self.add = False
elif m.re == comment_exp:
if self.removeComments:
continue
output = join(newline, output + pre, format_comment(m.group(0), self.indentString * self.depth))
self.add = False
else:
output = join(newline, output + pre, (self.indentString * self.depth) + match)
self.add = False
self.prevDepth = self.depth
else:
output += xml[pos:]
break
if self.removeEmptyLines:
blank = re.compile(r'^\s*$\r?\n', re.M)
return blank.sub('', output)
return output
def format_comment(comment, indent):
match = comment_exp.search(comment)
if match:
output = preserve_indent_exp.sub(indent + '\\1', match.group(0))
return output
return comment