Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Lib/test/test_minidom.py
Original file line number Diff line number Diff line change
Expand Up @@ -642,6 +642,30 @@ def test_toprettyxml_preserves_content_of_text_node(self):
dom.getElementsByTagName('B')[0].childNodes[0].toxml(),
dom2.getElementsByTagName('B')[0].childNodes[0].toxml())

def test_isWhitespaceInElementContent(self):
# only " \t\r\n" are whitespace in XML (see XML 1.0, 2.3)
dom = parseString('<!DOCTYPE a [<!ELEMENT a (b)*><!ELEMENT b (#PCDATA)>]>'
'<a> <b>x</b>\xa0</a>')
children = dom.documentElement.childNodes
self.assertTrue(children[0].isWhitespaceInElementContent)
self.assertFalse(children[2].isWhitespaceInElementContent)
dom.unlink()

def test_remove_whitespace_in_element_content(self):
from xml.dom.xmlbuilder import DOMBuilder, DOMInputSource
builder = DOMBuilder()
builder.setFeature("whitespace-in-element-content", False)
source = DOMInputSource()
source.byteStream = io.BytesIO(
b'<!DOCTYPE a [<!ELEMENT a (b)*><!ELEMENT b (#PCDATA)>]>'
b'<a> <b>x</b>\xc2\xa0</a>')
dom = builder.parse(source)
children = dom.documentElement.childNodes
# ignorable whitespace is removed, other characters are not
self.assertEqual([node.nodeName for node in children], ['b', '#text'])
self.assertEqual(children[1].data, '\xa0')
dom.unlink()

def testProcessingInstruction(self):
dom = parseString('<e><?mypi \t\n data \t\n ?></e>')
pi = dom.documentElement.firstChild
Expand Down
14 changes: 14 additions & 0 deletions Lib/test/test_xml_etree.py
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,15 @@ def test_indent_space_caching(self):
len({id(el.tail) for el in elem.iter()}),
)

def test_indent_non_xml_whitespace(self):
# only " \t\r\n" are whitespace in XML (see XML 1.0, 2.3)
elem = ET.XML('<html>\xa0<body><p>text</p>\xa0</body></html>')
ET.indent(elem)
self.assertEqual(
ET.tostring(elem),
b'<html>&#160;<body>\n <p>text</p>&#160;</body>\n</html>'
)

def test_indent_level(self):
elem = ET.XML("<html><body><p>pre<br/>post</p><p>text</p></body></html>")
with self.assertRaises(ValueError):
Expand Down Expand Up @@ -4755,6 +4764,11 @@ def test_simple_roundtrip(self):
xml = '<X xmlns="http://nps/a"><Y xmlns:b="http://nsp/b" b:targets="abc,xyz"></Y></X>'
self.assertEqual(c14n_roundtrip(xml), xml)

def test_c14n_strip_non_xml_whitespace(self):
# only " \t\r\n" are whitespace in XML (see XML 1.0, 2.3)
self.assertEqual(c14n_roundtrip("<a> \xa0x\xa0 </a>", strip_text=True),
"<a>\xa0x\xa0</a>")

def test_c14n_exclusion(self):
xml = textwrap.dedent("""\
<root xmlns:x="http://example.com/x">
Expand Down
6 changes: 4 additions & 2 deletions Lib/xml/dom/expatbuilder.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
from xml.dom import xmlbuilder, minidom, Node
from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE
from xml.parsers import expat
from xml.dom.minidom import _append_child, _set_attribute_node
from xml.dom.minidom import (_append_child, _set_attribute_node,
_XML_WHITESPACE)
from xml.dom.NodeFilter import NodeFilter

TEXT_NODE = Node.TEXT_NODE
Expand Down Expand Up @@ -413,7 +414,8 @@ def _handle_white_text_nodes(self, node, info):
# whitespace.
L = []
for child in node.childNodes:
if child.nodeType == TEXT_NODE and not child.data.strip():
if (child.nodeType == TEXT_NODE
and not child.data.strip(_XML_WHITESPACE)):
L.append(child)

# Remove ignorable whitespace from the tree.
Expand Down
5 changes: 4 additions & 1 deletion Lib/xml/dom/minidom.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
_nodeTypes_with_children = (xml.dom.Node.ELEMENT_NODE,
xml.dom.Node.ENTITY_REFERENCE_NODE)

# The white space characters of the XML specification (see XML 1.0, 2.3).
_XML_WHITESPACE = " \t\r\n"


class Node(xml.dom.Node):
namespaceURI = None # this is non-null only for elements and attributes
Expand Down Expand Up @@ -1209,7 +1212,7 @@ def replaceWholeText(self, content):
return None

def _get_isWhitespaceInElementContent(self):
if self.data.strip():
if self.data.strip(_XML_WHITESPACE):
return False
elem = _get_containing_element(self)
if elem is None:
Expand Down
13 changes: 8 additions & 5 deletions Lib/xml/etree/ElementTree.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@
from . import ElementPath


# The white space characters of the XML specification (see XML 1.0, 2.3).
_XML_WHITESPACE = " \t\r\n"

class ParseError(SyntaxError):
"""An error when parsing an XML document.

Expand Down Expand Up @@ -1190,17 +1193,17 @@ def _indent_children(elem, level):
child_indentation = indentations[level] + space
indentations.append(child_indentation)

if not elem.text or not elem.text.strip():
if not elem.text or not elem.text.strip(_XML_WHITESPACE):
elem.text = child_indentation

for child in elem:
if len(child):
_indent_children(child, child_level)
if not child.tail or not child.tail.strip():
if not child.tail or not child.tail.strip(_XML_WHITESPACE):
child.tail = child_indentation

# Dedent after the last child by overwriting the previous indentation.
if not child.tail.strip():
if not child.tail.strip(_XML_WHITESPACE):
child.tail = indentations[level]

_indent_children(tree, 0)
Expand Down Expand Up @@ -1705,7 +1708,7 @@ def _default(self, text):
if prefix == ">":
self._doctype = None
return
text = text.strip()
text = text.strip(_XML_WHITESPACE)
if not text:
return
self._doctype.append(text)
Expand Down Expand Up @@ -1921,7 +1924,7 @@ def _flush(self, _join_text=''.join):
data = _join_text(self._data)
del self._data[:]
if self._strip_text and not self._preserve_space[-1]:
data = data.strip()
data = data.strip(_XML_WHITESPACE)
if self._pending_start is not None:
args, self._pending_start = self._pending_start, None
qname_text = data if data and _looks_like_prefix_name(data) else None
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
:mod:`xml.dom` and :mod:`xml.etree.ElementTree` no longer treat characters
which are not white space in XML (such as U+00A0) as white space. Previously
they could be lost in :func:`~xml.etree.ElementTree.indent`,
:func:`~xml.etree.ElementTree.canonicalize` with ``strip_text=True``, and when
parsing with the ``whitespace-in-element-content`` feature turned off.
Loading