Skip to content

Commit a4b25ef

Browse files
committed
Fix indenting CData
The reason of all CData indenting issues was replacing CDATA tags before indent and then replacing it back. Due to this CDATA wasn't hanlded by minidom parser correctly. After this fix, CDATA will remain untouched. However, indenting CDATA block with writexml() (which is called from toprettyxml) works wierd - it starts cdata on the beginning of the next line (without indent) and keeps parent closing tag on the same line as well. E.g. formatted XML might look like: <a> <content> <![CDATA[hello & goodbye]]> </content> </a> To fix this, plugin now does monkey patching of CDataSection.writexml(). This is just a hack and potentially destructive action, so warning message is displayed when patched version is used and this behaviour can be disabled in settings. This commit fixes #57, #93, #101
1 parent f68aa44 commit a4b25ef

File tree

5 files changed

+54
-4
lines changed

5 files changed

+54
-4
lines changed

indent_xml.Sublime-settings

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"disable_patch_minidom": false
3+
}

indentxml.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,6 @@ def indent(self, s):
9898
xml_header = re.compile(b"<\?.*\?>").match(s)
9999
# convert to plain string without indents and spaces
100100
s = re.compile(b'>\s+([^\s])', re.DOTALL).sub(b'>\g<1>', s)
101-
# replace tags to convince minidom process cdata as text
102-
s = s.replace(b'<![CDATA[', b'%CDATAESTART%').replace(b']]>', b'%CDATAEEND%')
103101
try:
104102
s = parseString(s).toprettyxml()
105103
except ExpatError as err:
@@ -108,8 +106,6 @@ def indent(self, s):
108106
return
109107
# remove line breaks
110108
s = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL).sub('>\g<1></', s)
111-
# restore cdata
112-
s = s.replace('%CDATAESTART%', '<![CDATA[').replace('%CDATAEEND%', ']]>')
113109
# remove xml header
114110
s = s.replace("<?xml version=\"1.0\" ?>", "").strip()
115111
if xml_header:

setup.py

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import sublime
2+
from xml.dom.minidom import CDATASection
3+
4+
original_writexml = None
5+
warning_shown = False
6+
WARNING_MESSAGE = """
7+
Warning! You are using patched version of xml.dom.minidom.CDataSection.writexml from indent_xml plugin.
8+
For more details and how to disable please refer to https://github.com/alek-sys/sublimetext_indentxml
9+
"""
10+
11+
12+
def show_warning():
13+
global warning_shown
14+
15+
if not warning_shown:
16+
print(WARNING_MESSAGE)
17+
warning_shown = True
18+
19+
20+
def patch_minidom_cdata():
21+
global original_writexml
22+
23+
def patched_writexml(self, writer, indent="", addindent="", newl=""):
24+
show_warning()
25+
if self.data.find("]]>") >= 0:
26+
raise ValueError("']]>' not allowed in a CDATA section")
27+
writer.write("%s<![CDATA[%s]]>%s" % (indent, self.data, newl))
28+
29+
original_writexml = CDATASection.writexml
30+
setattr(CDATASection, "writexml", patched_writexml)
31+
32+
33+
def is_minidom_patching_disabled():
34+
settings = sublime.load_settings("indent_xml.Sublime-settings")
35+
return settings.get('disable_patch_minidom', False)
36+
37+
38+
def plugin_loaded():
39+
if not is_minidom_patching_disabled():
40+
patch_minidom_cdata()
41+
42+
43+
def plugin_unloaded():
44+
if not is_minidom_patching_disabled() and original_writexml:
45+
setattr(CDATASection, "writexml", original_writexml)

tests/fixtures/03_input.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<a><content><![CDATA[hello & goodbye]]></content></a>

tests/fixtures/03_output.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<a>
2+
<content>
3+
<![CDATA[hello & goodbye]]>
4+
</content>
5+
</a>

0 commit comments

Comments
 (0)