| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 59c4bdd commit ad447fa
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -284,6 +284,10 @@ rules apply: | |||
| 284 | 284 | and produced an invalid document, | |
| 285 | 285 | but removing an absent attribute raised :exc:`~xml.dom.NotFoundErr`. | |
| 286 | 286 | ||
| 287 | + .. versionchanged:: next | ||
| 288 | + Namespaces are now validated in the factory methods and when setting | ||
| 289 | + :attr:`~xml.dom.Node.prefix` of an attribute. | ||
| 290 | + | ||
| 287 | 291 | The following interfaces have no implementation in :mod:`!xml.dom.minidom`: | |
| 288 | 292 | ||
| 289 | 293 | * :class:`DOMTimeStamp` | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -687,6 +687,10 @@ inherits properties from :class:`Node`. | |||
| 687 | 687 | :meth:`~Node.insertBefore` or :meth:`~Node.appendChild`. | |
| 688 | 688 | ||
| 689 | 689 | Raise :exc:`InvalidCharacterErr` if the name is not a valid XML name. | |
| 690 | + Raise :exc:`NamespaceErr` if the qualified name is malformed, | ||
| 691 | + if it has a prefix and the namespace URI is empty, | ||
| 692 | + or if the prefix is ``'xml'`` | ||
| 693 | + and the namespace URI is not the XML namespace. | ||
| 690 | 694 | ||
| 691 | 695 | ||
| 692 | 696 | .. method:: Document.createTextNode(data) | |
@@ -740,6 +744,11 @@ inherits properties from :class:`Node`. | |||
| 740 | 744 | :class:`Element` object to use the newly created attribute instance. | |
| 741 | 745 | ||
| 742 | 746 | Raise :exc:`InvalidCharacterErr` if the name is not a valid XML name. | |
| 747 | + Raise :exc:`NamespaceErr` if the qualified name is malformed, | ||
| 748 | + if it has a prefix and the namespace URI is empty, | ||
| 749 | + if the prefix is ``'xml'`` and the namespace URI is not the XML namespace, | ||
| 750 | + or if the name or the prefix is ``'xmlns'`` | ||
| 751 | + and the namespace URI is not the XMLNS namespace, or vice versa. | ||
| 743 | 752 | ||
| 744 | 753 | ||
| 745 | 754 | .. method:: Document.getElementById(id) | |
@@ -905,6 +914,11 @@ of that class. | |||
| 905 | 914 | Note that a qname is the whole attribute name. This is different than above. | |
| 906 | 915 | ||
| 907 | 916 | Raise :exc:`InvalidCharacterErr` if the name is not a valid XML name. | |
| 917 | + Raise :exc:`NamespaceErr` if the qualified name is malformed, | ||
| 918 | + if it has a prefix and the namespace URI is empty, | ||
| 919 | + if the prefix is ``'xml'`` and the namespace URI is not the XML namespace, | ||
| 920 | + or if the name or the prefix is ``'xmlns'`` | ||
| 921 | + and the namespace URI is not the XMLNS namespace, or vice versa. | ||
| 908 | 922 | ||
| 909 | 923 | ||
| 910 | 924 | .. _dom-attr-objects: | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -702,6 +702,15 @@ xml | |||
| 702 | 702 | and :meth:`!Document.createEntityReference`. | |
| 703 | 703 | (Contributed by Jason Orendorff and Serhiy Storchaka in :gh:`44871`.) | |
| 704 | 704 | ||
| 705 | + * :mod:`xml.dom.minidom` now validates namespaces in the factory methods | ||
| 706 | + :meth:`~xml.dom.Document.createElementNS`, | ||
| 707 | + :meth:`~xml.dom.Document.createAttributeNS` | ||
| 708 | + and :meth:`~xml.dom.Element.setAttributeNS`. | ||
| 709 | + :exc:`~xml.dom.NamespaceErr` is now raised for a malformed qualified name, | ||
| 710 | + for a prefix with an empty namespace, and for illegal use | ||
| 711 | + of the ``xml`` and ``xmlns`` prefixes. | ||
| 712 | + (Contributed by Serhiy Storchaka in :gh:`156665`.) | ||
| 713 | + | ||
| 705 | 714 | * :meth:`~xml.dom.minidom.Node.toprettyxml` in :mod:`xml.dom.minidom` | |
| 706 | 715 | and :func:`~xml.etree.ElementTree.indent` in :mod:`xml.etree.ElementTree` | |
| 707 | 716 | no longer add whitespace inside an element | |
@@ -955,6 +964,12 @@ that may require changes to your code. | |||
| 955 | 964 | Attributes defaulted in the DTD are no longer omitted when parsing. | |
| 956 | 965 | (Contributed by Jason Orendorff and Serhiy Storchaka in :gh:`44871`.) | |
| 957 | 966 | ||
| 967 | + * :mod:`xml.dom.minidom` now raises :exc:`~xml.dom.NamespaceErr` | ||
| 968 | + for a malformed qualified name, for a prefix with an empty namespace, | ||
| 969 | + and for illegal use of the ``xml`` and ``xmlns`` prefixes. | ||
| 970 | + Such operations formerly succeeded and produced an invalid document. | ||
| 971 | + (Contributed by Serhiy Storchaka in :gh:`156665`.) | ||
| 972 | + | ||
| 958 | 973 | * :meth:`~xml.dom.minidom.Node.toprettyxml` in :mod:`xml.dom.minidom` | |
| 959 | 974 | and :func:`~xml.etree.ElementTree.indent` in :mod:`xml.etree.ElementTree` | |
| 960 | 975 | no longer add whitespace inside an element | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -365,7 +365,7 @@ def testRemoveAttrNS(self): | |||
| 365 | 365 | dom = Document() | |
| 366 | 366 | child = dom.appendChild( | |
| 367 | 367 | dom.createElementNS("http://www.python.org", "python:abc")) | |
| 368 | - child.setAttributeNS("http://www.w3.org", "xmlns:python", | ||
| 368 | + child.setAttributeNS(xml.dom.XMLNS_NAMESPACE, "xmlns:python", | ||
| 369 | 369 | "http://www.python.org") | |
| 370 | 370 | child.setAttributeNS("http://www.python.org", "python:abcattr", "foo") | |
| 371 | 371 | # removing an absent attribute has no effect | |
@@ -472,11 +472,13 @@ def testGetAttributeNS(self): | |||
| 472 | 472 | dom = Document() | |
| 473 | 473 | child = dom.appendChild( | |
| 474 | 474 | dom.createElementNS("http://www.python.org", "python:abc")) | |
| 475 | - child.setAttributeNS("http://www.w3.org", "xmlns:python", | ||
| 475 | + child.setAttributeNS(xml.dom.XMLNS_NAMESPACE, "xmlns:python", | ||
| 476 | 476 | "http://www.python.org") | |
| 477 | - self.assertEqual(child.getAttributeNS("http://www.w3.org", "python"), | ||
| 477 | + self.assertEqual( | ||
| 478 | + child.getAttributeNS(xml.dom.XMLNS_NAMESPACE, "python"), | ||
| 478 | 479 | 'http://www.python.org') | |
| 479 | - self.assertEqual(child.getAttributeNS("http://www.w3.org", "other"), | ||
| 480 | + self.assertEqual( | ||
| 481 | + child.getAttributeNS(xml.dom.XMLNS_NAMESPACE, "other"), | ||
| 480 | 482 | '') | |
| 481 | 483 | child2 = child.appendChild(dom.createElement('abc')) | |
| 482 | 484 | self.assertEqual(child2.getAttributeNS("http://www.python.org", "missing"), | |
@@ -2121,6 +2123,69 @@ def test_cdata_parsing(self): | |||
| 2121 | 2123 | dom2 = parseString(dom1.toprettyxml()) | |
| 2122 | 2124 | self.checkWholeText(dom2.getElementsByTagName('node')[0].firstChild, '</data>') | |
| 2123 | 2125 | ||
| 2126 | + def testNamespaceErr(self): | ||
| 2127 | + doc = parseString("<doc/>") | ||
| 2128 | + elem = doc.documentElement | ||
| 2129 | + XML_NS = xml.dom.XML_NAMESPACE | ||
| 2130 | + XMLNS_NS = xml.dom.XMLNS_NAMESPACE | ||
| 2131 | + for namespaceURI, qname in [ | ||
| 2132 | + (None, "p:e"), # a prefix without a namespace | ||
| 2133 | + ("", "p:e"), | ||
| 2134 | + ("http://xml.python.org/ns", "p:p:e"), # malformed | ||
| 2135 | + ("http://xml.python.org/ns", "p:"), | ||
| 2136 | + ("http://xml.python.org/ns", "p:1e"), | ||
| 2137 | + ("http://xml.python.org/ns", "xml:e"), # the xml prefix | ||
| 2138 | + ]: | ||
| 2139 | + with self.subTest(namespaceURI=namespaceURI, qname=qname): | ||
| 2140 | + self.assertRaises(xml.dom.NamespaceErr, | ||
| 2141 | + doc.createElementNS, namespaceURI, qname) | ||
| 2142 | + self.assertRaises(xml.dom.NamespaceErr, | ||
| 2143 | + doc.createAttributeNS, namespaceURI, qname) | ||
| 2144 | + self.assertRaises(xml.dom.NamespaceErr, | ||
| 2145 | + elem.setAttributeNS, namespaceURI, qname, "v") | ||
| 2146 | + | ||
| 2147 | + # the xmlns name and prefix are only allowed in the XMLNS namespace | ||
| 2148 | + for namespaceURI, qname in [ | ||
| 2149 | + ("http://xml.python.org/ns", "xmlns"), | ||
| 2150 | + ("http://xml.python.org/ns", "xmlns:p"), | ||
| 2151 | + (None, "xmlns:p"), | ||
| 2152 | + (XMLNS_NS, "p:a"), # and it allows nothing else | ||
| 2153 | + (XMLNS_NS, "a"), | ||
| 2154 | + ]: | ||
| 2155 | + with self.subTest(namespaceURI=namespaceURI, qname=qname): | ||
| 2156 | + self.assertRaises(xml.dom.NamespaceErr, | ||
| 2157 | + doc.createAttributeNS, namespaceURI, qname) | ||
| 2158 | + self.assertRaises(xml.dom.NamespaceErr, | ||
| 2159 | + elem.setAttributeNS, namespaceURI, qname, "v") | ||
| 2160 | + | ||
| 2161 | + # valid combinations | ||
| 2162 | + doc.createElementNS(None, "e") | ||
| 2163 | + doc.createElementNS("http://xml.python.org/ns", "p:e") | ||
| 2164 | + doc.createElementNS(XML_NS, "xml:e") | ||
| 2165 | + doc.createAttributeNS(None, "a") | ||
| 2166 | + doc.createAttributeNS(XML_NS, "xml:lang") | ||
| 2167 | + doc.createAttributeNS(XMLNS_NS, "xmlns") | ||
| 2168 | + doc.createAttributeNS(XMLNS_NS, "xmlns:p") | ||
| 2169 | + elem.setAttributeNS("http://xml.python.org/ns", "p:a", "v") | ||
| 2170 | + doc.unlink() | ||
| 2171 | + | ||
| 2172 | + def testAttrPrefix(self): | ||
| 2173 | + doc = parseString("<doc/>") | ||
| 2174 | + attr = doc.createAttributeNS("http://xml.python.org/ns", "p:a") | ||
| 2175 | + self.assertRaises(xml.dom.InvalidCharacterErr, | ||
| 2176 | + setattr, attr, "prefix", "q:r") | ||
| 2177 | + self.assertRaises(xml.dom.InvalidCharacterErr, | ||
| 2178 | + setattr, attr, "prefix", "1q") | ||
| 2179 | + self.assertRaises(xml.dom.NamespaceErr, | ||
| 2180 | + setattr, attr, "prefix", "xml") | ||
| 2181 | + self.assertRaises(xml.dom.NamespaceErr, | ||
| 2182 | + setattr, attr, "prefix", "xmlns") | ||
| 2183 | + attr.prefix = "q" | ||
| 2184 | + self.assertEqual(attr.name, "q:a") | ||
| 2185 | + attr.prefix = None | ||
| 2186 | + self.assertEqual(attr.name, "a") | ||
| 2187 | + doc.unlink() | ||
| 2188 | + | ||
| 2124 | 2189 | def testInvalidCharacterErr(self): | |
| 2125 | 2190 | doc = parseString("<doc/>") | |
| 2126 | 2191 | impl = getDOMImplementation() | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,7 +19,8 @@ | |||
| 19 | 19 | import xml | |
| 20 | 20 | import xml.dom | |
| 21 | 21 | ||
| 22 | - from xml.dom import EMPTY_NAMESPACE, EMPTY_PREFIX, XMLNS_NAMESPACE, domreg | ||
| 22 | + from xml.dom import (EMPTY_NAMESPACE, EMPTY_PREFIX, XML_NAMESPACE, | ||
| 23 | + XMLNS_NAMESPACE, domreg) | ||
| 23 | 24 | from xml.dom.minicompat import * | |
| 24 | 25 | from xml.dom.xmlbuilder import DOMImplementationLS, DocumentLS | |
| 25 | 26 | ||
@@ -305,6 +306,35 @@ def _check_name(name): | |||
| 305 | 306 | "%r is not a valid XML name" % (name,)) | |
| 306 | 307 | ||
| 307 | 308 | ||
| 309 | + def _check_prefix(prefix, namespaceURI, attribute=False): | ||
| 310 | + if not xml.is_valid_name(prefix) or ':' in prefix: | ||
| 311 | + raise xml.dom.InvalidCharacterErr( | ||
| 312 | + "%r is not a valid namespace prefix" % (prefix,)) | ||
| 313 | + if not namespaceURI: | ||
| 314 | + raise xml.dom.NamespaceErr( | ||
| 315 | + "cannot use the prefix %r with an empty namespace" % (prefix,)) | ||
| 316 | + if prefix == "xml" and namespaceURI != XML_NAMESPACE: | ||
| 317 | + raise xml.dom.NamespaceErr( | ||
| 318 | + "illegal use of the 'xml' prefix for the wrong namespace") | ||
| 319 | + if attribute and (prefix == "xmlns") != (namespaceURI == XMLNS_NAMESPACE): | ||
| 320 | + raise xml.dom.NamespaceErr( | ||
| 321 | + "illegal use of the 'xmlns' prefix for the wrong namespace") | ||
| 322 | + | ||
| 323 | + | ||
| 324 | + def _check_qualified_name(namespaceURI, qualifiedName, attribute=False): | ||
| 325 | + """Check a namespace URI and a qualified name (see DOM Level 2 Core).""" | ||
| 326 | + _check_name(qualifiedName) | ||
| 327 | + prefix, sep, localName = qualifiedName.partition(':') | ||
| 328 | + if sep: | ||
| 329 | + if not localName or ':' in localName or not xml.is_valid_name(localName): | ||
| 330 | + raise xml.dom.NamespaceErr( | ||
| 331 | + "%r is not a valid qualified name" % (qualifiedName,)) | ||
| 332 | + _check_prefix(prefix, namespaceURI, attribute) | ||
| 333 | + elif attribute and (qualifiedName == "xmlns") != (namespaceURI == XMLNS_NAMESPACE): | ||
| 334 | + raise xml.dom.NamespaceErr( | ||
| 335 | + "illegal use of the 'xmlns' attribute for the wrong namespace") | ||
| 336 | + | ||
| 337 | + | ||
| 308 | 338 | def _is_ancestor(node, other): | |
| 309 | 339 | "Returns true iff node is an ancestor of other." | |
| 310 | 340 | other = other.parentNode | |
@@ -444,11 +474,8 @@ def _get_prefix(self): | |||
| 444 | 474 | return self._prefix | |
| 445 | 475 | ||
| 446 | 476 | def _set_prefix(self, prefix): | |
| 447 | - nsuri = self.namespaceURI | ||
| 448 | - if prefix == "xmlns": | ||
| 449 | - if nsuri and nsuri != XMLNS_NAMESPACE: | ||
| 450 | - raise xml.dom.NamespaceErr( | ||
| 451 | - "illegal use of 'xmlns' prefix for the wrong namespace") | ||
| 477 | + if prefix is not None: | ||
| 478 | + _check_prefix(prefix, self.namespaceURI, True) | ||
| 452 | 479 | self._prefix = prefix | |
| 453 | 480 | if prefix is None: | |
| 454 | 481 | newName = self.localName | |
@@ -807,10 +834,10 @@ def setAttribute(self, attname, value): | |||
| 807 | 834 | _clear_id_cache(self) | |
| 808 | 835 | ||
| 809 | 836 | def setAttributeNS(self, namespaceURI, qualifiedName, value): | |
| 837 | + _check_qualified_name(namespaceURI, qualifiedName, True) | ||
| 810 | 838 | prefix, localname = _nssplit(qualifiedName) | |
| 811 | 839 | attr = self.getAttributeNodeNS(namespaceURI, localname) | |
| 812 | 840 | if attr is None: | |
| 813 | - _check_name(qualifiedName) | ||
| 814 | 841 | attr = Attr(qualifiedName, namespaceURI, localname, prefix) | |
| 815 | 842 | attr.value = value | |
| 816 | 843 | attr.ownerDocument = self.ownerDocument | |
@@ -1840,14 +1867,14 @@ def createAttribute(self, qName): | |||
| 1840 | 1867 | return a | |
| 1841 | 1868 | ||
| 1842 | 1869 | def createElementNS(self, namespaceURI, qualifiedName): | |
| 1843 | - _check_name(qualifiedName) | ||
| 1870 | + _check_qualified_name(namespaceURI, qualifiedName) | ||
| 1844 | 1871 | prefix, localName = _nssplit(qualifiedName) | |
| 1845 | 1872 | e = Element(qualifiedName, namespaceURI, prefix) | |
| 1846 | 1873 | e.ownerDocument = self | |
| 1847 | 1874 | return e | |
| 1848 | 1875 | ||
| 1849 | 1876 | def createAttributeNS(self, namespaceURI, qualifiedName): | |
| 1850 | - _check_name(qualifiedName) | ||
| 1877 | + _check_qualified_name(namespaceURI, qualifiedName, True) | ||
| 1851 | 1878 | prefix, localName = _nssplit(qualifiedName) | |
| 1852 | 1879 | a = Attr(qualifiedName, namespaceURI, localName, prefix) | |
| 1853 | 1880 | a.ownerDocument = self | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,8 @@ | |||
| 1 | + :mod:`xml.dom.minidom` now validates namespaces in | ||
| 2 | + :meth:`~xml.dom.Document.createElementNS`, | ||
| 3 | + :meth:`~xml.dom.Document.createAttributeNS` and | ||
| 4 | + :meth:`~xml.dom.Element.setAttributeNS`, and when setting | ||
| 5 | + :attr:`~xml.dom.Node.prefix` of an attribute. | ||
| 6 | + :exc:`~xml.dom.NamespaceErr` is now raised for a malformed qualified name, for | ||
| 7 | + a prefix with an empty namespace, and for illegal use of the ``xml`` and | ||
| 8 | + ``xmlns`` prefixes. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments