function _emit
Recursively converts a dictionary structure into XML SAX events, emitting them through a content handler for XML generation.
/tf/active/vicechatdev/SPFCsync/venv/lib64/python3.11/site-packages/xmltodict.py
397 - 473
complex
Purpose
This function is the core recursive engine for converting Python dictionaries to XML format. It traverses nested dictionary structures and generates corresponding SAX events (startElement, characters, endElement) through a content handler. It handles attributes (prefixed with '@'), text content (using '#text' key), namespaces, pretty printing, and various XML formatting options. The function is designed to work with xmltodict-style dictionary representations where keys become XML elements and special keys denote attributes and text content.
Source Code
def _emit(key, value, content_handler,
attr_prefix='@',
cdata_key='#text',
depth=0,
preprocessor=None,
pretty=False,
newl='\n',
indent='\t',
namespace_separator=':',
namespaces=None,
full_document=True,
expand_iter=None):
key = _process_namespace(key, namespaces, namespace_separator, attr_prefix)
if preprocessor is not None:
result = preprocessor(key, value)
if result is None:
return
key, value = result
if (not hasattr(value, '__iter__')
or isinstance(value, _basestring)
or isinstance(value, dict)):
value = [value]
for index, v in enumerate(value):
if full_document and depth == 0 and index > 0:
raise ValueError('document with multiple roots')
if v is None:
v = _dict()
elif isinstance(v, bool):
if v:
v = _unicode('true')
else:
v = _unicode('false')
elif not isinstance(v, dict):
if expand_iter and hasattr(v, '__iter__') and not isinstance(v, _basestring):
v = _dict(((expand_iter, v),))
else:
v = _unicode(v)
if isinstance(v, _basestring):
v = _dict(((cdata_key, v),))
cdata = None
attrs = _dict()
children = []
for ik, iv in v.items():
if ik == cdata_key:
cdata = iv
continue
if ik.startswith(attr_prefix):
ik = _process_namespace(ik, namespaces, namespace_separator,
attr_prefix)
if ik == '@xmlns' and isinstance(iv, dict):
for k, v in iv.items():
attr = 'xmlns{}'.format(':{}'.format(k) if k else '')
attrs[attr] = _unicode(v)
continue
if not isinstance(iv, _unicode):
iv = _unicode(iv)
attrs[ik[len(attr_prefix):]] = iv
continue
children.append((ik, iv))
if pretty:
content_handler.ignorableWhitespace(depth * indent)
content_handler.startElement(key, AttributesImpl(attrs))
if pretty and children:
content_handler.ignorableWhitespace(newl)
for child_key, child_value in children:
_emit(child_key, child_value, content_handler,
attr_prefix, cdata_key, depth+1, preprocessor,
pretty, newl, indent, namespaces=namespaces,
namespace_separator=namespace_separator,
expand_iter=expand_iter)
if cdata is not None:
content_handler.characters(cdata)
if pretty and children:
content_handler.ignorableWhitespace(depth * indent)
content_handler.endElement(key)
if pretty and depth:
content_handler.ignorableWhitespace(newl)
Parameters
| Name | Type | Default | Kind |
|---|---|---|---|
key |
- | - | positional_or_keyword |
value |
- | - | positional_or_keyword |
content_handler |
- | - | positional_or_keyword |
attr_prefix |
- | '@' | positional_or_keyword |
cdata_key |
- | '#text' | positional_or_keyword |
depth |
- | 0 | positional_or_keyword |
preprocessor |
- | None | positional_or_keyword |
pretty |
- | False | positional_or_keyword |
newl |
- | '\n' | positional_or_keyword |
indent |
- | '\t' | positional_or_keyword |
namespace_separator |
- | ':' | positional_or_keyword |
namespaces |
- | None | positional_or_keyword |
full_document |
- | True | positional_or_keyword |
expand_iter |
- | None | positional_or_keyword |
Parameter Details
key: The XML element name/tag to emit. Will be processed for namespace handling.
value: The value associated with the key. Can be a string, dict, list, bool, None, or any iterable. Dictionaries represent nested elements, strings become text content, lists cause multiple elements with the same tag.
content_handler: An XML SAX ContentHandler instance (typically XMLGenerator) that receives the SAX events (startElement, endElement, characters, etc.).
attr_prefix: String prefix used to identify dictionary keys that should be treated as XML attributes. Default is '@', so '@id' becomes an attribute 'id'.
cdata_key: Dictionary key name used to identify character data (text content) within an element. Default is '#text'.
depth: Current recursion depth level, used for indentation in pretty printing. Starts at 0 for root element.
preprocessor: Optional callable that takes (key, value) and returns modified (key, value) tuple or None to skip emission. Used for custom transformations before XML generation.
pretty: Boolean flag to enable pretty printing with indentation and newlines. Default is False for compact output.
newl: String to use for newlines in pretty printing. Default is '\n'.
indent: String to use for one level of indentation in pretty printing. Default is '\t' (tab character).
namespace_separator: Character used to separate namespace prefix from local name. Default is ':'.
namespaces: Dictionary mapping namespace prefixes to URIs for namespace processing.
full_document: Boolean flag that enforces single root element constraint when True. Raises ValueError if multiple root elements detected at depth 0.
expand_iter: Optional string key name. If provided, iterables (except strings/dicts) will be wrapped in a dictionary with this key, creating a parent element.
Return Value
This function returns None. It operates by side-effect, emitting SAX events to the provided content_handler. The XML output is generated through the content handler's methods rather than being returned directly.
Dependencies
xml.sax.saxutilsxml.sax.xmlreader
Required Imports
from xml.sax.xmlreader import AttributesImpl
Usage Example
from xml.sax.saxutils import XMLGenerator
from xml.sax.xmlreader import AttributesImpl
from io import StringIO
# Define required helper types/functions (simplified)
_basestring = str
_unicode = str
_dict = dict
def _process_namespace(key, namespaces, separator, prefix):
return key
# Create output buffer and content handler
output = StringIO()
handler = XMLGenerator(output, encoding='utf-8')
# Start document
handler.startDocument()
# Example dictionary to convert
data = {
'@id': '123',
'#text': 'Hello World',
'child': {'@attr': 'value', '#text': 'Child text'}
}
# Emit XML
_emit('root', data, handler, attr_prefix='@', cdata_key='#text', depth=0, pretty=True)
# End document
handler.endDocument()
# Get XML string
xml_output = output.getvalue()
print(xml_output)
Best Practices
- Always ensure the content_handler is properly initialized before calling this function
- When full_document=True, ensure the value parameter represents a single root element to avoid ValueError
- Use the preprocessor parameter for custom key/value transformations before XML emission
- Be cautious with deeply nested structures as this is a recursive function that could hit Python's recursion limit
- The attr_prefix and cdata_key conventions must be consistent with how the input dictionary was structured
- For namespace support, provide a proper namespaces dictionary mapping prefixes to URIs
- When pretty=True, be aware that whitespace will be added which may affect XML parsing in whitespace-sensitive contexts
- Boolean values are converted to lowercase strings 'true' and 'false'
- None values are converted to empty dictionaries, resulting in empty XML elements
Tags
Similar Components
AI-powered semantic similarity - components with related functionality:
-
class _DictSAXHandler 70.6% similar
-
function unparse 65.1% similar
-
function parse 59.1% similar
-
function _process_namespace 44.4% similar
-
function xml_escape 40.1% similar