Element.writexml() now writes the xmlns declarations needed for the
namespaces of the element and its attributes, if they are not already
declared for an ancestor. A prefix in scope is reused for an attribute
in a namespace without a prefix, or a new one is invented, because
attributes cannot use the default namespace. The document is not
modified by the serialization.
Serialization with the default_namespace option failed for any attribute
without a namespace. But a default namespace declaration does not apply
to attribute names, so an unqualified attribute name is written as is.
For the same reason a qualified attribute name in the default namespace is
now written with a prefix; it was written without one, which lost its
namespace (gh-113581).
createElementNS(), createAttributeNS() and setAttributeNS() now raise
NamespaceErr for a malformed qualified name, for a prefix with an empty
namespace, and for illegal use of the "xml" and "xmlns" prefixes, as required
by DOM Level 2 Core. Setting the prefix of an attribute is validated too.
Two tests used a wrong namespace URI for xmlns attributes.
Pretty-printing added whitespace inside an element which contains text,
which changed its content. Now xml.dom.minidom.Node.toprettyxml() and
xml.etree.ElementTree.indent() do not add whitespace inside an element
which is marked with xml:space="preserve" or which contains text.
toprettyxml() also takes into account the content model declared in
the DTD: only white space in element content is ignorable.
The list of events was collected by the TreeBuilder in the C implementation,
so the pull parser only worked with the standard target. The parser itself
now collects the events, and reports what the target returns. XMLPullParser
and iterparse() get the target parameter, which makes it possible to parse a
large document incrementally without building a tree for it.
The namespace events no longer need a separate code path: the parser reports
the prefix and the uri if the target does not implement start_ns()/end_ns(),
as the Python implementation already did.
The Python implementation of XMLParser only reported a document type
declaration with an external identifier. Use the Expat handler, like
the C implementation does.
The namespace declarations were the only attribute values written without
quoteattr(), so a URI containing "&", "<" or a quote character produced a
document which cannot be parsed.
Corrected:
* the parser argument of iterparse() is an instance of XMLParser or its
subclass, not a subclass;
* feed() accepts a string as well as encoded data;
* keys() and items() do not return a list in the Python implementation, and
the attributes are no longer returned in an arbitrary order.
Removed the claims that the element tag, the attribute names and values, the
text of a comment and the data of TreeBuilder.data() can be bytes. It is a
Python 2 leftover. Documented instead what they can be.
Corrected:
* the node types for the PROCESSING_INSTRUCTION and COMMENT events;
* the return value of getEvent() at the end of the document;
* the type of the argument of parseString();
* references to the xml.dom interfaces, written as xml.dom.minidom.
Documented:
* the event constants, which were referenced but never described;
* PullDOM, SAX2DOM and the documentFactory argument;
* the arguments of DOMEventStream, its reset() and clear() methods.
Added docstrings to the module, the classes and their public methods, and
removed the commented out paragraph about pulldom in the xml.dom
documentation, which was never rendered and refers to a site which no longer
exists.
Corrected:
* the name of the errorHandler argument of parse() and parseString();
* the default value of the parser_list argument of make_parser();
* the description of the source of parse();
* the types of the declaration-handler and dom-node properties;
* the way in which names are interned;
* the description of IncrementalParser.
Documented:
* default_parser_list and SAXReaderNotAvailable;
* property_encoding and property_interning_dict;
* IncrementalParser.prepareParser();
* XMLFilterBase.getParent() and setParent();
* which features and properties the parser based on Expat does not support.
Added missing docstrings to parse(), parseString(), AttributesImpl and
XMLGenerator.
XML defines white space as " \t\r\n" (see XML 1.0, 2.3), but str.strip()
also strips other characters, such as U+00A0. Such characters could be
lost in ElementTree.indent(), in canonicalize(strip_text=True), and when
parsing with the whitespace-in-element-content feature turned off.
ElementTree.write(), tostring() and tostringlist() get the standalone
parameter: True for standalone="yes", False for standalone="no", and None
(the default) to omit it. An XML declaration is written if it is not None,
and combining it with a false xml_declaration is an error.
* The factory methods now raise InvalidCharacterErr if the name is not
a valid XML name.
* Inserting or setting a node created by another document now raises
WrongDocumentErr.
* Setting an attribute node which belongs to another element now raises
InuseAttributeErr.
* Inserting a node into itself or its descendant now raises
HierarchyRequestErr.
* A document can have only one element child and only one document type
child, and a document fragment can no longer have notation children.
* Removing an absent attribute now has no effect instead of raising
NotFoundErr.
* Attributes defaulted in the DTD are no longer omitted when parsing,
and Attr.specified now reports whether the attribute was given in the
start tag. This needs the new pyexpat method
GetSpecifiedAttributeCount().
* EntityReference nodes and Document.createEntityReference() are now
implemented.
* The exceptions required by the DOM are now documented, and minidom
specific differences are described in the minidom documentation.
Co-authored-by: Jason Orendorff <283361+jorendorff@users.noreply.github.com>
The BOM already determines the encoding, so the declaration is now
omitted by default, and declares utf-8 if requested explicitly.
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Some references to a removed `c14n` serialization method remained in
ElementTree.py. Attempting to use `method='c14n'` in the `write()`
method would result in `ValueError: unknown method 'c14n'`.
Removes the `write_c14n()` method that uses `method='c14n'` and also
raises the same error.
* The content of comments, processing instructions and elements "xmp",
"iframe", "noembed", "noframes", and "plaintext" is no longer escaped.
* The "plaintext" element no longer have the closing tag.
* Add support of empty attributes (with value None).
The C accelerator implementations use PyArg_ParseTuple, which
inherently enforces positional-only parameters. The Python fallback
allowed these as keyword arguments, creating a behavioral mismatch.
Make the tag parameter of Element.__init__ and the parent and tag
parameters of SubElement positional-only to align with the C
accelerator.
When iterparse() opens a file by filename and is not explicitly closed,
emit a ResourceWarning to alert developers of the resource leak.
Signed-off-by: Osama Abdelkader <osama.abdelkader@gmail.com>
Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
The exception message for `xml.etree.ElementTree.Element.remove` when an element is not found
has been updated from "list.remove(x): x not in list" to "Element.remove(x): element not found".
* Allow DOMParser.parse() to correctly handle DOMInputSource instances
that only have a systemId attribute set.
* Fix DOMEntityResolver.resolveEntity(), which was broken by the
Python 3.0 transition.
* Add Lib/test/test_xml_dom_xmlbuilder.py with few tests.
Add __all__ to the following modules:
importlib.machinery, importlib.util and xml.sax.
Add also "# noqa: F401" in collections.abc,
subprocess and xml.sax.
* Sort __all__; remove collections.abc.__all__; remove private names
* Add tests
Tools such as ruff can ignore "imported but unused" warnings if a
line ends with "# noqa: F401". It avoids the temptation to remove
an import which is used effectively.
Adjust DeprecationWarning when testing element truth values in ElementTree, we're planning to go with the more natural True return rather than a disruptive harder to code around exception raise, and are deferring the behavior change for a few more releases.
Allow controlling Expat >=2.6.0 reparse deferral (CVE-2023-52425) by adding five new methods:
- `xml.etree.ElementTree.XMLParser.flush`
- `xml.etree.ElementTree.XMLPullParser.flush`
- `xml.parsers.expat.xmlparser.GetReparseDeferralEnabled`
- `xml.parsers.expat.xmlparser.SetReparseDeferralEnabled`
- `xml.sax.expatreader.ExpatParser.flush`
Based on the "flush" idea from https://github.com/python/cpython/pull/115138#issuecomment-1932444270 .
### Notes
- Please treat as a security fix related to CVE-2023-52425.
Includes code suggested-by: Snild Dolkow <snild@sony.com>
and by core dev Serhiy Storchaka.
Prior to gh-114269, the iterator returned by ElementTree.iterparse was
initialized with the root attribute as None. This restores the previous
behavior.
The iterator returned by ElementTree.iterparse() may hold on to a file
descriptor. The reference cycle prevented prompt clean-up of the file
descriptor if the returned iterator was not exhausted.
When testing element truth values, emit a DeprecationWarning in all implementations.
This had emitted a FutureWarning in the rarely used python-only implementation since ~2.7 and has always been documented as a behavior not to rely on.
Matching an element in a tree search but having it test False can be unexpected. Raising the warning enables making the choice to finally raise an exception for this ambiguous behavior in the future.
The API documentation for [findtext](https://docs.python.org/3/library/xml.etree.elementtree.html#xml.etree.ElementTree.Element.findtext) states that this function gives back an empty string on "no text content." With the previous implementation, this would give back a empty string even on text content values such as 0 or False. This patch attempts to resolve that by only giving back an empty string if the text attribute is set to `None`. Resolves#91447.
Automerge-Triggered-By: GH:gvanrossum
xml.etree: Remove the ElementTree.Element.copy() method of the pure
Python implementation, deprecated in Python 3.10, use the copy.copy()
function instead. The C implementation of xml.etree has no copy()
method, only a __copy__() method.
Suppress writing an XML declaration in open files in ElementTree.write()
with encoding='unicode' and xml_declaration=None.
If file patch is passed to ElementTree.write() with encoding='unicode',
always open a new file in UTF-8.